From 574e348c1e8fa160129d6b90e3a19e2bebb2b301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= Date: Thu, 2 Feb 2023 20:12:37 +0800 Subject: [PATCH 001/469] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=20esModule#p?= =?UTF-8?q?referClassProperty=20=E9=85=8D=E7=BD=AE=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/generator/ProjectBuilder.ts | 19 ++++++++++++ .../src/plugins/common/esmodule.ts | 4 ++- .../component/react/containerInjectUtils.ts | 29 ++++++++++++++----- .../src/postprocessor/prettier/index.ts | 2 ++ modules/code-generator/src/types/core.ts | 3 ++ .../code-generator/src/types/intermediate.ts | 1 + 6 files changed, 50 insertions(+), 8 deletions(-) diff --git a/modules/code-generator/src/generator/ProjectBuilder.ts b/modules/code-generator/src/generator/ProjectBuilder.ts index 819f37c5c4..040136057d 100644 --- a/modules/code-generator/src/generator/ProjectBuilder.ts +++ b/modules/code-generator/src/generator/ProjectBuilder.ts @@ -24,22 +24,31 @@ interface IModuleInfo { } export interface ProjectBuilderInitOptions { + /** 项目模板 */ template: IProjectTemplate; + /** 项目插件 */ plugins: IProjectPlugins; + /** 模块后置处理器 */ postProcessors: PostProcessor[]; + /** Schema 解析器 */ schemaParser?: ISchemaParser; + /** 项目级别的前置处理器 */ projectPreProcessors?: ProjectPreProcessor[]; + /** 项目级别的后置处理器 */ projectPostProcessors?: ProjectPostProcessor[]; + /** 是否处于严格模式 */ inStrictMode?: boolean; + /** 一些额外的上下文数据 */ extraContextData?: Record; + /** * Hook which is used to customize original options, we can reorder/add/remove plugins/processors * of the existing solution. @@ -264,6 +273,16 @@ export class ProjectBuilder implements IProjectBuilder { } // TODO: 更多 slots 的处理??是不是可以考虑把 template 中所有的 slots 都处理下? + // const whitelistSlotNames = [ + // 'router', + // 'entry', + // 'appConfig', + // 'buildConfig', + // 'router', + // ]; + // Object.keys(this.template.slots).forEach((slotName: string) => { + + // }); // Post Process const isSingleComponent = parseResult?.project?.projectRemark?.isSingleComponent; diff --git a/modules/code-generator/src/plugins/common/esmodule.ts b/modules/code-generator/src/plugins/common/esmodule.ts index 04dfd1ce21..09c6aec599 100644 --- a/modules/code-generator/src/plugins/common/esmodule.ts +++ b/modules/code-generator/src/plugins/common/esmodule.ts @@ -443,6 +443,7 @@ function buildPackageImport( export interface PluginConfig { fileType?: string; // 导出的文件类型 useAliasName?: boolean; // 是否使用 componentName 重命名组件 identifier + filter?: (deps: IDependency[]) => IDependency[]; // 支持过滤能力 } const pluginFactory: BuilderComponentPluginFactory = (config?: PluginConfig) => { @@ -460,7 +461,8 @@ const pluginFactory: BuilderComponentPluginFactory = (config?: Plu const ir = next.ir as IWithDependency; if (ir && ir.deps && ir.deps.length > 0) { - const packs = groupDepsByPack(ir.deps); + const deps = cfg.filter ? cfg.filter(ir.deps) : ir.deps; + const packs = groupDepsByPack(deps); Object.keys(packs).forEach((pkg) => { const chunks = buildPackageImport(pkg, packs[pkg], cfg.fileType, cfg.useAliasName); diff --git a/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts b/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts index 33fc8c28d3..c5c566e17b 100644 --- a/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts +++ b/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts @@ -16,6 +16,9 @@ import { export interface PluginConfig { fileType: string; + + /** prefer using class property to define utils */ + preferClassProperty?: boolean; } const pluginFactory: BuilderComponentPluginFactory = (config?) => { @@ -57,13 +60,25 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], }); - next.chunks.push({ - type: ChunkType.STRING, - fileType: cfg.fileType, - name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, - content: 'this.utils = utils;', - linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart], - }); + if (cfg.preferClassProperty) { + // mode: class property + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: 'utils = utils;', + linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsVar]], + }); + } else { + // mode: assign in constructor + next.chunks.push({ + type: ChunkType.STRING, + fileType: cfg.fileType, + name: CLASS_DEFINE_CHUNK_NAME.ConstructorContent, + content: 'this.utils = utils;', + linkAfter: [CLASS_DEFINE_CHUNK_NAME.ConstructorStart], + }); + } if (useRef) { next.chunks.push({ diff --git a/modules/code-generator/src/postprocessor/prettier/index.ts b/modules/code-generator/src/postprocessor/prettier/index.ts index d4e61e3c00..b4c3188f3f 100644 --- a/modules/code-generator/src/postprocessor/prettier/index.ts +++ b/modules/code-generator/src/postprocessor/prettier/index.ts @@ -22,6 +22,8 @@ const factory: PostProcessorFactory = (config?: ProcessorConfig let parser: prettier.BuiltInParserName | any; if (fileType === 'js' || fileType === 'jsx') { parser = 'babel'; + } else if (fileType === 'json') { + parser = 'json-stringify'; } else if (PARSERS.indexOf(fileType) >= 0) { parser = fileType; } else if (cfg.customFileTypeParser[fileType]) { diff --git a/modules/code-generator/src/types/core.ts b/modules/code-generator/src/types/core.ts index 39e4c32ba9..30c86a7e9e 100644 --- a/modules/code-generator/src/types/core.ts +++ b/modules/code-generator/src/types/core.ts @@ -22,8 +22,10 @@ export enum FileType { LESS = 'less', HTML = 'html', JS = 'js', + MJS = 'mjs', JSX = 'jsx', TS = 'ts', + MTS = 'mts', TSX = 'tsx', JSON = 'json', MD = 'md', @@ -168,6 +170,7 @@ export interface IProjectBuilderOptions { * - expr: 求值的表达式 */ evalErrorsHandler?: string; + /** * Hook which is used to customize original options, we can reorder/add/remove plugins/processors * of the existing solution. diff --git a/modules/code-generator/src/types/intermediate.ts b/modules/code-generator/src/types/intermediate.ts index 30d6c4f7f5..7cba0bd44b 100644 --- a/modules/code-generator/src/types/intermediate.ts +++ b/modules/code-generator/src/types/intermediate.ts @@ -42,6 +42,7 @@ export interface IRouterInfo extends IWithDependency { * project's remarks */ export interface ProjectRemark { + /** if current project only contain one container which type is `Component` */ isSingleComponent?: boolean; } From da7ff590661823100eff75c68b43c741bab6f5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= Date: Wed, 8 Feb 2023 14:49:52 +0800 Subject: [PATCH 002/469] =?UTF-8?q?fix:=20=E5=85=BC=E5=AE=B9=20isJSExpress?= =?UTF-8?q?ion=20=E4=B8=8D=E5=8C=85=E5=90=AB=E5=87=BD=E6=95=B0=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E7=9A=84=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/rax/containerLifeCycle.ts | 2 ++ .../src/plugins/component/rax/jsx.ts | 3 +-- .../react/containerInjectDataSourceEngine.ts | 8 +++++--- .../code-generator/src/plugins/project/i18n.ts | 3 ++- modules/code-generator/src/utils/common.ts | 5 +++++ .../code-generator/src/utils/compositeType.ts | 3 ++- modules/code-generator/src/utils/dataSource.ts | 4 ++++ .../code-generator/src/utils/jsExpression.ts | 18 ++++++++++++------ modules/code-generator/src/utils/schema.ts | 2 ++ 9 files changed, 35 insertions(+), 13 deletions(-) diff --git a/modules/code-generator/src/plugins/component/rax/containerLifeCycle.ts b/modules/code-generator/src/plugins/component/rax/containerLifeCycle.ts index f928c3995e..bbee6367f2 100644 --- a/modules/code-generator/src/plugins/component/rax/containerLifeCycle.ts +++ b/modules/code-generator/src/plugins/component/rax/containerLifeCycle.ts @@ -13,6 +13,7 @@ import { IContainerInfo, } from '../../../types'; import { debug } from '../../../utils/debug'; +import { isJSExpressionFn } from '../../../utils/common'; export interface PluginConfig { fileType: string; @@ -49,6 +50,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => // 过滤掉非法数据(有些场景下会误传入空字符串或 null) if ( !isJSFunction(lifeCycles[lifeCycleName]) && + !isJSExpressionFn(lifeCycles[lifeCycleName]) && !isJSExpression(lifeCycles[lifeCycleName]) ) { return; diff --git a/modules/code-generator/src/plugins/component/rax/jsx.ts b/modules/code-generator/src/plugins/component/rax/jsx.ts index 98c80a4924..ddae619cd6 100644 --- a/modules/code-generator/src/plugins/component/rax/jsx.ts +++ b/modules/code-generator/src/plugins/component/rax/jsx.ts @@ -75,8 +75,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => // 注意:这里其实隐含了一个假设:schema 中的 componentName 应该是一个有效的 JS 标识符,而且是大写字母打头的 // FIXME: 为了快速修复临时加的逻辑,需要用 pre-process 的方式替代处理。 - const mapComponentNameToAliasOrKeepIt = (componentName: string) => - componentsNameAliasMap.get(componentName) || componentName; + const mapComponentNameToAliasOrKeepIt = (componentName: string) => componentsNameAliasMap.get(componentName) || componentName; // 然后过滤掉所有的别名 chunks next.chunks = next.chunks.filter((chunk) => !isImportAliasDefineChunk(chunk)); diff --git a/modules/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts b/modules/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts index bc5fa54ba2..c4385017b8 100644 --- a/modules/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts +++ b/modules/code-generator/src/plugins/component/react/containerInjectDataSourceEngine.ts @@ -29,6 +29,7 @@ import { generateCompositeType } from '../../../utils/compositeType'; import { parseExpressionConvertThis2Context } from '../../../utils/expressionParser'; import { isValidContainerType } from '../../../utils/schema'; import { REACT_CHUNK_NAME } from './const'; +import { isJSExpressionFn } from '../../../utils/common'; export interface PluginConfig { fileType?: string; @@ -37,6 +38,7 @@ export interface PluginConfig { * 数据源配置 */ datasourceConfig?: { + /** 数据源引擎的版本 */ engineVersion?: string; @@ -188,15 +190,15 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => export default pluginFactory; function wrapAsFunction(value: IPublicTypeCompositeValue, scope: IScope): IPublicTypeCompositeValue { - if (isJSExpression(value) || isJSFunction(value)) { + if (isJSExpression(value) || isJSFunction(value) || isJSExpressionFn(value)) { return { type: 'JSExpression', - value: `function(){ return ((${value.value}))}`, + value: `function(){ return ((${value.value}))}.bind(this)`, }; } return { type: 'JSExpression', - value: `function(){return((${generateCompositeType(value, scope)}))}`, + value: `function(){return((${generateCompositeType(value, scope)}))}.bind(this)`, }; } diff --git a/modules/code-generator/src/plugins/project/i18n.ts b/modules/code-generator/src/plugins/project/i18n.ts index ae568f9724..d1d32ff32c 100644 --- a/modules/code-generator/src/plugins/project/i18n.ts +++ b/modules/code-generator/src/plugins/project/i18n.ts @@ -25,7 +25,8 @@ const pluginFactory: BuilderComponentPluginFactory = () => { content: ` const i18nConfig = ${i18nStr}; - let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN'; + // let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN'; + let locale = 'zh-CN'; const getLocale = () => locale; diff --git a/modules/code-generator/src/utils/common.ts b/modules/code-generator/src/utils/common.ts index cfba393e96..d822fdf811 100644 --- a/modules/code-generator/src/utils/common.ts +++ b/modules/code-generator/src/utils/common.ts @@ -1,3 +1,4 @@ +import type { IPublicTypeJSExpression, IPublicTypeJSFunction } from '@alilc/lowcode-types'; import changeCase from 'change-case'; import short from 'short-uuid'; @@ -39,3 +40,7 @@ export function getStaticExprValue(expr: string): T { // eslint-disable-next-line no-new-func return Function(`"use strict";return (${expr})`)(); } + +export function isJSExpressionFn(data: any): data is IPublicTypeJSFunction { + return data?.type === 'JSExpression' && data?.extType === 'function'; +} \ No newline at end of file diff --git a/modules/code-generator/src/utils/compositeType.ts b/modules/code-generator/src/utils/compositeType.ts index 2e09e2da08..0dd612641d 100644 --- a/modules/code-generator/src/utils/compositeType.ts +++ b/modules/code-generator/src/utils/compositeType.ts @@ -16,6 +16,7 @@ import { generateExpression, generateFunction } from './jsExpression'; import { generateJsSlot } from './jsSlot'; import { executeFunctionStack } from './aopHelper'; import { parseExpressionGetKeywords } from './expressionParser'; +import { isJSExpressionFn } from './common'; interface ILegaoVariable { type: 'variable'; @@ -159,7 +160,7 @@ function generateUnknownType( return generateExpression(value, scope); } - if (isJSFunction(value)) { + if (isJSFunction(value) || isJSExpressionFn(value)) { if (options.handlers?.function) { return executeFunctionStack(value, scope, options.handlers.function, genFunction, options); } diff --git a/modules/code-generator/src/utils/dataSource.ts b/modules/code-generator/src/utils/dataSource.ts index cd10351624..5595b8defd 100644 --- a/modules/code-generator/src/utils/dataSource.ts +++ b/modules/code-generator/src/utils/dataSource.ts @@ -2,14 +2,18 @@ import changeCase from 'change-case'; import type { IProjectInfo } from '../types/intermediate'; export interface DataSourceDependenciesConfig { + /** 数据源引擎的版本 */ engineVersion?: string; + /** 数据源引擎的包名 */ enginePackage?: string; + /** 数据源 handlers 的版本 */ handlersVersion?: { [key: string]: string; }; + /** 数据源 handlers 的包名 */ handlersPackages?: { [key: string]: string; diff --git a/modules/code-generator/src/utils/jsExpression.ts b/modules/code-generator/src/utils/jsExpression.ts index 1162d08203..40099b1e24 100644 --- a/modules/code-generator/src/utils/jsExpression.ts +++ b/modules/code-generator/src/utils/jsExpression.ts @@ -5,6 +5,7 @@ import * as t from '@babel/types'; import { IPublicTypeJSExpression, IPublicTypeJSFunction, isJSExpression, isJSFunction } from '@alilc/lowcode-types'; import { CodeGeneratorError, IScope } from '../types'; import { transformExpressionLocalRef, ParseError } from './expressionParser'; +import { isJSExpressionFn } from './common'; function parseFunction(content: string): t.FunctionExpression | null { try { @@ -79,7 +80,7 @@ function getBodyStatements(content: string) { } export function isJsCode(value: unknown): boolean { - return isJSExpression(value) || isJSFunction(value); + return isJSExpressionFn(value) || isJSFunction(value); } export function generateExpression(value: any, scope: IScope): string { @@ -96,6 +97,10 @@ export function generateExpression(value: any, scope: IScope): string { throw new CodeGeneratorError('Not a JSExpression'); } +function getFunctionSource(cfg: IPublicTypeJSFunction): string { + return cfg.source || cfg.value || cfg.compiled; +} + export function generateFunction( value: any, config: { @@ -114,19 +119,20 @@ export function generateFunction( ) { if (isJsCode(value)) { const functionCfg = value as IPublicTypeJSFunction; + const functionSource = getFunctionSource(functionCfg); if (config.isMember) { - return transformFuncExpr2MethodMember(config.name || '', functionCfg.value); + return transformFuncExpr2MethodMember(config.name || '', functionSource); } if (config.isBlock) { - return getBodyStatements(functionCfg.value); + return getBodyStatements(functionSource); } if (config.isArrow) { - return getArrowFunction(functionCfg.value); + return getArrowFunction(functionSource); } if (config.isBindExpr) { - return `(${functionCfg.value}).bind(this)`; + return `(${functionSource}).bind(this)`; } - return functionCfg.value; + return functionSource; } throw new CodeGeneratorError('Not a JSFunction or JSExpression'); diff --git a/modules/code-generator/src/utils/schema.ts b/modules/code-generator/src/utils/schema.ts index 5099772771..0b8295aac3 100644 --- a/modules/code-generator/src/utils/schema.ts +++ b/modules/code-generator/src/utils/schema.ts @@ -13,6 +13,7 @@ import { isJSFunction, } from '@alilc/lowcode-types'; import { CodeGeneratorError } from '../types/error'; +import { isJSExpressionFn } from './common'; export function isContainerSchema(x: any): x is IPublicTypeContainerSchema { return ( @@ -128,6 +129,7 @@ export function handleSubNodes( // IPublicTypeCompositeObject if ( !isJSExpression(value) && + !isJSExpressionFn(value) && !isJSFunction(value) && typeof value === 'object' && value !== null From 62289e5995fe151d80aea2dfa5073b8d4aa9a578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= Date: Wed, 8 Feb 2023 16:38:37 +0800 Subject: [PATCH 003/469] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20lifeCycles?= =?UTF-8?q?=20=E6=97=A0=E6=B3=95=E6=AD=A3=E5=B8=B8=E5=87=BA=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/plugins/component/react/containerLifeCycle.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts b/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts index 8caa9b105a..75dcada63d 100644 --- a/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts +++ b/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts @@ -13,6 +13,7 @@ import { IContainerInfo, } from '../../../types'; import { isJSFunction, isJSExpression } from '@alilc/lowcode-types'; +import { isJSExpressionFn } from '../../../utils/common'; export interface PluginConfig { fileType: string; @@ -41,6 +42,7 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => // 过滤掉非法数据(有些场景下会误传入空字符串或 null) if ( !isJSFunction(lifeCycles[lifeCycleName]) && + !isJSExpressionFn(lifeCycles[lifeCycleName]) && !isJSExpression(lifeCycles[lifeCycleName]) ) { return null; From df8a7507467e8ceef1d9fa8db437dd202239c6ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= Date: Wed, 8 Feb 2023 19:50:51 +0800 Subject: [PATCH 004/469] =?UTF-8?q?fix:=20=E5=85=BC=E5=AE=B9=E6=9F=90?= =?UTF-8?q?=E4=BA=9B=E8=80=81=E7=9A=84=E9=80=9A=E8=BF=87=20JSE=20=E6=9D=A5?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=87=BD=E6=95=B0=E7=9A=84=E5=9C=BA=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/code-generator/src/utils/jsExpression.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/code-generator/src/utils/jsExpression.ts b/modules/code-generator/src/utils/jsExpression.ts index 40099b1e24..25c7f47fd5 100644 --- a/modules/code-generator/src/utils/jsExpression.ts +++ b/modules/code-generator/src/utils/jsExpression.ts @@ -135,5 +135,9 @@ export function generateFunction( return functionSource; } + if (isJSExpression(value)) { + return value.value; + } + throw new CodeGeneratorError('Not a JSFunction or JSExpression'); } From 37e07bb238396942e11e16719859bc60da34f166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= Date: Fri, 10 Feb 2023 22:10:17 +0800 Subject: [PATCH 005/469] fix: replace the top-level context only --- modules/code-generator/src/utils/expressionParser.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/code-generator/src/utils/expressionParser.ts b/modules/code-generator/src/utils/expressionParser.ts index cbc950bbc8..fc1fe41953 100644 --- a/modules/code-generator/src/utils/expressionParser.ts +++ b/modules/code-generator/src/utils/expressionParser.ts @@ -271,7 +271,7 @@ export function parseExpressionConvertThis2Context( const localVariablesSet = new Set(localVariables); - let thisScopeLevel = CROSS_THIS_SCOPE_TYPE_NODE[exprAst.type] ? -1 : 0; + let thisScopeLevel = -1; traverse(fileAst, { enter(path) { if (CROSS_THIS_SCOPE_TYPE_NODE[path.node.type]) { @@ -303,7 +303,7 @@ export function parseExpressionConvertThis2Context( } // 替换 this (只在顶层替换) - if (thisScopeLevel <= 0) { + if (thisScopeLevel === 0) { obj.replaceWith(t.identifier(contextName)); } }, @@ -317,7 +317,7 @@ export function parseExpressionConvertThis2Context( return; } - if (thisScopeLevel <= 0) { + if (thisScopeLevel === 0) { path.replaceWith(t.identifier(contextName)); } }, From 76f5ee4cf80552efac75cc62707611e94b934148 Mon Sep 17 00:00:00 2001 From: eternalsky Date: Mon, 13 Feb 2023 10:09:10 +0800 Subject: [PATCH 006/469] feat: console the expression error --- modules/code-generator/src/generator/ProjectBuilder.ts | 2 +- modules/code-generator/src/utils/jsExpression.ts | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/code-generator/src/generator/ProjectBuilder.ts b/modules/code-generator/src/generator/ProjectBuilder.ts index 040136057d..6db81b0d76 100644 --- a/modules/code-generator/src/generator/ProjectBuilder.ts +++ b/modules/code-generator/src/generator/ProjectBuilder.ts @@ -328,7 +328,7 @@ export class ProjectBuilder implements IProjectBuilder { // template: this.template, inStrictMode: this.inStrictMode, tolerateEvalErrors: true, - evalErrorsHandler: '', + evalErrorsHandler: 'console.error(error)', ...this.extraContextData, ...extraContextData, }, diff --git a/modules/code-generator/src/utils/jsExpression.ts b/modules/code-generator/src/utils/jsExpression.ts index 25c7f47fd5..08d2fafd8a 100644 --- a/modules/code-generator/src/utils/jsExpression.ts +++ b/modules/code-generator/src/utils/jsExpression.ts @@ -79,7 +79,12 @@ function getBodyStatements(content: string) { throw new Error('Can not find Function Statement'); } -export function isJsCode(value: unknown): boolean { +/** + * 是否是广义上的 JSFunction + * @param value + * @returns + */ +export function isBroadJSFunction(value: unknown): boolean { return isJSExpressionFn(value) || isJSFunction(value); } @@ -117,7 +122,7 @@ export function generateFunction( isBindExpr: false, }, ) { - if (isJsCode(value)) { + if (isBroadJSFunction(value)) { const functionCfg = value as IPublicTypeJSFunction; const functionSource = getFunctionSource(functionCfg); if (config.isMember) { From 20b34b74a257497a6b766796076cc88b045af49b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= Date: Tue, 14 Feb 2023 17:49:58 +0800 Subject: [PATCH 007/469] feat: handle extra slots --- modules/code-generator/src/const/index.ts | 21 +++++++++++++ .../src/generator/ProjectBuilder.ts | 30 ++++++++++++------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/modules/code-generator/src/const/index.ts b/modules/code-generator/src/const/index.ts index 103d912db6..24449ca429 100644 --- a/modules/code-generator/src/const/index.ts +++ b/modules/code-generator/src/const/index.ts @@ -8,5 +8,26 @@ export const CONTAINER_TYPE = { export const SUPPORT_SCHEMA_VERSION_LIST = ['0.0.1', '1.0.0']; +// built-in slot names which have been handled in ProjectBuilder +export const BUILTIN_SLOT_NAMES = [ + 'pages', + 'components', + 'router', + 'entry', + 'appConfig', + 'buildConfig', + 'constants', + 'utils', + 'i18n', + 'globalStyle', + 'htmlEntry', + 'packageJSON', + 'demo', +]; + +export const isBuiltinSlotName = function (name: string) { + return BUILTIN_SLOT_NAMES.includes(name); +}; + export * from './file'; export * from './generator'; diff --git a/modules/code-generator/src/generator/ProjectBuilder.ts b/modules/code-generator/src/generator/ProjectBuilder.ts index 040136057d..f3fb5fc1c5 100644 --- a/modules/code-generator/src/generator/ProjectBuilder.ts +++ b/modules/code-generator/src/generator/ProjectBuilder.ts @@ -16,6 +16,7 @@ import { createResultDir, addDirectory, addFile } from '../utils/resultHelper'; import { createModuleBuilder } from './ModuleBuilder'; import { ProjectPreProcessor, ProjectPostProcessor, IContextData } from '../types/core'; import { CodeGeneratorError } from '../types/error'; +import { isBuiltinSlotName } from '../const'; interface IModuleInfo { moduleName?: string; @@ -272,17 +273,8 @@ export class ProjectBuilder implements IProjectBuilder { }); } - // TODO: 更多 slots 的处理??是不是可以考虑把 template 中所有的 slots 都处理下? - // const whitelistSlotNames = [ - // 'router', - // 'entry', - // 'appConfig', - // 'buildConfig', - // 'router', - // ]; - // Object.keys(this.template.slots).forEach((slotName: string) => { - - // }); + // handle extra slots + await this.generateExtraSlots(builders, parseResult, buildResult); // Post Process const isSingleComponent = parseResult?.project?.projectRemark?.isSingleComponent; @@ -339,6 +331,22 @@ export class ProjectBuilder implements IProjectBuilder { return builders; } + + private async generateExtraSlots( + builders: Record, + parseResult: IParseResult, + buildResult: IModuleInfo[], + ) { + for (const slotName in this.template.slots) { + if (!isBuiltinSlotName(slotName)) { + const { files } = await builders[slotName].generateModule(parseResult); + buildResult.push({ + path: this.template.slots[slotName].path, + files, + }); + } + } + } } export function createProjectBuilder(initOptions: ProjectBuilderInitOptions): IProjectBuilder { From bbe438cf83c8c92ba7c2896eff4d27cd991525ea Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 20 Feb 2023 14:06:00 +0800 Subject: [PATCH 008/469] test: add ut for utils/build-components --- .github/workflows/cov packages.yml | 22 ++ .../build-components/buildComponents.test.ts | 336 ++++++++++++++++++ .../build-components/getProjectUtils.test.ts | 43 +++ .../build-components/getSubComponent.test.ts | 85 +++++ 4 files changed, 486 insertions(+) create mode 100644 packages/utils/test/src/build-components/buildComponents.test.ts create mode 100644 packages/utils/test/src/build-components/getProjectUtils.test.ts create mode 100644 packages/utils/test/src/build-components/getSubComponent.test.ts diff --git a/.github/workflows/cov packages.yml b/.github/workflows/cov packages.yml index 228e1cf989..499750282d 100644 --- a/.github/workflows/cov packages.yml +++ b/.github/workflows/cov packages.yml @@ -71,4 +71,26 @@ jobs: 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 + package-manager: yarn annotations: none \ No newline at end of file diff --git a/packages/utils/test/src/build-components/buildComponents.test.ts b/packages/utils/test/src/build-components/buildComponents.test.ts new file mode 100644 index 0000000000..5662aa12c9 --- /dev/null +++ b/packages/utils/test/src/build-components/buildComponents.test.ts @@ -0,0 +1,336 @@ + +import { buildComponents } from "../../../src/build-components"; + +function Button() {}; + +function WrapButton() {}; + +function ButtonGroup() {}; + +function WrapButtonGroup() {}; + +ButtonGroup.Button = Button; + +Button.displayName = "Button"; +ButtonGroup.displayName = "ButtonGroup"; +ButtonGroup.prototype.isReactComponent = true; +Button.prototype.isReactComponent = true; + +jest.mock('../../../src/is-react', () => { + const original = jest.requireActual('../../../src/is-react'); + return { + ...original, + wrapReactClass(view) { + return view; + } + } +}) + +describe('build-component', () => { + it('basic button', () => { + expect( + buildComponents( + { + '@alilc/button': { + Button, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'Button', + subName: 'Button', + } + }, + () => {}, + )) + .toEqual({ + Button, + }); + }); + + it('component is a __esModule', () => { + expect( + buildComponents( + { + '@alilc/button': { + __esModule: true, + default: Button, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + } + }, + () => {}, + )) + .toEqual({ + Button, + }); + }) + + it('basic warp button', () => { + expect( + buildComponents( + { + '@alilc/button': { + WrapButton, + } + }, + { + WrapButton: { + componentName: 'WrapButton', + package: '@alilc/button', + destructuring: true, + exportName: 'WrapButton', + subName: 'WrapButton', + } + }, + () => {}, + )) + .toEqual({ + WrapButton, + }); + }); + + it('destructuring is false button', () => { + expect( + buildComponents( + { + '@alilc/button': Button + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: false, + } + }, + () => {}, + )) + .toEqual({ + Button, + }); + }); + + it('Button and ButtonGroup', () => { + expect( + buildComponents( + { + '@alilc/button': { + Button, + ButtonGroup, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'Button', + subName: 'Button', + }, + ButtonGroup: { + componentName: 'ButtonGroup', + package: '@alilc/button', + destructuring: true, + exportName: 'ButtonGroup', + subName: 'ButtonGroup', + } + }, + () => {}, + )) + .toEqual({ + Button, + ButtonGroup, + }); + }); + + it('ButtonGroup and ButtonGroup.Button', () => { + expect( + buildComponents( + { + '@alilc/button': { + ButtonGroup, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'ButtonGroup', + subName: 'ButtonGroup.Button', + }, + ButtonGroup: { + componentName: 'ButtonGroup', + package: '@alilc/button', + destructuring: true, + exportName: 'ButtonGroup', + subName: 'ButtonGroup', + } + }, + () => {}, + )) + .toEqual({ + Button, + ButtonGroup, + }); + }); + + it('ButtonGroup.default and ButtonGroup.Button', () => { + expect( + buildComponents( + { + '@alilc/button': ButtonGroup, + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'Button', + subName: 'Button', + }, + ButtonGroup: { + componentName: 'ButtonGroup', + package: '@alilc/button', + destructuring: true, + exportName: 'default', + subName: 'default', + } + }, + () => {}, + )) + .toEqual({ + Button, + ButtonGroup, + }); + }); + + it('no npm component', () => { + expect( + buildComponents( + { + '@alilc/button': Button, + }, + { + Button: null, + }, + () => {}, + )) + .toEqual({}); + }); + + it('no npm component and global button', () => { + window.Button = Button; + expect( + buildComponents( + {}, + { + Button: null, + }, + () => {}, + )) + .toEqual({ + Button, + }); + window.Button = null; + }); + + it('componentsMap value is component funtion', () => { + expect( + buildComponents( + {}, + { + Button, + }, + () => {}, + )) + .toEqual({ + Button, + }); + }); + + + it('componentsMap value is component', () => { + expect( + buildComponents( + {}, + { + Button: WrapButton, + }, + () => {}, + )) + .toEqual({ + Button: WrapButton, + }); + }); + + it('componentsMap value is mix component', () => { + expect( + buildComponents( + {}, + { + Button: { + WrapButton, + Button, + ButtonGroup, + }, + }, + () => {}, + )) + .toEqual({ + Button: { + WrapButton, + Button, + ButtonGroup, + }, + }); + }); + + it('componentsMap value is Lowcode Component', () => { + expect( + buildComponents( + {}, + { + Button: { + componentName: 'Component', + schema: {}, + }, + }, + (component) => { + return component as any; + }, + )) + .toEqual({ + Button: { + componentName: 'Component', + schema: {}, + }, + }); + }) +}); + +describe('build div component', () => { + it('build div component', () => { + const components = buildComponents( + { + '@alilc/div': 'div' + }, + { + div: { + componentName: 'div', + package: '@alilc/div' + } + }, + () => {}, + ); + + expect(components['div']).not.toBeNull(); + }) +}) \ No newline at end of file diff --git a/packages/utils/test/src/build-components/getProjectUtils.test.ts b/packages/utils/test/src/build-components/getProjectUtils.test.ts new file mode 100644 index 0000000000..216f3db427 --- /dev/null +++ b/packages/utils/test/src/build-components/getProjectUtils.test.ts @@ -0,0 +1,43 @@ +import { getProjectUtils } from "../../../src/build-components"; + +const sampleUtil = () => 'I am a sample util'; +const sampleUtil2 = () => 'I am a sample util 2'; + +describe('get project utils', () => { + it('get utils with destructuring true', () => { + expect(getProjectUtils( + { + '@alilc/utils': { + destructuring: true, + sampleUtil, + sampleUtil2, + } + }, + [{ + name: 'sampleUtils', + npm: { + package: '@alilc/utils' + } + }] + )).toEqual({ + sampleUtil, + sampleUtil2, + }) + }); + + it('get utils with name', () => { + expect(getProjectUtils( + { + '@alilc/utils': sampleUtil + }, + [{ + name: 'sampleUtil', + npm: { + package: '@alilc/utils' + } + }] + )).toEqual({ + sampleUtil, + }) + }); +}) \ No newline at end of file diff --git a/packages/utils/test/src/build-components/getSubComponent.test.ts b/packages/utils/test/src/build-components/getSubComponent.test.ts new file mode 100644 index 0000000000..ca91bb2304 --- /dev/null +++ b/packages/utils/test/src/build-components/getSubComponent.test.ts @@ -0,0 +1,85 @@ +import { getSubComponent } from '../../../src/build-components'; + +function Button() {} + +function ButtonGroup() {} + +ButtonGroup.Button = Button; + +function OnlyButtonGroup() {} + +describe('getSubComponent library is object', () => { + it('get Button from Button', () => { + expect(getSubComponent({ + Button, + }, ['Button'])).toBe(Button); + }); + + it('get ButtonGroup.Button from ButtonGroup', () => { + expect(getSubComponent({ + ButtonGroup, + }, ['ButtonGroup', 'Button'])).toBe(Button); + }); + + it('get ButtonGroup from ButtonGroup', () => { + expect(getSubComponent({ + ButtonGroup, + }, ['ButtonGroup'])).toBe(ButtonGroup); + }); + + it('get ButtonGroup.Button from OnlyButtonGroup', () => { + expect(getSubComponent({ + ButtonGroup: OnlyButtonGroup, + }, ['ButtonGroup', 'Button'])).toBe(OnlyButtonGroup); + }); +}); + +describe('getSubComponent library is null', () => { + it('getSubComponent library is null', () => { + expect(getSubComponent(null, ['ButtonGroup', 'Button'])).toBeNull(); + }); +}) + +describe('getSubComponent paths is []', () => { + it('getSubComponent paths is []', () => { + expect(getSubComponent(Button, [])).toBe(Button); + }); +}); + +describe('getSubComponent make error', () => { + it('library is string', () => { + expect(getSubComponent(true, ['Button'])).toBe(null); + }); + + it('library is boolean', () => { + expect(getSubComponent('I am a string', ['Button'])).toBe(null); + }); + + it('library is number', () => { + expect(getSubComponent(123, ['Button'])).toBe(null); + }); + + it('library ButtonGroup is null', () => { + expect(getSubComponent({ + ButtonGroup: null, + }, ['ButtonGroup', 'Button'])).toBe(null); + }); + + it('library ButtonGroup.Button is null', () => { + expect(getSubComponent({ + ButtonGroup: null, + }, ['ButtonGroup', 'Button', 'SubButton'])).toBe(null); + }); + + it('path s is [[]]', () => { + expect(getSubComponent({ + ButtonGroup: null, + }, [['ButtonGroup'] as any, 'Button'])).toBe(null); + }); + + it('ButtonGroup is undefined', () => { + expect(getSubComponent({ + ButtonGroup: undefined, + }, ['ButtonGroup', 'Button'])).toBe(null); + }); +}) \ No newline at end of file From 16c4c96c66d080e4dd4c45a4006c1117427a762c Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 20 Feb 2023 15:53:38 +0800 Subject: [PATCH 009/469] docs: improve comments for plugin-context --- .../designer/src/plugin/plugin-context.ts | 6 +- .../types/src/shell/model/plugin-context.ts | 62 ++++++++++++++++++- 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/packages/designer/src/plugin/plugin-context.ts b/packages/designer/src/plugin/plugin-context.ts index c1a7ddee83..f43134c75d 100644 --- a/packages/designer/src/plugin/plugin-context.ts +++ b/packages/designer/src/plugin/plugin-context.ts @@ -16,6 +16,7 @@ import { IPublicApiPlugins, IPublicTypePluginDeclaration, IPublicApiCanvas, + IPublicApiWorkspace, } from '@alilc/lowcode-types'; import { IPluginContextOptions, @@ -24,8 +25,8 @@ import { } from './plugin-types'; import { isValidPreferenceKey } from './plugin-utils'; - -export default class PluginContext implements IPublicModelPluginContext, ILowCodePluginContextPrivate { +export default class PluginContext implements + IPublicModelPluginContext, ILowCodePluginContextPrivate { hotkey: IPublicApiHotkey; project: IPublicApiProject; skeleton: IPublicApiSkeleton; @@ -39,6 +40,7 @@ export default class PluginContext implements IPublicModelPluginContext, ILowCod preference: IPluginPreferenceMananger; pluginEvent: IPublicApiEvent; canvas: IPublicApiCanvas; + workspace: IPublicApiWorkspace; constructor( options: IPluginContextOptions, diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts index ae7ef8bbb2..5d97b54726 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -10,6 +10,7 @@ import { IPublicApiCanvas, IPluginPreferenceMananger, IPublicApiPlugins, + IPublicApiWorkspace, } from '../api'; import { IPublicModelEngineConfig } from './'; @@ -28,31 +29,88 @@ export interface IPublicModelPluginContext { * by using this, init options can be accessed from inside plugin */ preference: IPluginPreferenceMananger; + + /** + * skeleton API + * @tutorial https://lowcode-engine.cn/site/docs/api/skeleton + */ get skeleton(): IPublicApiSkeleton; + + /** + * hotkey API + * @tutorial https://lowcode-engine.cn/site/docs/api/hotkey + */ get hotkey(): IPublicApiHotkey; + + /** + * setter API + * @tutorial https://lowcode-engine.cn/site/docs/api/setters + */ get setters(): IPublicApiSetters; + + /** + * config API + * @tutorial https://lowcode-engine.cn/site/docs/api/config + */ get config(): IPublicModelEngineConfig; + + /** + * material API + * @tutorial https://lowcode-engine.cn/site/docs/api/material + */ get material(): IPublicApiMaterial; /** + * event API * this event works globally, can be used between plugins and engine. + * @tutorial https://lowcode-engine.cn/site/docs/api/event */ get event(): IPublicApiEvent; + + /** + * project API + * @tutorial https://lowcode-engine.cn/site/docs/api/project + */ get project(): IPublicApiProject; + + /** + * common API + * @tutorial https://lowcode-engine.cn/site/docs/api/common + */ get common(): IPublicApiCommon; + + /** + * plugins API + * @tutorial https://lowcode-engine.cn/site/docs/api/plugins + */ get plugins(): IPublicApiPlugins; + + /** + * logger API + * @tutorial https://lowcode-engine.cn/site/docs/api/logger + */ get logger(): IPublicApiLogger; /** * this event works within current plugin, on an emit locally. + * @tutorial https://lowcode-engine.cn/site/docs/api/event */ get pluginEvent(): IPublicApiEvent; + + /** + * canvas API + * @tutorial https://lowcode-engine.cn/site/docs/api/canvas + */ get canvas(): IPublicApiCanvas; + + /** + * workspace API + * @tutorial https://lowcode-engine.cn/site/docs/api/workspace + */ + get workspace(): IPublicApiWorkspace; } /** - * - * * @deprecated please use IPublicModelPluginContext instead */ export interface ILowCodePluginContext extends IPublicModelPluginContext { From 7c2ebf3c0228b9310e7093f4f2f8123092ca8ac6 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 21 Feb 2023 11:46:22 +0800 Subject: [PATCH 010/469] refactor: rename executeLifeCycleMethod to executeLifeCycleMethod --- packages/renderer-core/src/renderer/addon.tsx | 2 +- packages/renderer-core/src/renderer/base.tsx | 20 +++++++++---------- packages/renderer-core/src/renderer/block.tsx | 2 +- .../renderer-core/src/renderer/component.tsx | 2 +- packages/renderer-core/src/renderer/page.tsx | 3 +-- packages/renderer-core/src/types/index.ts | 2 +- .../tests/renderer/base.test.tsx | 2 +- 7 files changed, 16 insertions(+), 17 deletions(-) diff --git a/packages/renderer-core/src/renderer/addon.tsx b/packages/renderer-core/src/renderer/addon.tsx index 62aeddbbad..9cb114bee4 100644 --- a/packages/renderer-core/src/renderer/addon.tsx +++ b/packages/renderer-core/src/renderer/addon.tsx @@ -45,7 +45,7 @@ export default function addonRendererFactory(): IBaseRenderComponent { this.__initDataSource(props); this.open = this.open || (() => { }); this.close = this.close || (() => { }); - this.__excuteLifeCycleMethod('constructor', [...arguments]); + this.__executeLifeCycleMethod('constructor', [...arguments]); } async componentWillUnmount() { diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 054628c5fe..311493736a 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -40,7 +40,7 @@ import isUseLoop from '../utils/is-use-loop'; * execute method in schema.lifeCycles with context * @PRIVATE */ -export function excuteLifeCycleMethod(context: any, schema: IPublicTypeNodeSchema, method: string, args: any, thisRequiredInJSE: boolean | undefined): any { +export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSchema, method: string, args: any, thisRequiredInJSE: boolean | undefined): any { if (!context || !isSchema(schema) || !method) { return; } @@ -183,32 +183,32 @@ export default function baseRendererFactory(): IBaseRenderComponent { __afterInit(_props: IBaseRendererProps) { } static getDerivedStateFromProps(props: IBaseRendererProps, state: any) { - return excuteLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE); + return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE); } async getSnapshotBeforeUpdate(...args: any[]) { - this.__excuteLifeCycleMethod('getSnapshotBeforeUpdate', args); + this.__executeLifeCycleMethod('getSnapshotBeforeUpdate', args); this.__debug(`getSnapshotBeforeUpdate - ${this.props?.__schema?.fileName}`); } async componentDidMount(...args: any[]) { this.reloadDataSource(); - this.__excuteLifeCycleMethod('componentDidMount', args); + this.__executeLifeCycleMethod('componentDidMount', args); this.__debug(`componentDidMount - ${this.props?.__schema?.fileName}`); } async componentDidUpdate(...args: any[]) { - this.__excuteLifeCycleMethod('componentDidUpdate', args); + this.__executeLifeCycleMethod('componentDidUpdate', args); this.__debug(`componentDidUpdate - ${this.props.__schema.fileName}`); } async componentWillUnmount(...args: any[]) { - this.__excuteLifeCycleMethod('componentWillUnmount', args); + this.__executeLifeCycleMethod('componentWillUnmount', args); this.__debug(`componentWillUnmount - ${this.props?.__schema?.fileName}`); } async componentDidCatch(...args: any[]) { - this.__excuteLifeCycleMethod('componentDidCatch', args); + this.__executeLifeCycleMethod('componentDidCatch', args); console.warn(args); } @@ -248,8 +248,8 @@ export default function baseRendererFactory(): IBaseRenderComponent { * execute method in schema.lifeCycles * @PRIVATE */ - __excuteLifeCycleMethod = (method: string, args?: any) => { - excuteLifeCycleMethod(this, this.props.__schema, method, args, this.props.thisRequiredInJSE); + __executeLifeCycleMethod = (method: string, args?: any) => { + executeLifeCycleMethod(this, this.props.__schema, method, args, this.props.thisRequiredInJSE); }; /** @@ -406,7 +406,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { __render = () => { const schema = this.props.__schema; - this.__excuteLifeCycleMethod('render'); + this.__executeLifeCycleMethod('render'); this.__writeCss(this.props); const { engine } = this.context; diff --git a/packages/renderer-core/src/renderer/block.tsx b/packages/renderer-core/src/renderer/block.tsx index 560b5924b3..5132997f05 100644 --- a/packages/renderer-core/src/renderer/block.tsx +++ b/packages/renderer-core/src/renderer/block.tsx @@ -13,7 +13,7 @@ export default function blockRendererFactory(): IBaseRenderComponent { const schema = props.__schema || {}; this.state = this.__parseData(schema.state || {}); this.__initDataSource(props); - this.__excuteLifeCycleMethod('constructor', [...arguments]); + this.__executeLifeCycleMethod('constructor', [...arguments]); } render() { diff --git a/packages/renderer-core/src/renderer/component.tsx b/packages/renderer-core/src/renderer/component.tsx index 58d5c0093c..4be33f5c19 100644 --- a/packages/renderer-core/src/renderer/component.tsx +++ b/packages/renderer-core/src/renderer/component.tsx @@ -15,7 +15,7 @@ export default function componentRendererFactory(): IBaseRenderComponent { const schema = props.__schema || {}; this.state = this.__parseData(schema.state || {}); this.__initDataSource(props); - this.__excuteLifeCycleMethod('constructor', arguments as any); + this.__executeLifeCycleMethod('constructor', arguments as any); } render() { diff --git a/packages/renderer-core/src/renderer/page.tsx b/packages/renderer-core/src/renderer/page.tsx index 9875f8d73e..9ba49c7233 100644 --- a/packages/renderer-core/src/renderer/page.tsx +++ b/packages/renderer-core/src/renderer/page.tsx @@ -15,7 +15,7 @@ export default function pageRendererFactory(): IBaseRenderComponent { const schema = props.__schema || {}; this.state = this.__parseData(schema.state || {}); this.__initDataSource(props); - this.__excuteLifeCycleMethod('constructor', [props, ...rest]); + this.__executeLifeCycleMethod('constructor', [props, ...rest]); } async componentDidUpdate(prevProps: IBaseRendererProps, _prevState: {}, snapshot: unknown) { @@ -44,7 +44,6 @@ export default function pageRendererFactory(): IBaseRenderComponent { }); this.__render(); - const { Page } = __components; if (Page) { return this.__renderComp(Page, { pageContext: this }); diff --git a/packages/renderer-core/src/types/index.ts b/packages/renderer-core/src/types/index.ts index 8d619737c3..4e44dd312f 100644 --- a/packages/renderer-core/src/types/index.ts +++ b/packages/renderer-core/src/types/index.ts @@ -281,7 +281,7 @@ export type IBaseRendererInstance = IGeneralComponent< __beforeInit(props: IBaseRendererProps): void; __init(props: IBaseRendererProps): void; __afterInit(props: IBaseRendererProps): void; - __excuteLifeCycleMethod(method: string, args?: any[]): void; + __executeLifeCycleMethod(method: string, args?: any[]): void; __bindCustomMethods(props: IBaseRendererProps): void; __generateCtx(ctx: Record): void; __parseData(data: any, ctx?: any): any; diff --git a/packages/renderer-core/tests/renderer/base.test.tsx b/packages/renderer-core/tests/renderer/base.test.tsx index 3d19e324b5..63c5cfbb2e 100644 --- a/packages/renderer-core/tests/renderer/base.test.tsx +++ b/packages/renderer-core/tests/renderer/base.test.tsx @@ -121,7 +121,7 @@ describe('Base Render methods', () => { // it('should excute lifecycle.componentDidCatch when defined', () => { // }); - // it('__excuteLifeCycleMethod should work', () => { + // it('__executeLifeCycleMethod should work', () => { // }); // it('reloadDataSource should work', () => { From 7c16bb1f9cc08be8d1a40ae2e694f1d3a68a20ff Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 21 Feb 2023 17:41:03 +0800 Subject: [PATCH 011/469] feat: fix prop module issue and ts type definition --- .../src/designer/setting/setting-field.ts | 5 +++-- .../src/designer/setting/setting-prop-entry.ts | 5 +++-- .../designer/src/document/node/props/prop.ts | 2 +- .../types/src/shell/type/field-extra-props.ts | 17 +++++++++++++++-- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/designer/src/designer/setting/setting-field.ts b/packages/designer/src/designer/setting/setting-field.ts index c8bdf52e85..50e2819d60 100644 --- a/packages/designer/src/designer/setting/setting-field.ts +++ b/packages/designer/src/designer/setting/setting-field.ts @@ -58,7 +58,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry { constructor( parent: SettingEntry, config: IPublicTypeFieldConfig, - settingFieldCollector?: (name: string | number, field: SettingField) => void, + private settingFieldCollector?: (name: string | number, field: SettingField) => void, ) { super(parent, config.name, config.type); makeObservable(this); @@ -137,7 +137,8 @@ export class SettingField extends SettingPropEntry implements SettingEntry { // 创建子配置项,通常用于 object/array 类型数据 createField(config: IPublicTypeFieldConfig): SettingField { - return new SettingField(this, config); + this.settingFieldCollector?.(getSettingFieldCollectorKey(this.parent, config), this); + return new SettingField(this, config, this.settingFieldCollector); } purge() { diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts index 3c3cee9d35..d523a0d35f 100644 --- a/packages/designer/src/designer/setting/setting-prop-entry.ts +++ b/packages/designer/src/designer/setting/setting-prop-entry.ts @@ -1,11 +1,12 @@ import { obx, computed, makeObservable, runInAction, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { GlobalEvent, IPublicModelEditor, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; import { uniqueId, isJSExpression, isSettingField } from '@alilc/lowcode-utils'; +import { Setters } from '@alilc/lowcode-shell'; import { SettingEntry } from './setting-entry'; import { INode } from '../../document'; import { IComponentMeta } from '../../component-meta'; import { Designer } from '../designer'; -import { Setters } from '@alilc/lowcode-shell'; +import { SettingField } from './setting-field'; export class SettingPropEntry implements SettingEntry { // === static properties === @@ -52,7 +53,7 @@ export class SettingPropEntry implements SettingEntry { extraProps: any = {}; - constructor(readonly parent: SettingEntry, name: string | number, type?: 'field' | 'group') { + constructor(readonly parent: SettingEntry | SettingField, name: string | number, type?: 'field' | 'group') { makeObservable(this); if (type == null) { const c = typeof name === 'string' ? name.slice(0, 1) : ''; diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index f23c686e7a..f16f24c841 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -303,7 +303,7 @@ export class Prop implements IProp, IPropParent { return this._value; } const values = this.items!.map((prop) => { - return prop.export(stage); + return prop?.export(stage); }); if (values.every((val) => val === undefined)) { return undefined; diff --git a/packages/types/src/shell/type/field-extra-props.ts b/packages/types/src/shell/type/field-extra-props.ts index 948411c892..2977da1d87 100644 --- a/packages/types/src/shell/type/field-extra-props.ts +++ b/packages/types/src/shell/type/field-extra-props.ts @@ -1,59 +1,72 @@ -import { IPublicModelSettingTarget } from '../model'; +import { IPublicModelSettingPropEntry, IPublicModelSettingTarget } from '../model'; import { IPublicTypeLiveTextEditingConfig } from './'; /** * extra props for field */ export interface IPublicTypeFieldExtraProps { + /** * 是否必填参数 */ isRequired?: boolean; + /** * default value of target prop for setter use */ defaultValue?: any; + /** * get value for field */ getValue?: (target: IPublicModelSettingTarget, fieldValue: any) => any; + /** * set value for field */ setValue?: (target: IPublicModelSettingTarget, value: any) => void; + /** * the field conditional show, is not set always true * @default undefined */ - condition?: (target: IPublicModelSettingTarget) => boolean; + condition?: (target: IPublicModelSettingPropEntry) => boolean; + /** * autorun when something change */ autorun?: (target: IPublicModelSettingTarget) => void; + /** * is this field is a virtual field that not save to schema */ virtual?: (target: IPublicModelSettingTarget) => boolean; + /** * default collapsed when display accordion */ defaultCollapsed?: boolean; + /** * important field */ important?: boolean; + /** * internal use */ forceInline?: number; + /** * 是否支持变量配置 */ supportVariable?: boolean; + /** * compatiable vision display */ display?: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry'; + // @todo 这个 omit 是否合理? /** * @todo 待补充文档 From b319286c4896e34844e6f21a552874f0f70d0742 Mon Sep 17 00:00:00 2001 From: JackLian Date: Tue, 21 Feb 2023 15:22:52 +0800 Subject: [PATCH 012/469] feat: add shell config model --- docs/docs/api/model/config.md | 113 ++++++++++++++++++ packages/editor-core/src/config.ts | 13 +- packages/engine/src/engine-core.ts | 3 +- packages/shell/src/index.ts | 4 +- packages/shell/src/model/config.ts | 39 ++++++ packages/shell/src/model/index.ts | 3 +- packages/shell/src/symbols.ts | 3 +- .../types/src/shell/model/engine-config.ts | 3 +- 8 files changed, 168 insertions(+), 13 deletions(-) create mode 100644 docs/docs/api/model/config.md create mode 100644 packages/shell/src/model/config.ts diff --git a/docs/docs/api/model/config.md b/docs/docs/api/model/config.md new file mode 100644 index 0000000000..854aa1a04f --- /dev/null +++ b/docs/docs/api/model/config.md @@ -0,0 +1,113 @@ +--- +title: Config +sidebar_position: 16 +--- +> **@types** [IPublicModelEngineConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/engine-config.ts)
+> **@since** v1.1.3 + +## 方法 +### has + +判断指定 key 是否有值 + +```typescript +/** + * 判断指定 key 是否有值 + * check if config has certain key configed + * @param key + * @returns + */ +has(key: string): boolean; +``` + +### get + +获取指定 key 的值 + +```typescript +/** + * 获取指定 key 的值 + * get value by key + * @param key + * @param defaultValue + * @returns + */ +get(key: string, defaultValue?: any): any; +``` + +### set + +设置指定 key 的值 + +```typescript +/** + * 设置指定 key 的值 + * set value for certain key + * @param key + * @param value + */ +set(key: string, value: any): void; +``` + +### setConfig +批量设值,set 的对象版本 + +```typescript +/** + * 批量设值,set 的对象版本 + * set multiple config key-values + * @param config + */ +setConfig(config: { [key: string]: any }): void; +``` + +### 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) + +## 事件 + +### 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): IPublicTypeDisposable; +``` + +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + +### onceGot +获取指定 key 的值,若此时还未赋值,则等待,若已有值,则直接返回值 +> 注:此函数返回 Promise 实例,只会执行(fullfill)一次 + +```typescript +/** + * 获取指定 key 的值,若此时还未赋值,则等待,若已有值,则直接返回值 + * 注:此函数返回 Promise 实例,只会执行(fullfill)一次 + * wait until value of certain key is set, will only be + * triggered once. + * @param key + * @returns + */ +onceGot(key: string): Promise; +``` diff --git a/packages/editor-core/src/config.ts b/packages/editor-core/src/config.ts index 91ef33adbe..12ef865ec5 100644 --- a/packages/editor-core/src/config.ts +++ b/packages/editor-core/src/config.ts @@ -124,9 +124,7 @@ const VALID_ENGINE_OPTIONS = { type: 'array', description: '自定义 simulatorUrl 的地址', }, - /** - * 与 react-renderer 的 appHelper 一致,https://lowcode-engine.cn/site/docs/guide/expand/runtime/renderer#apphelper - */ + // 与 react-renderer 的 appHelper 一致,https://lowcode-engine.cn/site/docs/guide/expand/runtime/renderer#apphelper appHelper: { type: 'object', description: '定义 utils 和 constants 等对象', @@ -149,7 +147,6 @@ const VALID_ENGINE_OPTIONS = { }, }; - const getStrictModeValue = (engineOptions: IPublicTypeEngineOptions, defaultValue: boolean): boolean => { if (!engineOptions || !isPlainObject(engineOptions)) { return defaultValue; @@ -161,7 +158,8 @@ const getStrictModeValue = (engineOptions: IPublicTypeEngineOptions, defaultValu return engineOptions.enableStrictPluginMode; }; -export interface IEngineConfigPrivate { +export interface IEngineConfig extends IPublicModelEngineConfig { + /** * if engineOptions.strictPluginMode === true, only accept propertied predefined in EngineOptions. * @@ -176,8 +174,7 @@ export interface IEngineConfigPrivate { delWait(key: string, fn: any): void; } - -export class EngineConfig implements IPublicModelEngineConfig, IEngineConfigPrivate { +export class EngineConfig implements IEngineConfig { private config: { [key: string]: any } = {}; private waits = new Map< @@ -350,4 +347,4 @@ export class EngineConfig implements IPublicModelEngineConfig, IEngineConfigPriv } } -export const engineConfig = new EngineConfig(); \ No newline at end of file +export const engineConfig = new EngineConfig(); diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index abe378d64a..ea0554cad2 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -43,6 +43,7 @@ import { Logger, Canvas, Workspace, + Config, } from '@alilc/lowcode-shell'; import { isPlainObject } from '@alilc/lowcode-utils'; import './modules/live-editing'; @@ -96,7 +97,7 @@ editor.set('project', project); editor.set('setters' as any, setters); editor.set('material', material); editor.set('innerHotkey', innerHotkey); -const config = engineConfig; +const config = new Config(engineConfig); const event = new Event(commonEvent, { prefix: 'common' }); const logger = new Logger({ level: 'warn', bizName: 'common' }); const common = new Common(editor, innerSkeleton); diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index 74d11288ea..aed56fb957 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -10,6 +10,7 @@ import { SettingPropEntry, SettingTopEntry, Clipboard, + Config, } from './model'; import { Project, @@ -61,4 +62,5 @@ export { Workspace, Clipboard, SimulatorHost, -}; \ No newline at end of file + Config, +}; diff --git a/packages/shell/src/model/config.ts b/packages/shell/src/model/config.ts new file mode 100644 index 0000000000..d841208780 --- /dev/null +++ b/packages/shell/src/model/config.ts @@ -0,0 +1,39 @@ +import { IPublicModelEngineConfig, IPublicModelPreference, IPublicTypeDisposable } from '@alilc/lowcode-types'; +import { configSymbol } from '../symbols'; +import { IEngineConfig } from '@alilc/lowcode-editor-core'; + +export class Config implements IPublicModelEngineConfig { + private readonly [configSymbol]: IEngineConfig; + + constructor(innerEngineConfig: IEngineConfig) { + this[configSymbol] = innerEngineConfig; + } + + has(key: string): boolean { + return this[configSymbol].has(key); + } + + get(key: string, defaultValue?: any): any { + return this[configSymbol].get(key, defaultValue); + } + + set(key: string, value: any): void { + this[configSymbol].set(key, value); + } + + setConfig(config: { [key: string]: any }): void { + this[configSymbol].setConfig(config); + } + + onceGot(key: string): Promise { + return this[configSymbol].onceGot(key); + } + + onGot(key: string, fn: (data: any) => void): IPublicTypeDisposable { + return this[configSymbol].onGot(key, fn); + } + + getPreference(): IPublicModelPreference { + return this[configSymbol].getPreference(); + } +} diff --git a/packages/shell/src/model/index.ts b/packages/shell/src/model/index.ts index f2805342eb..8e18c36bb6 100644 --- a/packages/shell/src/model/index.ts +++ b/packages/shell/src/model/index.ts @@ -18,4 +18,5 @@ export * from './resource'; export * from './active-tracker'; export * from './plugin-instance'; export * from './window'; -export * from './clipboard'; \ No newline at end of file +export * from './clipboard'; +export * from './config'; diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index dac981e963..91ad609ac9 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -31,4 +31,5 @@ export const windowSymbol = Symbol('window'); export const pluginInstanceSymbol = Symbol('plugin-instance'); export const resourceTypeSymbol = Symbol('resourceType'); export const resourceSymbol = Symbol('resource'); -export const clipboardSymbol = Symbol('clipboard'); \ No newline at end of file +export const clipboardSymbol = Symbol('clipboard'); +export const configSymbol = Symbol('configSymbol'); diff --git a/packages/types/src/shell/model/engine-config.ts b/packages/types/src/shell/model/engine-config.ts index 2b17d7e725..c9473cd120 100644 --- a/packages/types/src/shell/model/engine-config.ts +++ b/packages/types/src/shell/model/engine-config.ts @@ -1,3 +1,4 @@ +import { IPublicTypeDisposable } from '../type'; import { IPublicModelPreference } from './'; export interface IPublicModelEngineConfig { @@ -52,7 +53,7 @@ export interface IPublicModelEngineConfig { * @param fn * @returns */ - onGot(key: string, fn: (data: any) => void): () => void; + onGot(key: string, fn: (data: any) => void): IPublicTypeDisposable; /** * 获取全局 Preference, 用于管理全局浏览器侧用户 Preference,如 Panel 是否钉住 From 319d495d3b7e44ae6aaf947a72ef131c8089303b Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 22 Feb 2023 12:00:12 +0800 Subject: [PATCH 013/469] test: add ut for designer/prop-setAsSlot --- .../tests/document/node/props/prop.test.ts | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 606c7fc08e..787b6bc9b1 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -499,6 +499,57 @@ describe('Prop 类测试', () => { expect(slotProp.purged).toBeTruthy(); slotProp.dispose(); }); + + describe('slotNode-value / setAsSlot', () => { + const editor = new Editor(); + const designer = new Designer({ editor, shellModelFactory }); + const doc = new DocumentModel(designer.project, { + componentName: 'Page', + children: [ + { + id: 'div', + componentName: 'Div', + }, + ], + }); + const div = doc.getNode('div'); + + const slotProp = new Prop(div?.getProps(), { + type: 'JSSlot', + value: { + componentName: 'Slot', + props: { + slotName: "content", + slotTitle: "主内容" + }, + children: [ + { + componentName: 'Button', + } + ] + }, + }); + + expect(slotProp.slotNode?.componentName).toBe('Slot'); + + expect(slotProp.slotNode?.title).toBe('主内容'); + expect(slotProp.slotNode?.getExtraProp('name')?.getValue()).toBe('content'); + + slotProp.export(); + + // Save + expect(slotProp.export()?.value[0].componentName).toBe('Button'); + expect(slotProp.export()?.title).toBe('主内容'); + expect(slotProp.export()?.name).toBe('content'); + + // Render + expect(slotProp.export(IPublicEnumTransformStage.Render)?.value.children[0].componentName).toBe('Button'); + expect(slotProp.export(IPublicEnumTransformStage.Render)?.value.componentName).toBe('Slot'); + + slotProp.purge(); + expect(slotProp.purged).toBeTruthy(); + slotProp.dispose(); + }); }); describe('其他导出函数', () => { From 1f09b639fb8b4f7be897aef2649e1f44f191a20a Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 22 Feb 2023 12:07:42 +0800 Subject: [PATCH 014/469] feat: add reverse api to node-children model --- docs/docs/api/model/node-children.md | 15 +++++++++++++++ .../designer/src/document/node/node-children.ts | 6 ++++++ packages/shell/src/model/node-children.ts | 9 +++++++++ packages/types/src/shell/model/node-children.ts | 6 ++++++ 4 files changed, 36 insertions(+) diff --git a/docs/docs/api/model/node-children.md b/docs/docs/api/model/node-children.md index 10488a7337..219e6bbc18 100644 --- a/docs/docs/api/model/node-children.md +++ b/docs/docs/api/model/node-children.md @@ -156,6 +156,21 @@ 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 diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index d370a797b8..12a9e75ba5 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -54,6 +54,8 @@ export interface INodeChildren extends Omit any, initialValue: any): void; + reverse(): INode[]; + mergeChildren( remover: (node: INode, idx: number) => boolean, adder: (children: INode[]) => IPublicTypeNodeData[] | null, @@ -442,6 +444,10 @@ export class NodeChildren implements INodeChildren { return this.children.reduce(fn, initialValue); } + reverse() { + return this.children.reverse(); + } + mergeChildren( remover: (node: INode, idx: number) => boolean, adder: (children: INode[]) => IPublicTypeNodeData[] | null, diff --git a/packages/shell/src/model/node-children.ts b/packages/shell/src/model/node-children.ts index 0192268bc3..4d1cc0a222 100644 --- a/packages/shell/src/model/node-children.ts +++ b/packages/shell/src/model/node-children.ts @@ -129,6 +129,15 @@ export class NodeChildren implements IPublicModelNodeChildren { }); } + /** + * 类似数组的 reverse + */ + reverse(): IPublicModelNode[] { + return this[nodeChildrenSymbol].reverse().map(d => { + return ShellNode.create(d)!; + }); + } + /** * 类似数组的 map * @param fn diff --git a/packages/types/src/shell/model/node-children.ts b/packages/types/src/shell/model/node-children.ts index d18bf78a36..0379194bf9 100644 --- a/packages/types/src/shell/model/node-children.ts +++ b/packages/types/src/shell/model/node-children.ts @@ -96,6 +96,12 @@ export interface IPublicModelNodeChildren { */ forEach(fn: (node: IPublicModelNode, index: number) => void): void; + /** + * 类似数组的 reverse + * provide the same function with {Array.prototype.reverse} + */ + reverse(): IPublicModelNode[]; + /** * 类似数组的 map * provide the same function with {Array.prototype.map} From 33a4192e2c786a0dae170744c31d15ef3bbe3ced Mon Sep 17 00:00:00 2001 From: liujuping Date: Fri, 24 Feb 2023 14:49:32 +0800 Subject: [PATCH 015/469] fix: fix slot id is automatically generated every time --- packages/designer/src/document/node/props/prop.ts | 2 +- packages/designer/tests/document/node/props/prop.test.ts | 2 ++ packages/react-simulator-renderer/src/renderer-view.tsx | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index f16f24c841..81675aa571 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -401,7 +401,7 @@ export class Prop implements IProp, IPropParent { slotSchema = { componentName: 'Slot', title: value.title || value.props?.slotTitle, - id: data.id, + id: value.id, name: value.name || value.props?.slotName, params: value.params || value.props?.slotParams, children: value.children, diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 787b6bc9b1..932733b1a2 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -518,6 +518,7 @@ describe('Prop 类测试', () => { type: 'JSSlot', value: { componentName: 'Slot', + id: 'node_oclei5rv2e2', props: { slotName: "content", slotTitle: "主内容" @@ -534,6 +535,7 @@ describe('Prop 类测试', () => { expect(slotProp.slotNode?.title).toBe('主内容'); expect(slotProp.slotNode?.getExtraProp('name')?.getValue()).toBe('content'); + expect(slotProp.slotNode?.export()?.id).toBe('node_oclei5rv2e2'); slotProp.export(); diff --git a/packages/react-simulator-renderer/src/renderer-view.tsx b/packages/react-simulator-renderer/src/renderer-view.tsx index 68e66fc020..e8c7ce52e6 100644 --- a/packages/react-simulator-renderer/src/renderer-view.tsx +++ b/packages/react-simulator-renderer/src/renderer-view.tsx @@ -170,7 +170,9 @@ class Renderer extends Component<{ this.startTime = Date.now(); this.schemaChangedSymbol = false; - if (!container.autoRender || isRendererDetached()) return null; + if (!container.autoRender || isRendererDetached()) { + return null; + } const { intl } = createIntl(locale); From b3a29913d2b3f6b26ce572c23b3b26e1ad8bf425 Mon Sep 17 00:00:00 2001 From: eternalsky Date: Mon, 27 Feb 2023 09:53:32 +0800 Subject: [PATCH 016/469] =?UTF-8?q?feat:=20=E7=9B=B8=E5=AF=B9=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E7=94=9F=E6=88=90=E5=8A=A8=E6=80=81=E5=8C=96=20&=20?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E9=83=A8=E5=88=86=E6=8F=92=E4=BB=B6=20ts=20?= =?UTF-8?q?=E5=A3=B0=E6=98=8E=E9=97=AE=E9=A2=98=20(#1618)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: console the expression error * feat: 相对路径生成动态化 * chore: 暂时恢复一些变化,用于更新测试 * chore: 修改错误的 schema * fix: 修复错误的 schema & 更新数据快照 --- modules/code-generator/example-schema.json | 8 ++-- modules/code-generator/example-schema.json5 | 8 ++-- .../src/generator/ProjectBuilder.ts | 3 +- modules/code-generator/src/index.ts | 3 +- .../component/react/containerInitState.ts | 4 +- .../component/react/containerInjectI18n.ts | 4 +- .../component/react/containerInjectUtils.ts | 22 ++-------- .../src/plugins/project/i18n.ts | 3 +- .../src/utils/expressionParser.ts | 6 +-- modules/code-generator/src/utils/index.ts | 2 + .../code-generator/src/utils/pathHelper.ts | 41 +++++++++++++++++++ .../demo-project/src/pages/Home/index.jsx | 2 - .../demo1/expected/demo-project/package.json | 13 ++++-- .../demo-project/src/pages/Test/index.jsx | 14 +++---- .../test-cases/react-app/demo1/schema.json5 | 2 +- .../expected/demo-project/package.json | 13 ++++-- .../demo-project/src/pages/Aaaa/index.jsx | 4 +- .../demo2/expected/demo-project/package.json | 13 ++++-- .../test-cases/react-app/demo2/schema.json5 | 2 +- .../demo3/expected/demo-project/package.json | 13 ++++-- .../demo4/expected/demo-project/package.json | 13 ++++-- .../demo-project/src/pages/Test/index.jsx | 4 +- .../demo5/expected/demo-project/package.json | 13 ++++-- .../expected/demo-project/package.json | 13 ++++-- .../demo-project/src/pages/Test/index.jsx | 14 +++---- .../demo6-literal-condition/schema.json5 | 8 ++-- .../expected/demo-project/package.json | 13 ++++-- .../demo-project/src/pages/Test/index.jsx | 2 + .../expected/demo-project/package.json | 13 ++++-- .../demo-project/src/pages/Example/index.jsx | 4 +- .../expected/demo-project/package.json | 13 ++++-- .../demo-project/src/pages/$/index.jsx | 4 +- .../expected/demo-project/package.json | 13 ++++-- .../demo-project/src/pages/Test/index.jsx | 2 - .../expected/demo-project/package.json | 13 ++++-- .../demo-project/src/pages/Test/index.jsx | 3 -- .../demo1/expected/demo-project/package.json | 13 ++++-- .../__snapshots__/prettier.test.ts.snap | 7 +++- 38 files changed, 231 insertions(+), 114 deletions(-) create mode 100644 modules/code-generator/src/utils/pathHelper.ts diff --git a/modules/code-generator/example-schema.json b/modules/code-generator/example-schema.json index aaf3a3e0d8..304cf2927d 100644 --- a/modules/code-generator/example-schema.json +++ b/modules/code-generator/example-schema.json @@ -71,7 +71,7 @@ }, "lifeCycles": { "componentDidMount": { - "type": "JSExpression", + "type": "JSFunction", "value": "function() { console.log('componentDidMount'); }" } }, @@ -91,7 +91,7 @@ "isSync": true }, "dataHandler": { - "type": "JSExpression", + "type": "JSFunction", "value": "function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}" } }, @@ -105,13 +105,13 @@ "isSync": true }, "dataHandler": { - "type": "JSExpression", + "type": "JSFunction", "value": "function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}" } } ], "dataHandler": { - "type": "JSExpression", + "type": "JSFunction", "value": "function (dataMap) {\n console.info(\"All datasources loaded:\", dataMap);\n}" } }, diff --git a/modules/code-generator/example-schema.json5 b/modules/code-generator/example-schema.json5 index f71096fc41..13fa019b4b 100644 --- a/modules/code-generator/example-schema.json5 +++ b/modules/code-generator/example-schema.json5 @@ -71,7 +71,7 @@ }, lifeCycles: { componentDidMount: { - type: 'JSExpression', + type: 'JSFunction', value: "function() { console.log('componentDidMount'); }", }, }, @@ -91,7 +91,7 @@ isSync: true, }, dataHandler: { - type: 'JSExpression', + type: 'JSFunction', value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}', }, }, @@ -105,13 +105,13 @@ isSync: true, }, dataHandler: { - type: 'JSExpression', + type: 'JSFunction', value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}', }, }, ], dataHandler: { - type: 'JSExpression', + type: 'JSFunction', value: 'function (dataMap) {\n console.info("All datasources loaded:", dataMap);\n}', }, }, diff --git a/modules/code-generator/src/generator/ProjectBuilder.ts b/modules/code-generator/src/generator/ProjectBuilder.ts index 6db81b0d76..f7262777cd 100644 --- a/modules/code-generator/src/generator/ProjectBuilder.ts +++ b/modules/code-generator/src/generator/ProjectBuilder.ts @@ -135,6 +135,7 @@ export class ProjectBuilder implements IProjectBuilder { const builders = this.createModuleBuilders({ extraContextData: { projectRemark: parseResult?.project?.projectRemark, + template: this.template, }, }); // Generator Code module @@ -328,7 +329,7 @@ export class ProjectBuilder implements IProjectBuilder { // template: this.template, inStrictMode: this.inStrictMode, tolerateEvalErrors: true, - evalErrorsHandler: 'console.error(error)', + evalErrorsHandler: '', ...this.extraContextData, ...extraContextData, }, diff --git a/modules/code-generator/src/index.ts b/modules/code-generator/src/index.ts index 7cf861e6f8..742b2e6a8e 100644 --- a/modules/code-generator/src/index.ts +++ b/modules/code-generator/src/index.ts @@ -1,6 +1,6 @@ /** * 低代码引擎的出码模块,负责将编排产出的 Schema 转换成实际可执行的代码。 - * 注意:为了保持 API 的稳定性, 这里所有导出的 API 均要显式命名方式导出 + * 注意:为了保持 API 的稳定性,这里所有导出的 API 均要显式命名方式导出 * (即用 export { xxx } from 'xx' 的方式,不要直接 export * from 'xxx') * 而且所有导出的 API 务必在 tests/public 中编写单元测试 */ @@ -51,6 +51,7 @@ export default { }, plugins: { common: { + /** * 处理 ES Module * @deprecated please use esModule diff --git a/modules/code-generator/src/plugins/component/react/containerInitState.ts b/modules/code-generator/src/plugins/component/react/containerInitState.ts index 5f246e1156..d1dd0d1ddf 100644 --- a/modules/code-generator/src/plugins/component/react/containerInitState.ts +++ b/modules/code-generator/src/plugins/component/react/containerInitState.ts @@ -13,12 +13,12 @@ import { } from '../../../types'; export interface PluginConfig { - fileType: string; + fileType?: string; implementType: 'inConstructor' | 'insMember' | 'hooks'; } const pluginFactory: BuilderComponentPluginFactory = (config?) => { - const cfg: PluginConfig = { + const cfg: PluginConfig & { fileType: string } = { fileType: FileType.JSX, implementType: 'inConstructor', ...config, diff --git a/modules/code-generator/src/plugins/component/react/containerInjectI18n.ts b/modules/code-generator/src/plugins/component/react/containerInjectI18n.ts index da04029c00..aff42af15f 100644 --- a/modules/code-generator/src/plugins/component/react/containerInjectI18n.ts +++ b/modules/code-generator/src/plugins/component/react/containerInjectI18n.ts @@ -11,6 +11,7 @@ import { FileType, ICodeStruct, } from '../../../types'; +import { getSlotRelativePath } from '../../../utils/pathHelper'; export interface PluginConfig { fileType: string; @@ -31,9 +32,8 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => type: ChunkType.STRING, fileType: cfg.fileType, name: COMMON_CHUNK_NAME.InternalDepsImport, - // TODO: 下面这个路径有没有更好的方式来获取?而非写死 content: ` - import * as __$$i18n from '../../i18n'; + import * as __$$i18n from '${getSlotRelativePath({ contextData: next.contextData, from: 'components', to: 'i18n' })}'; `, linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], }); diff --git a/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts b/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts index c5c566e17b..d9eb14f769 100644 --- a/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts +++ b/modules/code-generator/src/plugins/component/react/containerInjectUtils.ts @@ -11,18 +11,18 @@ import { FileType, ICodeStruct, IContainerInfo, - IProjectTemplate, } from '../../../types'; +import { getSlotRelativePath } from '../../../utils/pathHelper'; export interface PluginConfig { - fileType: string; + fileType?: string; /** prefer using class property to define utils */ preferClassProperty?: boolean; } const pluginFactory: BuilderComponentPluginFactory = (config?) => { - const cfg: PluginConfig = { + const cfg: PluginConfig & { fileType: string } = { fileType: FileType.JSX, ...config, }; @@ -36,26 +36,12 @@ const pluginFactory: BuilderComponentPluginFactory = (config?) => next.contextData.useRefApi = true; const useRef = !!ir.analyzeResult?.isUsingRef; - // const isSingleComponent = next.contextData?.projectRemark?.isSingleComponent; - // const template = next.contextData?.template; - - // function getRelativeUtilsPath(template: IProjectTemplate, isSingleComponent: boolean) { - // let relativeUtilsPath = '../../utils'; - // const utilsPath = template.slots.utils.path; - // if (ir.containerType === 'Component') { - // // TODO: isSingleComponent - // relativeUtilsPath = getRelativePath(template.slots.components.path.join('/'), utilsPath.join('/')); - // } - // return relativeUtilsPath; - // } - next.chunks.push({ type: ChunkType.STRING, fileType: cfg.fileType, name: COMMON_CHUNK_NAME.InternalDepsImport, - // TODO: 下面这个路径有没有更好的方式来获取?而非写死 content: ` - import utils${useRef ? ', { RefsManager }' : ''} from '../../utils'; + import utils${useRef ? ', { RefsManager }' : ''} from '${getSlotRelativePath({ contextData: next.contextData, from: 'components', to: 'utils' })}'; `, linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], }); diff --git a/modules/code-generator/src/plugins/project/i18n.ts b/modules/code-generator/src/plugins/project/i18n.ts index d1d32ff32c..ae568f9724 100644 --- a/modules/code-generator/src/plugins/project/i18n.ts +++ b/modules/code-generator/src/plugins/project/i18n.ts @@ -25,8 +25,7 @@ const pluginFactory: BuilderComponentPluginFactory = () => { content: ` const i18nConfig = ${i18nStr}; - // let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN'; - let locale = 'zh-CN'; + let locale = typeof navigator === 'object' && typeof navigator.language === 'string' ? navigator.language : 'zh-CN'; const getLocale = () => locale; diff --git a/modules/code-generator/src/utils/expressionParser.ts b/modules/code-generator/src/utils/expressionParser.ts index fc1fe41953..cbc950bbc8 100644 --- a/modules/code-generator/src/utils/expressionParser.ts +++ b/modules/code-generator/src/utils/expressionParser.ts @@ -271,7 +271,7 @@ export function parseExpressionConvertThis2Context( const localVariablesSet = new Set(localVariables); - let thisScopeLevel = -1; + let thisScopeLevel = CROSS_THIS_SCOPE_TYPE_NODE[exprAst.type] ? -1 : 0; traverse(fileAst, { enter(path) { if (CROSS_THIS_SCOPE_TYPE_NODE[path.node.type]) { @@ -303,7 +303,7 @@ export function parseExpressionConvertThis2Context( } // 替换 this (只在顶层替换) - if (thisScopeLevel === 0) { + if (thisScopeLevel <= 0) { obj.replaceWith(t.identifier(contextName)); } }, @@ -317,7 +317,7 @@ export function parseExpressionConvertThis2Context( return; } - if (thisScopeLevel === 0) { + if (thisScopeLevel <= 0) { path.replaceWith(t.identifier(contextName)); } }, diff --git a/modules/code-generator/src/utils/index.ts b/modules/code-generator/src/utils/index.ts index cac63d415c..8c41d678ff 100644 --- a/modules/code-generator/src/utils/index.ts +++ b/modules/code-generator/src/utils/index.ts @@ -12,6 +12,7 @@ import * as version from './version'; import * as scope from './Scope'; import * as expressionParser from './expressionParser'; import * as dataSource from './dataSource'; +import * as pathHelper from './pathHelper'; export { common, @@ -27,4 +28,5 @@ export { scope, expressionParser, dataSource, + pathHelper, }; diff --git a/modules/code-generator/src/utils/pathHelper.ts b/modules/code-generator/src/utils/pathHelper.ts new file mode 100644 index 0000000000..8440089d89 --- /dev/null +++ b/modules/code-generator/src/utils/pathHelper.ts @@ -0,0 +1,41 @@ +import { IContextData } from '../types'; + +function relativePath(from: string[], to: string[]): string[] { + const length = Math.min(from.length, to.length); + let samePartsLength = length; + for (let i = 0; i < length; i++) { + if (from[i] !== to[i]) { + samePartsLength = i; + break; + } + } + if (samePartsLength === 0) { + return to; + } + let outputParts = []; + for (let i = samePartsLength; i < from.length; i++) { + outputParts.push('..'); + } + outputParts = [...outputParts, ...to.slice(samePartsLength)]; + if (outputParts[0] !== '..') { + outputParts.unshift('.'); + } + return outputParts; +} + +export function getSlotRelativePath(options: { + contextData: IContextData; + from: string; + to: string; +}) { + const { contextData, from, to } = options; + const isSingleComponent = contextData?.extraContextData?.projectRemark?.isSingleComponent; + const template = contextData?.extraContextData?.template; + let toPath = template.slots[to].path; + toPath = [...toPath, template.slots[to].fileName!]; + let fromPath = template.slots[from].path; + if (!isSingleComponent && ['components', 'pages'].indexOf(from) !== -1) { + fromPath = [...fromPath, 'pageName']; + } + return relativePath(fromPath, toPath).join('/'); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/pages/Home/index.jsx b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/pages/Home/index.jsx index 7bfda59caf..06e39454d0 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/pages/Home/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/pages/Home/index.jsx @@ -253,7 +253,6 @@ class Home$$Page extends Component { if (!response.success) { throw new Error(response.message); } - return response.data; }, isInit: true, @@ -280,7 +279,6 @@ class Home$$Page extends Component { if (!response.success) { throw new Error(response.message); } - return response.data.result; }, isInit: true, diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/package.json index 36eaf12f26..d18604922d 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/package.json @@ -31,9 +31,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/pages/Test/index.jsx index c8db61db74..070020b746 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/pages/Test/index.jsx @@ -71,10 +71,10 @@ class Test$$Page extends React.Component { type: 'urlParams', isInit: function () { return undefined; - }, + }.bind(_this), options: function () { return undefined; - }, + }.bind(_this), }, { id: 'user', @@ -85,17 +85,16 @@ class Test$$Page extends React.Component { uri: 'https://shs.xxx.com/mock/1458/demo/user', isSync: true, }; - }, + }.bind(_this), dataHandler: function (response) { if (!response.data.success) { throw new Error(response.data.message); } - return response.data.data; }, isInit: function () { return undefined; - }, + }.bind(_this), }, { id: 'orders', @@ -106,17 +105,16 @@ class Test$$Page extends React.Component { uri: 'https://shs.xxx.com/mock/1458/demo/orders', isSync: true, }; - }, + }.bind(_this), dataHandler: function (response) { if (!response.data.success) { throw new Error(response.data.message); } - return response.data.data.result; }, isInit: function () { return undefined; - }, + }.bind(_this), }, ], dataHandler: function (dataMap) { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/schema.json5 index 5a1cfc4d9a..76c52fb5e8 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/schema.json5 +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/schema.json5 @@ -71,7 +71,7 @@ }, "lifeCycles": { "componentDidMount": { - "type": "JSExpression", + "type": "JSFunction", "value": "function() { console.log('componentDidMount'); }" } }, diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/package.json index 8ce6c92801..d83d45e324 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/package.json @@ -34,9 +34,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx index a1b0524249..2945a9d8f5 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx @@ -67,10 +67,10 @@ class Aaaa$$Page extends React.Component { return { uri: '', }; - }, + }.bind(_this), isInit: function () { return undefined; - }, + }.bind(_this), }, ], }; diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/package.json index 5fdcfad855..03820c1574 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/package.json @@ -29,9 +29,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/schema.json5 index 8678b4e925..2228212067 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/schema.json5 +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/schema.json5 @@ -71,7 +71,7 @@ }, "lifeCycles": { "componentDidMount": { - "type": "JSExpression", + "type": "JSFunction", "value": "function() { console.log('componentDidMount'); }" } }, diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/package.json index 5fdcfad855..03820c1574 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/package.json @@ -29,9 +29,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/package.json index b91e8870f1..6190fc0238 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/package.json @@ -31,9 +31,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/pages/Test/index.jsx index 9058b0aa70..6400d7445b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/pages/Test/index.jsx @@ -76,7 +76,7 @@ class Test$$Page extends React.Component { type: 'fetch', isInit: function () { return true; - }, + }.bind(_this), options: function () { return { params: {}, @@ -86,7 +86,7 @@ class Test$$Page extends React.Component { headers: {}, uri: 'https://mocks.xxx.com/mock/jjpin/user/list', }; - }, + }.bind(_this), id: 'users', }, ], diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/package.json index 2a2915e545..b31603b3a3 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/package.json @@ -32,9 +32,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/package.json index 36eaf12f26..d18604922d 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/package.json @@ -31,9 +31,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx index 7a5c6fdfac..c27cce1532 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx @@ -71,10 +71,10 @@ class Test$$Page extends React.Component { type: 'urlParams', isInit: function () { return undefined; - }, + }.bind(_this), options: function () { return undefined; - }, + }.bind(_this), }, { id: 'user', @@ -85,17 +85,16 @@ class Test$$Page extends React.Component { uri: 'https://shs.xxx.com/mock/1458/demo/user', isSync: true, }; - }, + }.bind(_this), dataHandler: function (response) { if (!response.data.success) { throw new Error(response.data.message); } - return response.data.data; }, isInit: function () { return undefined; - }, + }.bind(_this), }, { id: 'orders', @@ -106,17 +105,16 @@ class Test$$Page extends React.Component { uri: 'https://shs.xxx.com/mock/1458/demo/orders', isSync: true, }; - }, + }.bind(_this), dataHandler: function (response) { if (!response.data.success) { throw new Error(response.data.message); } - return response.data.data.result; }, isInit: function () { return undefined; - }, + }.bind(_this), }, ], dataHandler: function (dataMap) { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/schema.json5 index 6d3a601373..5b6776c1ee 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/schema.json5 +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/schema.json5 @@ -71,7 +71,7 @@ }, lifeCycles: { componentDidMount: { - type: 'JSExpression', + type: 'JSFunction', value: "function() { console.log('componentDidMount'); }", }, }, @@ -91,7 +91,7 @@ isSync: true, }, dataHandler: { - type: 'JSExpression', + type: 'JSFunction', value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}', }, }, @@ -105,13 +105,13 @@ isSync: true, }, dataHandler: { - type: 'JSExpression', + type: 'JSFunction', value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}', }, }, ], dataHandler: { - type: 'JSExpression', + type: 'JSFunction', value: 'function (dataMap) {\n console.info("All datasources loaded:", dataMap);\n}', }, }, diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/package.json index 4ac494ebe0..84141875ec 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/package.json @@ -31,9 +31,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.jsx index e9cc592f14..9e93a3ff6f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.jsx @@ -151,6 +151,7 @@ class Test$$Page extends React.Component { onOkModifyDialogThird() { //第三步 修改 对话框 确定 + this.setState({ currentStep: 0, isModifyDialogVisible: false, @@ -159,6 +160,7 @@ class Test$$Page extends React.Component { onCancelModifyDialogThird() { //第三步 修改 对话框 取消 + this.setState({ isModifyDialogVisible: false, }); diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/package.json index 10269e8fd7..91da69eef2 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/package.json @@ -30,9 +30,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.jsx index d1046bd0d9..9a661ad753 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.jsx @@ -63,10 +63,10 @@ class Example$$Page extends React.Component { return { uri: 'https://api.example.com/user/list', }; - }, + }.bind(_this), isInit: function () { return undefined; - }, + }.bind(_this), }, ], }; diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/package.json index 1dac338e3f..939adb7791 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/package.json @@ -30,9 +30,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx index 9226280c7c..1f2bf90418 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx @@ -59,14 +59,14 @@ class $$Page extends React.Component { id: 'todos', isInit: function () { return true; - }, + }.bind(_this), type: 'jsonp', options: function () { return { method: 'GET', uri: 'https://a0ee9135-6a7f-4c0f-a215-f0f247ad907d.mock.pstmn.io', }; - }, + }.bind(_this), dataHandler: function dataHandler(data) { return data.data; }, diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/package.json index 2ab1720fc7..41f379d7a0 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/package.json @@ -32,9 +32,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.jsx index aa14cb9163..922ad47ad8 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.jsx @@ -65,7 +65,6 @@ class Test$$Page extends React.Component { }; this.__jp__init(); - this.statusDesc = { 0: '失败', 1: '成功', @@ -163,7 +162,6 @@ class Test$$Page extends React.Component { if (!item) { return '暂无结果'; } - const { channel, plat, version, status } = item; return [channel, plat, version, status].join('-'); } diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/package.json index a3a7ba8abb..2b45dfc53f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/package.json @@ -32,9 +32,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.jsx index d40458cf81..5630342f37 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.jsx @@ -67,7 +67,6 @@ class Test$$Page extends React.Component { }; this.__jp__init(); - this.statusDesc = { 0: '失败', 1: '成功', @@ -202,12 +201,10 @@ class Test$$Page extends React.Component { componentDidMount() { this.$ds.resolve('PROJECTS'); - if (this.userTimeout) { clearTimeout(this.userTimeout); this.userTimeout = null; } - if (this.projectTimeout) { clearTimeout(this.projectTimeout); this.projectTimeout = null; diff --git a/modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/package.json index ebb17b143d..d32b684dcf 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/react-module/demo1/expected/demo-project/package.json @@ -25,9 +25,16 @@ "eslint": "eslint --cache --ext .js,.jsx ./", "stylelint": "stylelint ./**/*.scss" }, - "ideMode": { "name": "ice-react" }, - "iceworks": { "type": "react", "adapter": "adapter-react-v3" }, - "engines": { "node": ">=8.0.0" }, + "ideMode": { + "name": "ice-react" + }, + "iceworks": { + "type": "react", + "adapter": "adapter-react-v3" + }, + "engines": { + "node": ">=8.0.0" + }, "repository": { "type": "git", "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" diff --git a/modules/code-generator/tests/postprocessor/__snapshots__/prettier.test.ts.snap b/modules/code-generator/tests/postprocessor/__snapshots__/prettier.test.ts.snap index 37d8d786b4..db47e1829f 100644 --- a/modules/code-generator/tests/postprocessor/__snapshots__/prettier.test.ts.snap +++ b/modules/code-generator/tests/postprocessor/__snapshots__/prettier.test.ts.snap @@ -19,7 +19,12 @@ export function App() { `; exports[`postprocessor/prettier should works for json file 1`] = ` -"{ \\"components\\": [\\"Button\\", \\"Block\\"] } +"{ + \\"components\\": [ + \\"Button\\", + \\"Block\\" + ] +} " `; From 65a040390fe516bfef154cdb8c35fbf1a30f63e7 Mon Sep 17 00:00:00 2001 From: za-liyong002 Date: Mon, 27 Feb 2023 23:48:09 +0800 Subject: [PATCH 017/469] =?UTF-8?q?fix:=E4=BF=AE=E6=94=B9config.onGot=20?= =?UTF-8?q?=E5=92=8C=20editor.onGot=20=E6=96=B9=E6=B3=95=E4=B8=8E=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E4=B8=8D=E4=B8=80=E8=87=B4=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/editor-core/src/config.ts | 10 ++++------ packages/editor-core/src/editor.ts | 12 +++++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/editor-core/src/config.ts b/packages/editor-core/src/config.ts index 12ef865ec5..ef889e7273 100644 --- a/packages/editor-core/src/config.ts +++ b/packages/editor-core/src/config.ts @@ -288,13 +288,11 @@ export class EngineConfig implements IEngineConfig { const val = this.config?.[key]; if (val !== undefined) { fn(val); - return () => {}; - } else { - this.setWait(key, fn); - return () => { - this.delWait(key, fn); - }; } + this.setWait(key, fn); + return () => { + this.delWait(key, fn); + }; } notifyGot(key: string): void { diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index 5fa6bb894d..062b7e6699 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -190,13 +190,11 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor const x = this.context.get(keyOrType); if (x !== undefined) { fn(x); - return () => { }; - } else { - this.setWait(keyOrType, fn); - return () => { - this.delWait(keyOrType, fn); - }; } + this.setWait(keyOrType, fn); + return () => { + this.delWait(keyOrType, fn); + }; } register(data: any, key?: IPublicTypeEditorValueKey): void { @@ -328,4 +326,4 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor } } -export const commonEvent = new EventBus(new EventEmitter()); \ No newline at end of file +export const commonEvent = new EventBus(new EventEmitter()); From d8014c9d1ab310317ad6fafb8fbba2c475d0491d Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 27 Feb 2023 19:59:54 +0800 Subject: [PATCH 018/469] fix: fix some ts error --- .eslintrc.js | 2 +- packages/designer/src/component-meta.ts | 3 +- packages/designer/src/designer/designer.ts | 11 +- packages/designer/src/designer/detecting.ts | 7 +- packages/designer/src/designer/location.ts | 9 +- .../src/designer/setting/setting-top-entry.ts | 20 +- .../designer/src/document/document-model.ts | 183 +++++++++++------- .../src/document/node/modal-nodes-manager.ts | 10 +- .../src/document/node/node-children.ts | 41 ++-- packages/designer/src/document/node/node.ts | 129 ++++++++---- .../designer/src/document/node/props/prop.ts | 8 +- .../designer/src/document/node/props/props.ts | 16 +- packages/designer/src/document/selection.ts | 20 +- packages/designer/src/project/project.ts | 26 ++- packages/designer/src/simulator.ts | 12 +- packages/shell/src/model/document-model.ts | 5 +- packages/shell/src/model/node.ts | 6 +- packages/shell/src/model/selection.ts | 4 +- .../types/src/shell/model/component-meta.ts | 10 +- packages/types/src/shell/model/detecting.ts | 6 +- .../types/src/shell/model/document-model.ts | 59 +++--- .../src/shell/model/modal-nodes-manager.ts | 10 +- .../types/src/shell/model/node-children.ts | 40 ++-- packages/types/src/shell/model/node.ts | 44 +++-- packages/types/src/shell/model/props.ts | 12 +- packages/types/src/shell/model/selection.ts | 10 +- .../types/src/shell/type/drag-node-object.ts | 4 +- packages/types/src/shell/type/field-config.ts | 2 +- .../types/src/shell/type/field-extra-props.ts | 4 +- packages/types/src/shell/type/metadata.ts | 22 +-- .../types/src/shell/type/setter-config.ts | 11 ++ .../check-types/is-drag-node-data-object.ts | 4 +- .../src/check-types/is-drag-node-object.ts | 4 +- packages/utils/src/check-types/is-node.ts | 4 +- 34 files changed, 455 insertions(+), 303 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 1ec3834e6a..f3ebedbbef 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -20,7 +20,7 @@ module.exports = { 'no-await-in-loop': 0, 'no-plusplus': 0, '@typescript-eslint/no-parameter-properties': 0, - '@typescript-eslint/no-unused-vars': 1, + 'no-restricted-exports': ['error'], 'no-multi-assign': 1, 'no-dupe-class-members': 1, 'react/no-deprecated': 1, diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index c361b21c9b..2691a89717 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -56,7 +56,8 @@ export function buildFilter(rule?: string | string[] | RegExp | IPublicTypeNesti return (testNode: Node | IPublicTypeNodeSchema) => list.includes(testNode.componentName); } -export interface IComponentMeta extends IPublicModelComponentMeta { +export interface IComponentMeta extends IPublicModelComponentMeta { + prototype?: any; } export class ComponentMeta implements IComponentMeta { diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index c39e439aa3..d40082d82f 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -30,7 +30,7 @@ import { ActiveTracker, IActiveTracker } from './active-tracker'; import { Detecting } from './detecting'; import { DropLocation } from './location'; import { OffsetObserver, createOffsetObserver } from './offset-observer'; -import { SettingTopEntry } from './setting'; +import { ISettingTopEntry, SettingTopEntry } from './setting'; import { BemToolsManager } from '../builtin-simulator/bem-tools/manager'; import { ComponentActions } from '../component-actions'; @@ -61,6 +61,7 @@ export interface DesignerProps { } export interface IDesigner { + readonly shellModelFactory: IShellModelFactory; get dragon(): IPublicModelDragon; @@ -91,6 +92,12 @@ export interface IDesigner { getComponentMetasMap(): Map; addPropsReducer(reducer: IPublicTypePropsTransducer, stage: IPublicEnumTransformStage): void; + + postEvent(event: string, ...args: any[]): void; + + transformProps(props: IPublicTypeCompositeObject | IPublicTypePropsList, node: Node, stage: IPublicEnumTransformStage): IPublicTypeCompositeObject | IPublicTypePropsList; + + createSettingEntry(nodes: INode[]): ISettingTopEntry; } export class Designer implements IDesigner { @@ -331,7 +338,7 @@ export class Designer implements IDesigner { this.oobxList.forEach((item) => item.compute()); } - createSettingEntry(nodes: Node[]) { + createSettingEntry(nodes: INode[]): ISettingTopEntry { return new SettingTopEntry(this.editor, nodes); } diff --git a/packages/designer/src/designer/detecting.ts b/packages/designer/src/designer/detecting.ts index 3a6082d5ca..568639c372 100644 --- a/packages/designer/src/designer/detecting.ts +++ b/packages/designer/src/designer/detecting.ts @@ -4,8 +4,11 @@ import { IDocumentModel } from '../document/document-model'; import { INode } from '../document/node/node'; const DETECTING_CHANGE_EVENT = 'detectingChange'; -export interface IDetecting extends Omit< IPublicModelDetecting, 'capture' | 'release' | 'leave' > { - +export interface IDetecting extends Omit< IPublicModelDetecting, + 'capture' | + 'release' | + 'leave' +> { capture(node: INode | null): void; release(node: INode | null): void; diff --git a/packages/designer/src/designer/location.ts b/packages/designer/src/designer/location.ts index 08c168091c..ccf26e325a 100644 --- a/packages/designer/src/designer/location.ts +++ b/packages/designer/src/designer/location.ts @@ -1,7 +1,6 @@ -import { INode } from '../document'; +import { IDocumentModel, INode } from '../document'; import { ILocateEvent } from './dragon'; import { - IPublicModelDocumentModel, IPublicModelDropLocation, IPublicTypeLocationDetailType, IPublicTypeRect, @@ -105,7 +104,7 @@ export interface IDropLocation extends Omit< IPublicModelDropLocation, 'target' get target(): INode; - get document(): IPublicModelDocumentModel; + get document(): IDocumentModel | null; clone(event: IPublicModelLocateEvent): IDropLocation; } @@ -119,7 +118,7 @@ export class DropLocation implements IDropLocation { readonly source: string; - get document(): IPublicModelDocumentModel { + get document(): IDocumentModel | null { return this.target.document; } @@ -159,7 +158,7 @@ export class DropLocation implements IDropLocation { if (this.detail.index <= 0) { return null; } - return this.target.children.get(this.detail.index - 1); + return this.target.children?.get(this.detail.index - 1); } return (this.detail as any)?.near?.node; } diff --git a/packages/designer/src/designer/setting/setting-top-entry.ts b/packages/designer/src/designer/setting/setting-top-entry.ts index 16a80dbc4f..1c36f8e1bc 100644 --- a/packages/designer/src/designer/setting/setting-top-entry.ts +++ b/packages/designer/src/designer/setting/setting-top-entry.ts @@ -4,19 +4,22 @@ import { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor import { SettingEntry } from './setting-entry'; import { SettingField } from './setting-field'; import { SettingPropEntry } from './setting-prop-entry'; -import { Node } from '../../document'; +import { INode } from '../../document'; import { ComponentMeta } from '../../component-meta'; -import { Designer } from '../designer'; +import { IDesigner } from '../designer'; import { Setters } from '@alilc/lowcode-shell'; -function generateSessionId(nodes: Node[]) { +function generateSessionId(nodes: INode[]) { return nodes .map((node) => node.id) .sort() .join(','); } -export class SettingTopEntry implements SettingEntry { +export interface ISettingTopEntry extends SettingEntry { +} + +export class SettingTopEntry implements ISettingTopEntry { private emitter: IEventBus = createModuleEventBus('SettingTopEntry'); private _items: Array = []; @@ -68,21 +71,21 @@ export class SettingTopEntry implements SettingEntry { readonly id: string; - readonly first: Node; + readonly first: INode; - readonly designer: Designer; + readonly designer: IDesigner | undefined; readonly setters: Setters; disposeFunctions: any[] = []; - constructor(readonly editor: IPublicModelEditor, readonly nodes: Node[]) { + constructor(readonly editor: IPublicModelEditor, readonly nodes: INode[]) { if (!Array.isArray(nodes) || nodes.length < 1) { throw new ReferenceError('nodes should not be empty'); } this.id = generateSessionId(nodes); this.first = nodes[0]; - this.designer = this.first.document.designer; + this.designer = this.first.document?.designer; this.setters = editor.get('setters') as Setters; // setups @@ -229,7 +232,6 @@ export class SettingTopEntry implements SettingEntry { this.disposeFunctions = []; } - getProp(propName: string | number) { return this.get(propName); } diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 9600e80082..63fe094db7 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -1,4 +1,13 @@ -import { makeObservable, obx, engineConfig, action, runWithGlobalEventOff, wrapWithEventSwitch, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core'; +import { + makeObservable, + obx, + engineConfig, + action, + runWithGlobalEventOff, + wrapWithEventSwitch, + createModuleEventBus, + IEventBus, +} from '@alilc/lowcode-editor-core'; import { IPublicTypeNodeData, IPublicTypeNodeSchema, @@ -8,20 +17,32 @@ import { IPublicTypeDragNodeObject, IPublicTypeDragNodeDataObject, IPublicModelDocumentModel, - IPublicModelHistory, - IPublicModelNode, IPublicEnumTransformStage, IPublicTypeOnChangeOptions, + IPublicTypeDisposable, } from '@alilc/lowcode-types'; +import { + IDropLocation, +} from '@alilc/lowcode-designer'; +import { + uniqueId, + isPlainObject, + compatStage, + isJSExpression, + isDOMText, + isNodeSchema, + isDragNodeObject, + isDragNodeDataObject, + isNode, +} from '@alilc/lowcode-utils'; import { IProject, Project } from '../project'; import { ISimulatorHost } from '../simulator'; -import { ComponentMeta } from '../component-meta'; -import { IDropLocation, Designer, IHistory } from '../designer'; -import { Node, insertChildren, insertChild, RootNode, INode } from './node/node'; +import { IComponentMeta } from '../component-meta'; +import { IDesigner, IHistory } from '../designer'; +import { insertChildren, insertChild, RootNode, INode } from './node/node'; import { Selection, ISelection } from './selection'; import { History } from './history'; -import { IModalNodesManager, ModalNodesManager } from './node'; -import { uniqueId, isPlainObject, compatStage, isJSExpression, isDOMText, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isNode } from '@alilc/lowcode-utils'; +import { IModalNodesManager, ModalNodesManager, Node } from './node'; import { EDITOR_EVENT } from '../types'; export type GetDataType = T extends undefined @@ -32,21 +53,39 @@ export type GetDataType = T extends undefined : any : T; -export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'selection' | 'checkNesting' > { +export interface IDocumentModel extends Omit< IPublicModelDocumentModel< + ISelection, + IHistory, + INode | RootNode, + IDropLocation, + IModalNodesManager, + IProject +>, + 'detecting' | + 'checkNesting' | + 'getNodeById' | + // 以下属性在内部的 document 中不存在 + 'exportSchema' | + 'importSchema' | + 'onAddNode' | + 'onRemoveNode' | + 'onChangeDetecting' | + 'onChangeSelection' | + 'onMountNode' | + 'onChangeNodeProp' | + 'onImportSchema' | + 'isDetectingNode' | + 'onFocusNodeChanged' | + 'onDropLocationChanged' +> { + + readonly designer: IDesigner; - readonly designer: Designer; - - /** - * 选区控制 - */ - readonly selection: ISelection; + get rootNode(): INode | null; - readonly project: IProject; + get simulator(): ISimulatorHost | null; - /** - * 模态节点管理 - */ - readonly modalNodesManager: IModalNodesManager; + get active(): boolean; /** * 根据 id 获取节点 @@ -55,16 +94,26 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'select getHistory(): IHistory; - get focusNode(): INode | null; - - get rootNode(): INode | null; - checkNesting( dropTarget: INode, dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject, ): boolean; getNodeCount(): number; + + nextId(possibleId: string | undefined): string; + + import(schema: IPublicTypeRootSchema, checkId?: boolean): void; + + export(stage: IPublicEnumTransformStage): IPublicTypeRootSchema | undefined; + + onNodeCreate(func: (node: INode) => void): IPublicTypeDisposable; + + onNodeDestroy(func: (node: INode) => void): IPublicTypeDisposable; + + onChangeNodeVisible(fn: (node: INode, visible: boolean) => void): IPublicTypeDisposable; + + addWillPurge(node: INode): void; } export class DocumentModel implements IDocumentModel { @@ -86,20 +135,20 @@ export class DocumentModel implements IDocumentModel { /** * 操作记录控制 */ - readonly history: IPublicModelHistory; + readonly history: IHistory; /** * 模态节点管理 */ - readonly modalNodesManager: IModalNodesManager; + modalNodesManager: IModalNodesManager; - private _nodesMap = new Map(); + private _nodesMap = new Map(); readonly project: IProject; - readonly designer: Designer; + readonly designer: IDesigner; - @obx.shallow private nodes = new Set(); + @obx.shallow private nodes = new Set(); private seqId = 0; @@ -119,7 +168,7 @@ export class DocumentModel implements IDocumentModel { return this.project.simulator; } - get nodesMap(): Map { + get nodesMap(): Map { return this._nodesMap; } @@ -131,7 +180,7 @@ export class DocumentModel implements IDocumentModel { this.rootNode?.getExtraProp('fileName', true)?.setValue(fileName); } - get focusNode(): INode { + get focusNode(): INode | null { if (this._drillDownNode) { return this._drillDownNode; } @@ -142,7 +191,7 @@ export class DocumentModel implements IDocumentModel { return this.rootNode; } - @obx.ref private _drillDownNode: Node | null = null; + @obx.ref private _drillDownNode: INode | null = null; private _modalNode?: INode; @@ -150,7 +199,7 @@ export class DocumentModel implements IDocumentModel { private inited = false; - @obx.shallow private willPurgeSpace: Node[] = []; + @obx.shallow private willPurgeSpace: INode[] = []; get modalNode() { return this._modalNode; @@ -160,7 +209,7 @@ export class DocumentModel implements IDocumentModel { return this.modalNode || this.focusNode; } - @obx.shallow private activeNodes?: Node[]; + @obx.shallow private activeNodes?: INode[]; @obx.ref private _dropLocation: IDropLocation | null = null; @@ -236,7 +285,7 @@ export class DocumentModel implements IDocumentModel { // 兼容 vision this.id = project.getSchema()?.id || this.id; - this.rootNode = this.createNode( + this.rootNode = this.createNode( schema || { componentName: 'Page', id: 'root', @@ -257,11 +306,11 @@ export class DocumentModel implements IDocumentModel { this.inited = true; } - drillDown(node: Node | null) { + drillDown(node: INode | null) { this._drillDownNode = node; } - onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): () => void { + onChangeNodeVisible(fn: (node: INode, visible: boolean) => void): IPublicTypeDisposable { this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_CHILDREN_CHANGE, fn); return () => { @@ -269,7 +318,7 @@ export class DocumentModel implements IDocumentModel { }; } - onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): () => void { + onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): IPublicTypeDisposable { this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_VISIBLE_CHANGE, fn); return () => { @@ -277,11 +326,11 @@ export class DocumentModel implements IDocumentModel { }; } - addWillPurge(node: Node) { + addWillPurge(node: INode) { this.willPurgeSpace.push(node); } - removeWillPurge(node: Node) { + removeWillPurge(node: INode) { const i = this.willPurgeSpace.indexOf(node); if (i > -1) { this.willPurgeSpace.splice(i, 1); @@ -295,7 +344,7 @@ export class DocumentModel implements IDocumentModel { /** * 生成唯一 id */ - nextId(possibleId: string | undefined) { + nextId(possibleId: string | undefined): string { let id = possibleId; while (!id || this.nodesMap.get(id)) { id = `node_${(String(this.id).slice(-10) + (++this.seqId).toString(36)).toLocaleLowerCase()}`; @@ -330,7 +379,7 @@ export class DocumentModel implements IDocumentModel { * 根据 schema 创建一个节点 */ @action - createNode(data: GetDataType, checkId: boolean = true): T { + createNode(data: GetDataType, checkId: boolean = true): T { let schema: any; if (isDOMText(data) || isJSExpression(data)) { schema = { @@ -341,7 +390,7 @@ export class DocumentModel implements IDocumentModel { schema = data; } - let node: Node | null = null; + let node: INode | null = null; if (this.hasNode(schema?.id)) { schema.id = null; } @@ -373,30 +422,30 @@ export class DocumentModel implements IDocumentModel { return node as any; } - public destroyNode(node: Node) { + public destroyNode(node: INode) { this.emitter.emit('nodedestroy', node); } /** * 插入一个节点 */ - insertNode(parent: INode, thing: Node | IPublicTypeNodeData, at?: number | null, copy?: boolean): Node { + insertNode(parent: INode, thing: INode | IPublicTypeNodeData, at?: number | null, copy?: boolean): INode { return insertChild(parent, thing, at, copy); } /** * 插入多个节点 */ - insertNodes(parent: INode, thing: Node[] | IPublicTypeNodeData[], at?: number | null, copy?: boolean) { + insertNodes(parent: INode, thing: INode[] | IPublicTypeNodeData[], at?: number | null, copy?: boolean) { return insertChildren(parent, thing, at, copy); } /** * 移除一个节点 */ - removeNode(idOrNode: string | Node) { + removeNode(idOrNode: string | INode) { let id: string; - let node: Node | null; + let node: INode | null; if (typeof idOrNode === 'string') { id = idOrNode; node = this.getNode(id); @@ -413,14 +462,14 @@ export class DocumentModel implements IDocumentModel { /** * 内部方法,请勿调用 */ - internalRemoveAndPurgeNode(node: Node, useMutator = false) { + internalRemoveAndPurgeNode(node: INode, useMutator = false) { if (!this.nodes.has(node)) { return; } node.remove(useMutator); } - unlinkNode(node: Node) { + unlinkNode(node: INode) { this.nodes.delete(node); this._nodesMap.delete(node.id); } @@ -428,7 +477,7 @@ export class DocumentModel implements IDocumentModel { /** * 包裹当前选区中的节点 */ - wrapWith(schema: IPublicTypeNodeSchema): Node | null { + wrapWith(schema: IPublicTypeNodeSchema): INode | null { const nodes = this.selection.getTopNodes(); if (nodes.length < 1) { return null; @@ -465,17 +514,17 @@ export class DocumentModel implements IDocumentModel { }); } - export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Serilize) { + export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Serilize): IPublicTypeRootSchema | undefined { stage = compatStage(stage); // 置顶只作用于 Page 的第一级子节点,目前还用不到里层的置顶;如果后面有需要可以考虑将这段写到 node-children 中的 export - const currentSchema = this.rootNode?.export(stage); - if (Array.isArray(currentSchema?.children) && currentSchema?.children.length > 0) { - const FixedTopNodeIndex = currentSchema.children + const currentSchema = this.rootNode?.export(stage); + if (Array.isArray(currentSchema?.children) && currentSchema?.children?.length && currentSchema?.children?.length > 0) { + const FixedTopNodeIndex = currentSchema?.children .filter(i => isPlainObject(i)) .findIndex((i => (i as IPublicTypeNodeSchema).props?.__isTopFixed__)); if (FixedTopNodeIndex > 0) { - const FixedTopNode = currentSchema.children.splice(FixedTopNodeIndex, 1); - currentSchema.children.unshift(FixedTopNode[0]); + const FixedTopNode = currentSchema?.children.splice(FixedTopNodeIndex, 1); + currentSchema?.children.unshift(FixedTopNode[0]); } } return currentSchema; @@ -504,7 +553,7 @@ export class DocumentModel implements IDocumentModel { return this.simulator!.getComponent(componentName); } - getComponentMeta(componentName: string): ComponentMeta { + getComponentMeta(componentName: string): IComponentMeta { return this.designer.getComponentMeta( componentName, () => this.simulator?.generateComponentMetadata(componentName) || null, @@ -579,10 +628,10 @@ export class DocumentModel implements IDocumentModel { dropTarget: INode, dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject, ): boolean { - let items: Array; + let items: Array; if (isDragNodeDataObject(dragObject)) { items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data]; - } else if (isDragNodeObject(dragObject)) { + } else if (isDragNodeObject(dragObject)) { items = dragObject.nodes; } else if (isNode(dragObject) || isNodeSchema(dragObject)) { items = [dragObject]; @@ -599,11 +648,13 @@ export class DocumentModel implements IDocumentModel { * Use checkNesting method instead. */ checkDropTarget(dropTarget: INode, dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject): boolean { - let items: Array; + let items: Array; if (isDragNodeDataObject(dragObject)) { items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data]; - } else { + } else if (isDragNodeObject(dragObject)) { items = dragObject.nodes; + } else { + return false; } return items.every((item) => this.checkNestingUp(dropTarget, item)); } @@ -611,7 +662,7 @@ export class DocumentModel implements IDocumentModel { /** * 检查对象对父级的要求,涉及配置 parentWhitelist */ - checkNestingUp(parent: INode, obj: IPublicTypeNodeSchema | Node): boolean { + checkNestingUp(parent: INode, obj: IPublicTypeNodeSchema | INode): boolean { if (isNode(obj) || isNodeSchema(obj)) { const config = isNode(obj) ? obj.componentMeta : this.getComponentMeta(obj.componentName); if (config) { @@ -625,7 +676,7 @@ export class DocumentModel implements IDocumentModel { /** * 检查投放位置对子级的要求,涉及配置 childWhitelist */ - checkNestingDown(parent: INode, obj: IPublicTypeNodeSchema | Node): boolean { + checkNestingDown(parent: INode, obj: IPublicTypeNodeSchema | INode): boolean { const config = parent.componentMeta; return config.checkNestingDown(parent, obj); } @@ -666,7 +717,9 @@ export class DocumentModel implements IDocumentModel { */ /* istanbul ignore next */ exportAddonData() { - const addons = {}; + const addons: { + [key: string]: any; + } = {}; this._addons.forEach((addon) => { const data = addon.exportData(); if (data === null) { diff --git a/packages/designer/src/document/node/modal-nodes-manager.ts b/packages/designer/src/document/node/modal-nodes-manager.ts index 585b52f5f2..8e04f72fc5 100644 --- a/packages/designer/src/document/node/modal-nodes-manager.ts +++ b/packages/designer/src/document/node/modal-nodes-manager.ts @@ -1,9 +1,9 @@ -import { INode, Node } from './node'; +import { INode } from './node'; import { DocumentModel } from '../document-model'; import { IPublicModelModalNodesManager } from '@alilc/lowcode-types'; import { createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core'; -export function getModalNodes(node: INode | Node) { +export function getModalNodes(node: INode) { if (!node) return []; let nodes: any = []; if (node.componentMeta.isModal) { @@ -18,11 +18,7 @@ export function getModalNodes(node: INode | Node) { return nodes; } -export interface IModalNodesManager extends IPublicModelModalNodesManager { - - getModalNodes(): INode[]; - - getVisibleModalNode(): INode | null; +export interface IModalNodesManager extends IPublicModelModalNodesManager { } export class ModalNodesManager implements IModalNodesManager { diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index 12a9e75ba5..ff85b2231d 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -10,7 +10,12 @@ export interface IOnChangeOptions { node: Node; } -export interface INodeChildren extends Omit { +export interface INodeChildren extends Omit, + 'importSchema' | + 'exportSchema' | + 'isEmpty' | + 'notEmpty' +> { get owner(): INode; unlinkChild(node: INode): void; @@ -42,31 +47,17 @@ export interface INodeChildren extends Omit void): void; - map(fn: (item: INode, index: number) => T): T[] | null; - - every(fn: (item: INode, index: number) => any): boolean; - - some(fn: (item: INode, index: number) => any): boolean; - - filter(fn: (item: INode, index: number) => any): any; - - find(fn: (item: INode, index: number) => boolean): any; - - reduce(fn: (acc: any, cur: INode) => any, initialValue: any): void; - - reverse(): INode[]; - - mergeChildren( - remover: (node: INode, idx: number) => boolean, - adder: (children: INode[]) => IPublicTypeNodeData[] | null, - sorter: (firstNode: INode, secondNode: INode) => number, - ): any; - /** * 根据索引获得节点 */ get(index: number): INode | null; + isEmpty(): boolean; + + notEmpty(): boolean; + + internalInitParent(): void; + /** overriding methods end */ } export class NodeChildren implements INodeChildren { @@ -140,12 +131,12 @@ export class NodeChildren implements INodeChildren { const child = originChildren[i]; const item = data[i]; - let node: Node | undefined; + let node: INode | undefined | null; if (isNodeSchema(item) && !checkId && child && child.componentName === item.componentName) { node = child; node.import(item); } else { - node = this.owner.document.createNode(item, checkId); + node = this.owner.document?.createNode(item, checkId); } children[i] = node; } @@ -436,7 +427,7 @@ export class NodeChildren implements INodeChildren { return this.children.filter(fn); } - find(fn: (item: INode, index: number) => boolean) { + find(fn: (item: INode, index: number) => boolean): INode | undefined { return this.children.find(fn); } @@ -471,7 +462,7 @@ export class NodeChildren implements INodeChildren { const items = adder(this.children); if (items && items.length > 0) { items.forEach((child: IPublicTypeNodeData) => { - const node = this.owner.document?.createNode(child); + const node: INode = this.owner.document?.createNode(child); this.children.push(node); node.internalSetParent(this.owner); }); diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 7739bcf1c4..efa860c8db 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -16,9 +16,10 @@ import { IPublicModelExclusiveGroup, IPublicEnumTransformStage, IPublicTypeDisposable, + IBaseModelNode, } from '@alilc/lowcode-types'; import { compatStage, isDOMText, isJSExpression, isNode } from '@alilc/lowcode-utils'; -import { SettingTopEntry } from '@alilc/lowcode-designer'; +import { ISettingTopEntry, SettingTopEntry } from '@alilc/lowcode-designer'; import { Props, getConvertedExtraKey, IProps } from './props/props'; import { DocumentModel, IDocumentModel } from '../document-model'; import { NodeChildren, INodeChildren } from './node-children'; @@ -36,28 +37,38 @@ export interface NodeStatus { inPlaceEditing: boolean; } -export interface INode extends IPublicModelNode { - - /** - * 当前节点子集 - */ - get children(): INodeChildren | null; - - /** - * 获取上一个兄弟节点 - */ - get prevSibling(): INode | null; - - /** - * 获取下一个兄弟节点 - */ - get nextSibling(): INode | null; - - /** - * 父级节点 - */ - get parent(): INode | null; - +export interface INode extends Omit, + 'slots' | + 'slotFor' | + 'props' | + 'getProp' | + 'getExtraProp' | + 'replaceChild' | + 'isRoot' | + 'isPage' | + 'isComponent' | + 'isModal' | + 'isSlot' | + 'isParental' | + 'isLeaf' | + 'settingEntry' | + // 在内部的 node 模型中不存在 + 'getExtraPropValue' | + 'setExtraPropValue' | + 'exportSchema' | + 'visible' | + 'importSchema' | + 'isEmptyNode' | + // 内外实现有差异 + 'isContainer' | + 'isEmpty' +> { get slots(): INode[]; /** @@ -69,7 +80,9 @@ export interface INode extends IPublicModelNode { get componentMeta(): IComponentMeta; - get document(): IDocumentModel; + get settingEntry(): SettingTopEntry; + + get isPurged(): boolean; setVisible(flag: boolean): void; @@ -79,7 +92,7 @@ export interface INode extends IPublicModelNode { * 内部方法,请勿使用 * @param useMutator 是否触发联动逻辑 */ - internalSetParent(parent: INode | null, useMutator: boolean): void; + internalSetParent(parent: INode | null, useMutator?: boolean): void; setConditionGroup(grp: IPublicModelExclusiveGroup | string | null): void; @@ -89,12 +102,10 @@ export interface INode extends IPublicModelNode { unlinkSlot(slotNode: Node): void; - didDropOut(dragment: Node): void; - /** * 导出 schema */ - export(stage: IPublicEnumTransformStage, options?: any): IPublicTypeNodeSchema; + export(stage: IPublicEnumTransformStage, options?: any): T; emitPropChange(val: IPublicTypePropChangeOptions): void; @@ -117,6 +128,38 @@ export interface INode extends IPublicModelNode { onChildrenChange(fn: (param?: { type: string; node: INode }) => void): IPublicTypeDisposable; onPropChange(func: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable; + + isModal(): boolean; + + isRoot(): boolean; + + isPage(): boolean; + + isComponent(): boolean; + + isSlot(): boolean; + + isParental(): boolean; + + isLeaf(): boolean; + + isContainer(): boolean; + + isEmpty(): boolean; + + remove( + useMutator?: boolean, + purge?: boolean, + options?: NodeRemoveOptions, + ): void; + + didDropIn(dragment: Node): void; + + didDropOut(dragment: Node): void; + + get isPurging(): boolean; + + purge(): void; } /** @@ -251,9 +294,9 @@ export class Node isInited = false; - _settingEntry: SettingTopEntry; + _settingEntry: ISettingTopEntry; - get settingEntry(): SettingTopEntry { + get settingEntry(): ISettingTopEntry { if (this._settingEntry) return this._settingEntry; this._settingEntry = this.document.designer.createSettingEntry([this]); return this._settingEntry; @@ -319,7 +362,7 @@ export class Node pseudo: false, }; - constructor(readonly document: IDocumentModel, nodeSchema: Schema, options: any = {}) { + constructor(readonly document: IDocumentModel, nodeSchema: Schema) { makeObservable(this); const { componentName, id, children, props, ...extras } = nodeSchema; this.id = document.nextId(id); @@ -347,7 +390,7 @@ export class Node this.onVisibleChange((visible: boolean) => { editor?.eventBus.emit(EDITOR_EVENT.NODE_VISIBLE_CHANGE, this, visible); }); - this.onChildrenChange((info?: { type: string; node: Node }) => { + this.onChildrenChange((info?: { type: string; node: INode }) => { editor?.eventBus.emit(EDITOR_EVENT.NODE_VISIBLE_CHANGE, info); }); } @@ -475,7 +518,7 @@ export class Node this.document.addWillPurge(this); } - private didDropIn(dragment: Node) { + didDropIn(dragment: Node) { const { callbacks } = this.componentMeta.advanced; if (callbacks?.onNodeAdd) { const cbThis = this.internalToShellNode(); @@ -486,7 +529,7 @@ export class Node } } - private didDropOut(dragment: Node) { + didDropOut(dragment: Node) { const { callbacks } = this.componentMeta.advanced; if (callbacks?.onNodeRemove) { const cbThis = this.internalToShellNode(); @@ -869,7 +912,7 @@ export class Node /** * 导出 schema */ - export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save, options: any = {}): Schema { + export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save, options: any = {}): T { stage = compatStage(stage); const baseSchema: any = { componentName: this.componentName, @@ -955,7 +998,7 @@ export class Node /** * 删除一个Slot节点 */ - removeSlot(slotNode: Node, purge = false): boolean { + removeSlot(slotNode: Node): boolean { // if (purge) { // // should set parent null // slotNode?.internalSetParent(null, false); @@ -1047,16 +1090,16 @@ export class Node return this.componentName; } - insert(node: Node, ref?: Node, useMutator = true) { + insert(node: Node, ref?: INode, useMutator = true) { this.insertAfter(node, ref, useMutator); } - insertBefore(node: Node, ref?: Node, useMutator = true) { + insertBefore(node: INode, ref?: INode, useMutator = true) { const nodeInstance = ensureNode(node, this.document); this.children?.internalInsert(nodeInstance, ref ? ref.index : null, useMutator); } - insertAfter(node: any, ref?: Node, useMutator = true) { + insertAfter(node: any, ref?: INode, useMutator = true) { const nodeInstance = ensureNode(node, this.document); this.children?.internalInsert(nodeInstance, ref ? ref.index + 1 : null, useMutator); } @@ -1085,15 +1128,15 @@ export class Node return this.props; } - onChildrenChange(fn: (param?: { type: string; node: Node }) => void): IPublicTypeDisposable { + onChildrenChange(fn: (param?: { type: string; node: INode }) => void): IPublicTypeDisposable { const wrappedFunc = wrapWithEventSwitch(fn); return this.children?.onChange(wrappedFunc); } mergeChildren( - remover: () => any, - adder: (children: Node[]) => IPublicTypeNodeData[] | null, - sorter: () => any, + remover: (node: INode, idx: number) => any, + adder: (children: INode[]) => IPublicTypeNodeData[] | null, + sorter: (firstNode: INode, secondNode: INode) => any, ) { this.children?.mergeChildren(remover, adder, sorter); } diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 81675aa571..90d72668a3 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -2,7 +2,7 @@ import { untracked, computed, obx, engineConfig, action, makeObservable, mobx, r import { IPublicTypeCompositeValue, GlobalEvent, IPublicTypeJSSlot, IPublicTypeSlotSchema, IPublicEnumTransformStage, IPublicModelProp } from '@alilc/lowcode-types'; import { uniqueId, isPlainObject, hasOwnProperty, compatStage, isJSExpression, isJSSlot } from '@alilc/lowcode-utils'; import { valueToSource } from './value-to-source'; -import { Props, IProps, IPropParent } from './props'; +import { IProps, IPropParent } from './props'; import { SlotNode, INode } from '../node'; // import { TransformStage } from '../transform-stage'; @@ -13,7 +13,7 @@ export type UNSET = typeof UNSET; export interface IProp extends Omit { - readonly props: Props; + readonly props: IProps; readonly owner: INode; @@ -24,6 +24,8 @@ export interface IProp extends Omit { +export interface IProps extends Omit, | 'getExtraProp' | 'getExtraPropValue' | 'setExtraPropValue' | 'node'> { /** * 获取 props 对应的 node */ getNode(): INode; - getProp(path: string): IProp | null; + get(path: string, createIfNone?: boolean): Prop | null; - get(path: string, createIfNone: boolean): Prop; + export(stage?: IPublicEnumTransformStage): { + props?: IPublicTypePropsMap | IPublicTypePropsList; + extras?: ExtrasObject; + }; + + merge(value: IPublicTypePropsMap, extras?: IPublicTypePropsMap): void; } export class Props implements IProps, IPropParent { diff --git a/packages/designer/src/document/selection.ts b/packages/designer/src/document/selection.ts index bcbf778eaa..2456de7594 100644 --- a/packages/designer/src/document/selection.ts +++ b/packages/designer/src/document/selection.ts @@ -1,20 +1,10 @@ import { obx, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; -import { Node, INode, comparePosition, PositionNO } from './node/node'; +import { INode, comparePosition, PositionNO } from './node/node'; import { DocumentModel } from './document-model'; import { IPublicModelSelection } from '@alilc/lowcode-types'; -export interface ISelection extends Omit< IPublicModelSelection, 'getNodes' | 'getTopNodes' > { +export interface ISelection extends Omit, 'node'> { - /** - * 获取选中的节点实例 - * @returns - */ - getNodes(): INode[]; - - /** - * 获取顶层选区节点,场景:拖拽时,建立蒙层,只蒙在最上层 - */ - getTopNodes(includeRoot?: boolean): INode[]; } export class Selection implements ISelection { @@ -115,7 +105,7 @@ export class Selection implements ISelection { /** * 选区是否包含节点 */ - containsNode(node: Node, excludeRoot = false) { + containsNode(node: INode, excludeRoot = false) { for (const id of this._selected) { const parent = this.doc.getNode(id); if (excludeRoot && parent?.contains(this.doc.focusNode)) { @@ -131,8 +121,8 @@ export class Selection implements ISelection { /** * 获取选中的节点 */ - getNodes(): Node[] { - const nodes = []; + getNodes(): INode[] { + const nodes: INode[] = []; for (const id of this._selected) { const node = this.doc.getNode(id); if (node) { diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 42ba0b4fc9..6516d67aa7 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -12,13 +12,31 @@ import { import { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils'; import { ISimulatorHost } from '../simulator'; -export interface IProject extends Omit< IPublicApiProject, 'simulatorHost' | 'importSchema' | 'exportSchema' | 'openDocument' | 'getDocumentById' | 'getCurrentDocument' | 'addPropsTransducer' | 'onRemoveDocument' | 'onChangeDocument' | 'onSimulatorHostReady' | 'onSimulatorRendererReady' | 'setI18n' > { +export interface IProject extends Omit< IPublicApiProject, + 'simulatorHost' | + 'importSchema' | + 'exportSchema' | + 'openDocument' | + 'getDocumentById' | + 'getCurrentDocument' | + 'addPropsTransducer' | + 'onRemoveDocument' | + 'onChangeDocument' | + 'onSimulatorHostReady' | + 'onSimulatorRendererReady' | + 'setI18n' | + 'currentDocument' | + 'selection' | + 'documents' | + 'createDocument' | + 'getDocumentByFileName' +> { get designer(): IDesigner; get simulator(): ISimulatorHost | null; - get currentDocument(): IDocumentModel | null; + get currentDocument(): IDocumentModel | null | undefined; get documents(): IDocumentModel[]; @@ -60,6 +78,8 @@ export interface IProject extends Omit< IPublicApiProject, 'simulatorHost' | 'im // eslint-disable-next-line @typescript-eslint/no-unused-vars value: any, ): void; + + checkExclusive(activeDoc: DocumentModel): void; } export class Project implements IProject { @@ -85,7 +105,7 @@ export class Project implements IProject { return this._simulator || null; } - @computed get currentDocument(): IDocumentModel | null { + @computed get currentDocument(): IDocumentModel | null | undefined { return this.documents.find((doc) => doc.active); } diff --git a/packages/designer/src/simulator.ts b/packages/designer/src/simulator.ts index 5a2fb8efc5..32b9233c90 100644 --- a/packages/designer/src/simulator.ts +++ b/packages/designer/src/simulator.ts @@ -2,7 +2,7 @@ import { ComponentType } from 'react'; import { IPublicTypeComponentMetadata, IPublicTypeNodeSchema, IPublicTypeScrollable, IPublicTypeComponentInstance, IPublicModelSensor, IPublicTypeNodeInstance } from '@alilc/lowcode-types'; import { Point, ScrollTarget, ILocateEvent } from './designer'; import { BuiltinSimulatorRenderer } from './builtin-simulator/renderer'; -import { Node, INode } from './document'; +import { INode } from './document'; export type AutoFit = '100%'; // eslint-disable-next-line no-redeclare @@ -132,7 +132,7 @@ export interface ISimulatorHost

extends IPublicModelSensor { /** * 滚动视口到节点 */ - scrollToNode(node: Node, detail?: any): void; + scrollToNode(node: INode, detail?: any): void; /** * 描述组件 @@ -147,7 +147,7 @@ export interface ISimulatorHost

extends IPublicModelSensor { /** * 根据节点获取节点的组件实例 */ - getComponentInstances(node: Node): IPublicTypeComponentInstance[] | null; + getComponentInstances(node: INode): IPublicTypeComponentInstance[] | null; /** * 根据 schema 创建组件类 @@ -157,11 +157,11 @@ export interface ISimulatorHost

extends IPublicModelSensor { /** * 根据节点获取节点的组件运行上下文 */ - getComponentContext(node: Node): object | null; + getComponentContext(node: INode): object | null; getClosestNodeInstance(from: IPublicTypeComponentInstance, specId?: string): IPublicTypeNodeInstance | null; - computeRect(node: Node): DOMRect | null; + computeRect(node: INode): DOMRect | null; computeComponentInstanceRect(instance: IPublicTypeComponentInstance, selector?: string): DOMRect | null; @@ -189,6 +189,6 @@ export function isSimulatorHost(obj: any): obj is ISimulatorHost { export type Component = ComponentType | object; export interface INodeSelector { - node: Node; + node: INode; instance?: IPublicTypeComponentInstance; } diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts index 85d44c2ccf..b1015b8de8 100644 --- a/packages/shell/src/model/document-model.ts +++ b/packages/shell/src/model/document-model.ts @@ -21,6 +21,7 @@ import { IPublicApiCanvas, IPublicTypeDisposable, IPublicModelEditor, + IPublicTypeNodeSchema, } from '@alilc/lowcode-types'; import { isDragNodeObject } from '@alilc/lowcode-utils'; import { Node as ShellNode } from './node'; @@ -195,7 +196,7 @@ export class DocumentModel implements IPublicModelDocumentModel { * @param data * @returns */ - createNode(data: any): IPublicModelNode | null { + createNode(data: IPublicTypeNodeSchema): IPublicModelNode | null { return ShellNode.create(this[documentSymbol].createNode(data)); } @@ -289,7 +290,7 @@ export class DocumentModel implements IPublicModelDocumentModel { * @param fn */ onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): IPublicTypeDisposable { - return this[documentSymbol].onChangeNodeVisible((node: IPublicModelNode, visible: boolean) => { + return this[documentSymbol].onChangeNodeVisible((node: InnerNode, visible: boolean) => { fn(ShellNode.create(node)!, visible); }); } diff --git a/packages/shell/src/model/node.ts b/packages/shell/src/model/node.ts index ba2412e893..9b407de5cf 100644 --- a/packages/shell/src/model/node.ts +++ b/packages/shell/src/model/node.ts @@ -362,9 +362,9 @@ export class Node implements IPublicModelNode { * @param sorter */ mergeChildren( - remover: (node: IPublicModelNode, idx: number) => boolean, - adder: (children: IPublicModelNode[]) => any, - sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number, + remover: (node: Node, idx: number) => boolean, + adder: (children: Node[]) => any, + sorter: (firstNode: Node, secondNode: Node) => number, ): any { return this.children?.mergeChildren(remover, adder, sorter); } diff --git a/packages/shell/src/model/selection.ts b/packages/shell/src/model/selection.ts index ff2124bec4..073083a650 100644 --- a/packages/shell/src/model/selection.ts +++ b/packages/shell/src/model/selection.ts @@ -1,14 +1,14 @@ import { IDocumentModel as InnerDocumentModel, INode as InnerNode, - ISelection as InnerSelection, + ISelection, } from '@alilc/lowcode-designer'; import { Node as ShellNode } from './node'; import { selectionSymbol } from '../symbols'; import { IPublicModelSelection, IPublicModelNode, IPublicTypeDisposable } from '@alilc/lowcode-types'; export class Selection implements IPublicModelSelection { - private readonly [selectionSymbol]: InnerSelection; + private readonly [selectionSymbol]: ISelection; constructor(document: InnerDocumentModel) { this[selectionSymbol] = document.selection; diff --git a/packages/types/src/shell/model/component-meta.ts b/packages/types/src/shell/model/component-meta.ts index 369680fd6e..f2b0032a75 100644 --- a/packages/types/src/shell/model/component-meta.ts +++ b/packages/types/src/shell/model/component-meta.ts @@ -2,7 +2,9 @@ import { IPublicTypeNodeSchema, IPublicTypeNodeData, IPublicTypeIconType, IPubli import { ReactElement } from 'react'; import { IPublicModelNode } from './node'; -export interface IPublicModelComponentMeta { +export interface IPublicModelComponentMeta< + Node = IPublicModelNode +> { /** * 组件名 @@ -92,7 +94,7 @@ export interface IPublicModelComponentMeta { * @param my 当前节点 * @param parent 父节点 */ - checkNestingUp(my: IPublicModelNode | IPublicTypeNodeData, parent: any): boolean; + checkNestingUp(my: Node | IPublicTypeNodeData, parent: any): boolean; /** * 检测目标节点是否可被放置在父节点中 @@ -101,8 +103,8 @@ export interface IPublicModelComponentMeta { * @param parent 父节点 */ checkNestingDown( - my: IPublicModelNode | IPublicTypeNodeData, - target: IPublicTypeNodeSchema | IPublicModelNode | IPublicTypeNodeSchema[], + my: Node | IPublicTypeNodeData, + target: IPublicTypeNodeSchema | Node | IPublicTypeNodeSchema[], ): boolean; /** diff --git a/packages/types/src/shell/model/detecting.ts b/packages/types/src/shell/model/detecting.ts index 9bc215f9af..ec6320ad2f 100644 --- a/packages/types/src/shell/model/detecting.ts +++ b/packages/types/src/shell/model/detecting.ts @@ -1,7 +1,7 @@ import { IPublicModelNode } from './'; import { IPublicTypeDisposable } from '../type'; -export interface IPublicModelDetecting { +export interface IPublicModelDetecting { /** * 是否启用 @@ -15,7 +15,7 @@ export interface IPublicModelDetecting { * get current hovering node * @since v1.0.16 */ - get current(): IPublicModelNode | null; + get current(): Node | null; /** * hover 指定节点 @@ -42,5 +42,5 @@ export interface IPublicModelDetecting { * set callback which will be called when hovering object changed. * @since v1.1.0 */ - onDetectingChange(fn: (node: IPublicModelNode | null) => void): IPublicTypeDisposable; + onDetectingChange(fn: (node: Node | null) => void): IPublicTypeDisposable; } diff --git a/packages/types/src/shell/model/document-model.ts b/packages/types/src/shell/model/document-model.ts index 72d20ceb03..99086d20db 100644 --- a/packages/types/src/shell/model/document-model.ts +++ b/packages/types/src/shell/model/document-model.ts @@ -2,15 +2,22 @@ import { IPublicTypeRootSchema, IPublicTypeDragNodeDataObject, IPublicTypeDragNo import { IPublicEnumTransformStage } from '../enum'; import { IPublicApiProject } from '../api'; import { IPublicModelDropLocation, IPublicModelDetecting, IPublicModelNode, IPublicModelSelection, IPublicModelHistory, IPublicModelModalNodesManager } from './'; -import { IPublicTypeOnChangeOptions } from '@alilc/lowcode-types'; +import { IPublicTypeNodeData, IPublicTypeNodeSchema, IPublicTypeOnChangeOptions } from '@alilc/lowcode-types'; -export interface IPublicModelDocumentModel { +export interface IPublicModelDocumentModel< + Selection = IPublicModelSelection, + History = IPublicModelHistory, + Node = IPublicModelNode, + DropLocation = IPublicModelDropLocation, + ModalNodesManager = IPublicModelModalNodesManager, + Project = IPublicApiProject +> { /** * 节点选中区模型实例 * instance of selection */ - selection: IPublicModelSelection; + selection: Selection; /** * 画布节点 hover 区模型实例 @@ -22,7 +29,7 @@ export interface IPublicModelDocumentModel { * 操作历史模型实例 * instance of history */ - history: IPublicModelHistory; + history: History; /** * id @@ -36,30 +43,30 @@ export interface IPublicModelDocumentModel { * get project which this documentModel belongs to * @returns */ - get project(): IPublicApiProject; + get project(): Project; /** * 获取文档的根节点 * root node of this documentModel * @returns */ - get root(): IPublicModelNode | null; + get root(): Node | null; - get focusNode(): IPublicModelNode | null; + get focusNode(): Node | null; - set focusNode(node: IPublicModelNode | null); + set focusNode(node: Node | null); /** * 获取文档下所有节点 * @returns */ - get nodesMap(): Map; + get nodesMap(): Map; /** * 模态节点管理 * get instance of modalNodesManager */ - get modalNodesManager(): IPublicModelModalNodesManager | null; + get modalNodesManager(): ModalNodesManager | null; /** * 根据 nodeId 返回 Node 实例 @@ -67,7 +74,7 @@ export interface IPublicModelDocumentModel { * @param nodeId * @returns */ - getNodeById(nodeId: string): IPublicModelNode | null; + getNodeById(nodeId: string): Node | null; /** * 导入 schema @@ -89,11 +96,11 @@ export interface IPublicModelDocumentModel { * insert a node */ insertNode( - parent: IPublicModelNode, - thing: IPublicModelNode, + parent: Node, + thing: Node | IPublicTypeNodeData, at?: number | null | undefined, copy?: boolean | undefined - ): IPublicModelNode | null; + ): Node | null; /** * 创建一个节点 @@ -101,14 +108,14 @@ export interface IPublicModelDocumentModel { * @param data * @returns */ - createNode(data: any): IPublicModelNode | null; + createNode(data: IPublicTypeNodeSchema): Node | null; /** * 移除指定节点/节点id * remove a node by node instance or nodeId * @param idOrNode */ - removeNode(idOrNode: string | IPublicModelNode): void; + removeNode(idOrNode: string | Node): void; /** * componentsMap of documentModel @@ -126,7 +133,7 @@ export interface IPublicModelDocumentModel { * @since v1.0.16 */ checkNesting( - dropTarget: IPublicModelNode, + dropTarget: Node, dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject ): boolean; @@ -134,26 +141,26 @@ export interface IPublicModelDocumentModel { * 当前 document 新增节点事件 * set callback for event on node is created for a document */ - onAddNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; + onAddNode(fn: (node: Node) => void): IPublicTypeDisposable; /** * 当前 document 新增节点事件,此时节点已经挂载到 document 上 * set callback for event on node is mounted to canvas */ - onMountNode(fn: (payload: { node: IPublicModelNode }) => void): IPublicTypeDisposable; + onMountNode(fn: (payload: { node: Node }) => void): IPublicTypeDisposable; /** * 当前 document 删除节点事件 * set callback for event on node is removed */ - onRemoveNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; + onRemoveNode(fn: (node: Node) => void): IPublicTypeDisposable; /** * 当前 document 的 hover 变更事件 * * set callback for event on detecting changed */ - onChangeDetecting(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; + onChangeDetecting(fn: (node: Node) => void): IPublicTypeDisposable; /** * 当前 document 的选中变更事件 @@ -166,7 +173,7 @@ export interface IPublicModelDocumentModel { * set callback for event on visibility changed for certain node * @param fn */ - onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): IPublicTypeDisposable; + onChangeNodeVisible(fn: (node: Node, visible: boolean) => void): IPublicTypeDisposable; /** * 当前 document 的节点 children 变更事件 @@ -193,21 +200,21 @@ export interface IPublicModelDocumentModel { * @param node * @since v1.1.0 */ - isDetectingNode(node: IPublicModelNode): boolean; + isDetectingNode(node: Node): boolean; /** * 获取当前的 DropLocation 信息 * get current drop location * @since v1.1.0 */ - get dropLocation(): IPublicModelDropLocation | null; + get dropLocation(): DropLocation | null; /** * 设置当前的 DropLocation 信息 * set current drop location * @since v1.1.0 */ - set dropLocation(loc: IPublicModelDropLocation | null); + set dropLocation(loc: DropLocation | null); /** * 设置聚焦节点变化的回调 @@ -216,7 +223,7 @@ export interface IPublicModelDocumentModel { * @since v1.1.0 */ onFocusNodeChanged( - fn: (doc: IPublicModelDocumentModel, focusNode: IPublicModelNode) => void, + fn: (doc: IPublicModelDocumentModel, focusNode: Node) => void, ): IPublicTypeDisposable; /** diff --git a/packages/types/src/shell/model/modal-nodes-manager.ts b/packages/types/src/shell/model/modal-nodes-manager.ts index bfbba50ecb..07656c0701 100644 --- a/packages/types/src/shell/model/modal-nodes-manager.ts +++ b/packages/types/src/shell/model/modal-nodes-manager.ts @@ -1,6 +1,6 @@ import { IPublicModelNode } from './'; -export interface IPublicModelModalNodesManager { +export interface IPublicModelModalNodesManager { /** * 设置模态节点,触发内部事件 @@ -12,13 +12,13 @@ export interface IPublicModelModalNodesManager { * 获取模态节点(们) * get modal nodes */ - getModalNodes(): IPublicModelNode[]; + getModalNodes(): Node[]; /** * 获取当前可见的模态节点 * get current visible modal node */ - getVisibleModalNode(): IPublicModelNode | null; + getVisibleModalNode(): Node | null; /** * 隐藏模态节点(们) @@ -31,12 +31,12 @@ export interface IPublicModelModalNodesManager { * set specfic model node as visible * @param node Node */ - setVisible(node: IPublicModelNode): void; + setVisible(node: Node): void; /** * 设置指定节点为不可见态 * set specfic model node as invisible * @param node Node */ - setInvisible(node: IPublicModelNode): void; + setInvisible(node: Node): void; } diff --git a/packages/types/src/shell/model/node-children.ts b/packages/types/src/shell/model/node-children.ts index 0379194bf9..ecab5fd338 100644 --- a/packages/types/src/shell/model/node-children.ts +++ b/packages/types/src/shell/model/node-children.ts @@ -2,13 +2,15 @@ import { IPublicTypeNodeSchema, IPublicTypeNodeData } from '../type'; import { IPublicEnumTransformStage } from '../enum'; import { IPublicModelNode } from './'; -export interface IPublicModelNodeChildren { +export interface IPublicModelNodeChildren< + Node = IPublicModelNode +> { /** * 返回当前 children 实例所属的节点实例 * get owner node of this nodeChildren */ - get owner(): IPublicModelNode | null; + get owner(): Node | null; /** * children 内的节点实例数 @@ -45,7 +47,7 @@ export interface IPublicModelNodeChildren { * delete the node * @param node */ - delete(node: IPublicModelNode): boolean; + delete(node: Node): boolean; /** * 插入一个节点 @@ -54,7 +56,7 @@ export interface IPublicModelNodeChildren { * @param at 插入下标 * @returns */ - insert(node: IPublicModelNode, at?: number | null): void; + insert(node: Node, at?: number | null): void; /** * 返回指定节点的下标 @@ -62,7 +64,7 @@ export interface IPublicModelNodeChildren { * @param node * @returns */ - indexOf(node: IPublicModelNode): number; + indexOf(node: Node): number; /** * 类似数组 splice 操作 @@ -71,7 +73,7 @@ export interface IPublicModelNodeChildren { * @param deleteCount * @param node */ - splice(start: number, deleteCount: number, node?: IPublicModelNode): any; + splice(start: number, deleteCount: number, node?: Node): any; /** * 返回指定下标的节点 @@ -79,7 +81,7 @@ export interface IPublicModelNodeChildren { * @param index * @returns */ - get(index: number): IPublicModelNode | null; + get(index: number): Node | null; /** * 是否包含指定节点 @@ -87,62 +89,62 @@ export interface IPublicModelNodeChildren { * @param node * @returns */ - has(node: IPublicModelNode): boolean; + has(node: Node): boolean; /** * 类似数组的 forEach * provide the same function with {Array.prototype.forEach} * @param fn */ - forEach(fn: (node: IPublicModelNode, index: number) => void): void; + forEach(fn: (node: Node, index: number) => void): void; /** * 类似数组的 reverse * provide the same function with {Array.prototype.reverse} */ - reverse(): IPublicModelNode[]; + reverse(): Node[]; /** * 类似数组的 map * provide the same function with {Array.prototype.map} * @param fn */ - map(fn: (node: IPublicModelNode, index: number) => T[]): any[] | null; + map(fn: (node: Node, index: number) => T): T[] | null; /** * 类似数组的 every * provide the same function with {Array.prototype.every} * @param fn */ - every(fn: (node: IPublicModelNode, index: number) => boolean): boolean; + every(fn: (node: Node, index: number) => boolean): boolean; /** * 类似数组的 some * provide the same function with {Array.prototype.some} * @param fn */ - some(fn: (node: IPublicModelNode, index: number) => boolean): boolean; + some(fn: (node: Node, index: number) => boolean): boolean; /** * 类似数组的 filter * provide the same function with {Array.prototype.filter} * @param fn */ - filter(fn: (node: IPublicModelNode, index: number) => boolean): any; + filter(fn: (node: Node, index: number) => boolean): any; /** * 类似数组的 find * provide the same function with {Array.prototype.find} * @param fn */ - find(fn: (node: IPublicModelNode, index: number) => boolean): IPublicModelNode | null; + find(fn: (node: Node, index: number) => boolean): Node | null | undefined; /** * 类似数组的 reduce * provide the same function with {Array.prototype.reduce} * @param fn */ - reduce(fn: (acc: any, cur: IPublicModelNode) => any, initialValue: any): void; + reduce(fn: (acc: any, cur: Node) => any, initialValue: any): void; /** * 导入 schema @@ -166,9 +168,9 @@ export interface IPublicModelNodeChildren { * @param sorter */ mergeChildren( - remover: (node: IPublicModelNode, idx: number) => boolean, - adder: (children: IPublicModelNode[]) => IPublicTypeNodeData[] | null, - sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number + remover: (node: Node, idx: number) => boolean, + adder: (children: Node[]) => IPublicTypeNodeData[] | null, + sorter: (firstNode: Node, secondNode: Node) => number ): any; } diff --git a/packages/types/src/shell/model/node.ts b/packages/types/src/shell/model/node.ts index 70c92016bb..dd6db71bf2 100644 --- a/packages/types/src/shell/model/node.ts +++ b/packages/types/src/shell/model/node.ts @@ -3,7 +3,13 @@ import { IPublicTypeNodeSchema, IPublicTypeIconType, IPublicTypeI18nData, IPubli import { IPublicEnumTransformStage } from '../enum'; import { IPublicModelNodeChildren, IPublicModelComponentMeta, IPublicModelProp, IPublicModelProps, IPublicModelSettingTopEntry, IPublicModelDocumentModel, IPublicModelExclusiveGroup } from './'; -export interface IPublicModelNode { +export interface IBaseModelNode< + Document = IPublicModelDocumentModel, + Node = IPublicModelNode, + NodeChildren = IPublicModelNodeChildren, + ComponentMeta = IPublicModelComponentMeta, + SettingTopEntry = IPublicModelSettingTopEntry +> { /** * 节点 id @@ -185,43 +191,43 @@ export interface IPublicModelNode { * 节点的物料元数据 * get component meta of this node */ - get componentMeta(): IPublicModelComponentMeta | null; + get componentMeta(): ComponentMeta | null; /** * 获取节点所属的文档模型对象 * get documentModel of this node */ - get document(): IPublicModelDocumentModel | null; + get document(): Document | null; /** * 获取当前节点的前一个兄弟节点 * get previous sibling of this node */ - get prevSibling(): IPublicModelNode | null; + get prevSibling(): Node | null; /** * 获取当前节点的后一个兄弟节点 * get next sibling of this node */ - get nextSibling(): IPublicModelNode | null; + get nextSibling(): Node | null; /** * 获取当前节点的父亲节点 * get parent of this node */ - get parent(): IPublicModelNode | null; + get parent(): Node | null; /** * 获取当前节点的孩子节点模型 * get children of this node */ - get children(): IPublicModelNodeChildren | null; + get children(): NodeChildren | null; /** * 节点上挂载的插槽节点们 * get slots of this node */ - get slots(): IPublicModelNode[]; + get slots(): Node[]; /** * 当前节点为插槽节点时,返回节点对应的属性实例 @@ -258,7 +264,7 @@ export interface IPublicModelNode { * get setting entry of this node * @since v1.1.0 */ - get settingEntry(): IPublicModelSettingTopEntry; + get settingEntry(): SettingTopEntry; /** * 返回节点的尺寸、位置信息 @@ -359,8 +365,8 @@ export interface IPublicModelNode { * @param useMutator */ insertBefore( - node: IPublicModelNode, - ref?: IPublicModelNode | undefined, + node: Node, + ref?: Node | undefined, useMutator?: boolean, ): void; @@ -372,8 +378,8 @@ export interface IPublicModelNode { * @param useMutator */ insertAfter( - node: IPublicModelNode, - ref?: IPublicModelNode | undefined, + node: Node, + ref?: Node | undefined, useMutator?: boolean, ): void; @@ -384,7 +390,7 @@ export interface IPublicModelNode { * @param data 用作替换的节点对象或者节点描述 * @returns */ - replaceChild(node: IPublicModelNode, data: any): IPublicModelNode | null; + replaceChild(node: Node, data: any): Node | null; /** * 将当前节点替换成指定节点描述 @@ -427,9 +433,9 @@ export interface IPublicModelNode { * @since v1.1.0 */ mergeChildren( - remover: (node: IPublicModelNode, idx: number) => boolean, - adder: (children: IPublicModelNode[]) => any, - sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number + remover: (node: Node, idx: number) => boolean, + adder: (children: Node[]) => any, + sorter: (firstNode: Node, secondNode: Node) => number ): any; /** @@ -438,7 +444,7 @@ export interface IPublicModelNode { * @param node * @since v1.1.0 */ - contains(node: IPublicModelNode): boolean; + contains(node: Node): boolean; /** * 是否可执行某 action @@ -476,3 +482,5 @@ export interface IPublicModelNode { */ setConditionalVisible(): void; } + +export interface IPublicModelNode extends IBaseModelNode {} \ No newline at end of file diff --git a/packages/types/src/shell/model/props.ts b/packages/types/src/shell/model/props.ts index 9c862a0089..3c390a8cf6 100644 --- a/packages/types/src/shell/model/props.ts +++ b/packages/types/src/shell/model/props.ts @@ -1,7 +1,9 @@ import { IPublicTypeCompositeValue } from '../type'; -import { IPublicModelNode, IPublicModelProp } from './'; +import { IPublicModelNode } from './'; -export interface IPublicModelProps { +export interface IBaseModelProps< + Prop +> { /** * id @@ -24,7 +26,7 @@ export interface IPublicModelProps { * get prop by path * @param path 属性路径,支持 a / a.b / a.0 等格式 */ - getProp(path: string): IPublicModelProp | null; + getProp(path: string): Prop | null; /** * 获取指定 path 的属性模型实例值 @@ -39,7 +41,7 @@ export interface IPublicModelProps { * get extra prop by path * @param path 属性路径,支持 a / a.b / a.0 等格式 */ - getExtraProp(path: string): IPublicModelProp | null; + getExtraProp(path: string): Prop | null; /** * 获取指定 path 的属性模型实例值 @@ -83,3 +85,5 @@ export interface IPublicModelProps { add(value: IPublicTypeCompositeValue, key?: string | number | undefined): any; } + +export type IPublicModelProps = IBaseModelProps; \ No newline at end of file diff --git a/packages/types/src/shell/model/selection.ts b/packages/types/src/shell/model/selection.ts index 3b2fdb2f50..317a49837d 100644 --- a/packages/types/src/shell/model/selection.ts +++ b/packages/types/src/shell/model/selection.ts @@ -1,7 +1,9 @@ import { IPublicModelNode } from './'; import { IPublicTypeDisposable } from '../type'; -export interface IPublicModelSelection { +export interface IPublicModelSelection< + Node = IPublicModelNode +> { /** * 返回选中的节点 id @@ -14,7 +16,7 @@ export interface IPublicModelSelection { * return selected Node instance,return the first one if multiple nodes are selected * @since v1.1.0 */ - get node(): IPublicModelNode | null; + get node(): Node | null; /** * 选中指定节点(覆盖方式) @@ -62,7 +64,7 @@ export interface IPublicModelSelection { * 获取选中的节点实例 * get selected nodes */ - getNodes(): IPublicModelNode[]; + getNodes(): Node[]; /** * 获取选区的顶层节点 @@ -72,7 +74,7 @@ export interface IPublicModelSelection { * getTopNodes() will return [A, B], subA will be removed * @since v1.0.16 */ - getTopNodes(includeRoot?: boolean): IPublicModelNode[]; + getTopNodes(includeRoot?: boolean): Node[]; /** * 注册 selection 变化事件回调 diff --git a/packages/types/src/shell/type/drag-node-object.ts b/packages/types/src/shell/type/drag-node-object.ts index ec375cbc0a..21f14b2bcb 100644 --- a/packages/types/src/shell/type/drag-node-object.ts +++ b/packages/types/src/shell/type/drag-node-object.ts @@ -1,7 +1,7 @@ import { IPublicModelNode } from '..'; import { IPublicEnumDragObjectType } from '../enum'; -export interface IPublicTypeDragNodeObject { +export interface IPublicTypeDragNodeObject { type: IPublicEnumDragObjectType.Node; - nodes: IPublicModelNode[]; + nodes: Node[]; } diff --git a/packages/types/src/shell/type/field-config.ts b/packages/types/src/shell/type/field-config.ts index 32b40f157b..bd09e7b906 100644 --- a/packages/types/src/shell/type/field-config.ts +++ b/packages/types/src/shell/type/field-config.ts @@ -13,7 +13,7 @@ export interface IPublicTypeFieldConfig extends IPublicTypeFieldExtraProps { /** * the name of this setting field, which used in quickEditor */ - name: string | number; + name?: string | number; /** * the field title diff --git a/packages/types/src/shell/type/field-extra-props.ts b/packages/types/src/shell/type/field-extra-props.ts index 2977da1d87..79466389e0 100644 --- a/packages/types/src/shell/type/field-extra-props.ts +++ b/packages/types/src/shell/type/field-extra-props.ts @@ -19,12 +19,12 @@ export interface IPublicTypeFieldExtraProps { /** * get value for field */ - getValue?: (target: IPublicModelSettingTarget, fieldValue: any) => any; + getValue?: (target: IPublicModelSettingPropEntry, fieldValue: any) => any; /** * set value for field */ - setValue?: (target: IPublicModelSettingTarget, value: any) => void; + setValue?: (target: IPublicModelSettingPropEntry, value: any) => void; /** * the field conditional show, is not set always true diff --git a/packages/types/src/shell/type/metadata.ts b/packages/types/src/shell/type/metadata.ts index 918074c582..7ee0228c97 100644 --- a/packages/types/src/shell/type/metadata.ts +++ b/packages/types/src/shell/type/metadata.ts @@ -1,5 +1,5 @@ import { IPublicTypePropType, IPublicTypeComponentAction } from './'; -import { IPublicModelProp, IPublicModelSettingTarget } from '../model'; +import { IPublicModelNode, IPublicModelProp, IPublicModelSettingTarget } from '../model'; /** * 嵌套控制函数 @@ -184,20 +184,20 @@ export interface ConfigureSupport { */ export interface IPublicTypeCallbacks { // hooks - onMouseDownHook?: (e: MouseEvent, currentNode: any) => any; - onDblClickHook?: (e: MouseEvent, currentNode: any) => any; - onClickHook?: (e: MouseEvent, currentNode: any) => any; + onMouseDownHook?: (e: MouseEvent, currentNode: IPublicModelNode) => any; + onDblClickHook?: (e: MouseEvent, currentNode: IPublicModelNode) => any; + onClickHook?: (e: MouseEvent, currentNode: IPublicModelNode) => any; // onLocateHook?: (e: any, currentNode: any) => any; // onAcceptHook?: (currentNode: any, locationData: any) => any; - onMoveHook?: (currentNode: any) => boolean; + onMoveHook?: (currentNode: IPublicModelNode) => boolean; // thinkof 限制性拖拽 - onHoverHook?: (currentNode: any) => boolean; - onChildMoveHook?: (childNode: any, currentNode: any) => boolean; + onHoverHook?: (currentNode: IPublicModelNode) => boolean; + onChildMoveHook?: (childNode: IPublicModelNode, currentNode: IPublicModelNode) => boolean; // events - onNodeRemove?: (removedNode: any, currentNode: any) => void; - onNodeAdd?: (addedNode: any, currentNode: any) => void; - onSubtreeModified?: (currentNode: any, options: any) => void; + onNodeRemove?: (removedNode: IPublicModelNode, currentNode: IPublicModelNode) => void; + onNodeAdd?: (addedNode: IPublicModelNode, currentNode: IPublicModelNode) => void; + onSubtreeModified?: (currentNode: IPublicModelNode, options: any) => void; onResize?: ( e: MouseEvent & { trigger: string; @@ -220,6 +220,6 @@ export interface IPublicTypeCallbacks { deltaX?: number; deltaY?: number; }, - currentNode: any, + currentNode: IPublicModelNode, ) => void; } diff --git a/packages/types/src/shell/type/setter-config.ts b/packages/types/src/shell/type/setter-config.ts index ddca728293..ac8a05aa3d 100644 --- a/packages/types/src/shell/type/setter-config.ts +++ b/packages/types/src/shell/type/setter-config.ts @@ -6,49 +6,60 @@ import { IPublicTypeDynamicProps } from './dynamic-props'; * 设置器配置 */ export interface IPublicTypeSetterConfig { + // if *string* passed must be a registered Setter Name /** * 配置设置器用哪一个 setter */ componentName: string | IPublicTypeCustomView; + /** * 传递给 setter 的属性 * * the props pass to Setter Component */ props?: Record | IPublicTypeDynamicProps; + /** * @deprecated */ children?: any; + /** * 是否必填? * * ArraySetter 里有个快捷预览,可以在不打开面板的情况下直接编辑 */ isRequired?: boolean; + /** * Setter 的初始值 * * @todo initialValue 可能要和 defaultValue 二选一 */ initialValue?: any | ((target: IPublicModelSettingTarget) => any); + + defaultValue?: any; + // for MixedSetter /** * 给 MixedSetter 时切换 Setter 展示用的 */ title?: IPublicTypeTitleContent; + // for MixedSetter check this is available /** * 给 MixedSetter 用于判断优先选中哪个 */ condition?: (target: IPublicModelSettingTarget) => boolean; + /** * 给 MixedSetter,切换值时声明类型 * * @todo 物料协议推进 */ valueType?: IPublicTypeCompositeValue[]; + // 标识是否为动态 setter,默认为 true isDynamic?: boolean; } diff --git a/packages/utils/src/check-types/is-drag-node-data-object.ts b/packages/utils/src/check-types/is-drag-node-data-object.ts index 6f17abf23d..4b08f67fa6 100644 --- a/packages/utils/src/check-types/is-drag-node-data-object.ts +++ b/packages/utils/src/check-types/is-drag-node-data-object.ts @@ -1,5 +1,5 @@ -import { IPublicEnumDragObjectType } from '@alilc/lowcode-types'; +import { IPublicEnumDragObjectType, IPublicTypeDragNodeDataObject } from '@alilc/lowcode-types'; -export function isDragNodeDataObject(obj: any): boolean { +export function isDragNodeDataObject(obj: any): obj is IPublicTypeDragNodeDataObject { return obj && obj.type === IPublicEnumDragObjectType.NodeData; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-drag-node-object.ts b/packages/utils/src/check-types/is-drag-node-object.ts index 79b28fb586..1b6c131e93 100644 --- a/packages/utils/src/check-types/is-drag-node-object.ts +++ b/packages/utils/src/check-types/is-drag-node-object.ts @@ -1,5 +1,5 @@ -import { IPublicEnumDragObjectType } from '@alilc/lowcode-types'; +import { IPublicEnumDragObjectType, IPublicModelNode, IPublicTypeDragNodeObject } from '@alilc/lowcode-types'; -export function isDragNodeObject(obj: any): boolean { +export function isDragNodeObject(obj: any): obj is IPublicTypeDragNodeObject { return obj && obj.type === IPublicEnumDragObjectType.Node; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-node.ts b/packages/utils/src/check-types/is-node.ts index 9fe27b29d4..14c2e2f74e 100644 --- a/packages/utils/src/check-types/is-node.ts +++ b/packages/utils/src/check-types/is-node.ts @@ -1,3 +1,5 @@ -export function isNode(node: any): boolean { +import { IPublicModelNode } from '@alilc/lowcode-types'; + +export function isNode(node: any): node is Node { return node && node.isNode; } \ No newline at end of file From 93e9b6ee009f02e9eca6b22ecef5df65af117501 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 28 Feb 2023 15:38:00 +0800 Subject: [PATCH 019/469] fix: fix build error due to ts definition --- .../designer/src/designer/setting/setting-entry.ts | 8 ++++---- .../designer/src/designer/setting/setting-field.ts | 14 +++++++++----- .../src/designer/setting/setting-prop-entry.ts | 10 +++++----- .../src/designer/setting/setting-top-entry.ts | 4 ++-- .../src/components/settings/settings-pane.tsx | 6 +++--- packages/engine/src/modules/shell-model-factory.ts | 4 ++-- packages/shell/src/model/setting-prop-entry.ts | 4 ++-- packages/shell/src/model/setting-top-entry.ts | 8 ++++---- 8 files changed, 31 insertions(+), 27 deletions(-) diff --git a/packages/designer/src/designer/setting/setting-entry.ts b/packages/designer/src/designer/setting/setting-entry.ts index a625e94242..39f978a707 100644 --- a/packages/designer/src/designer/setting/setting-entry.ts +++ b/packages/designer/src/designer/setting/setting-entry.ts @@ -3,15 +3,15 @@ import { IComponentMeta } from '../../component-meta'; import { Designer } from '../designer'; import { INode } from '../../document'; -export interface SettingEntry extends IPublicModelSettingTarget { +export interface ISettingEntry extends IPublicModelSettingTarget { readonly nodes: INode[]; readonly componentMeta: IComponentMeta | null; readonly designer: Designer; // 顶端 - readonly top: SettingEntry; + readonly top: ISettingEntry; // 父级 - readonly parent: SettingEntry; + readonly parent: ISettingEntry; - get: (propName: string | number) => SettingEntry | null; + get: (propName: string | number) => ISettingEntry | null; } diff --git a/packages/designer/src/designer/setting/setting-field.ts b/packages/designer/src/designer/setting/setting-field.ts index 50e2819d60..c073e28548 100644 --- a/packages/designer/src/designer/setting/setting-field.ts +++ b/packages/designer/src/designer/setting/setting-field.ts @@ -9,11 +9,11 @@ import { } from '@alilc/lowcode-types'; import { Transducer } from './utils'; import { SettingPropEntry } from './setting-prop-entry'; -import { SettingEntry } from './setting-entry'; +import { ISettingEntry } from './setting-entry'; import { computed, obx, makeObservable, action, untracked, intl } from '@alilc/lowcode-editor-core'; import { cloneDeep, isCustomView, isDynamicSetter } from '@alilc/lowcode-utils'; -function getSettingFieldCollectorKey(parent: SettingEntry, config: IPublicTypeFieldConfig) { +function getSettingFieldCollectorKey(parent: ISettingEntry, config: IPublicTypeFieldConfig) { let cur = parent; const path = [config.name]; while (cur !== parent.top) { @@ -25,7 +25,11 @@ function getSettingFieldCollectorKey(parent: SettingEntry, config: IPublicTypeFi return path.join('.'); } -export class SettingField extends SettingPropEntry implements SettingEntry { +export interface ISettingField extends ISettingEntry { + +} + +export class SettingField extends SettingPropEntry implements ISettingField { readonly isSettingField = true; readonly isRequired: boolean; @@ -36,7 +40,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry { private hotValue: any; - parent: SettingEntry; + parent: ISettingEntry; extraProps: IPublicTypeFieldExtraProps; @@ -56,7 +60,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry { private _items: Array = []; constructor( - parent: SettingEntry, + parent: ISettingEntry, config: IPublicTypeFieldConfig, private settingFieldCollector?: (name: string | number, field: SettingField) => void, ) { diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts index d523a0d35f..ed20964bad 100644 --- a/packages/designer/src/designer/setting/setting-prop-entry.ts +++ b/packages/designer/src/designer/setting/setting-prop-entry.ts @@ -2,13 +2,13 @@ import { obx, computed, makeObservable, runInAction, IEventBus, createModuleEven import { GlobalEvent, IPublicModelEditor, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; import { uniqueId, isJSExpression, isSettingField } from '@alilc/lowcode-utils'; import { Setters } from '@alilc/lowcode-shell'; -import { SettingEntry } from './setting-entry'; +import { ISettingEntry } from './setting-entry'; import { INode } from '../../document'; import { IComponentMeta } from '../../component-meta'; import { Designer } from '../designer'; -import { SettingField } from './setting-field'; +import { ISettingField } from './setting-field'; -export class SettingPropEntry implements SettingEntry { +export class SettingPropEntry implements ISettingEntry { // === static properties === readonly editor: IPublicModelEditor; @@ -26,7 +26,7 @@ export class SettingPropEntry implements SettingEntry { readonly designer: Designer; - readonly top: SettingEntry; + readonly top: ISettingEntry; readonly isGroup: boolean; @@ -53,7 +53,7 @@ export class SettingPropEntry implements SettingEntry { extraProps: any = {}; - constructor(readonly parent: SettingEntry | SettingField, name: string | number, type?: 'field' | 'group') { + constructor(readonly parent: ISettingEntry | ISettingField, name: string | number, type?: 'field' | 'group') { makeObservable(this); if (type == null) { const c = typeof name === 'string' ? name.slice(0, 1) : ''; diff --git a/packages/designer/src/designer/setting/setting-top-entry.ts b/packages/designer/src/designer/setting/setting-top-entry.ts index 1c36f8e1bc..5c3c1c250e 100644 --- a/packages/designer/src/designer/setting/setting-top-entry.ts +++ b/packages/designer/src/designer/setting/setting-top-entry.ts @@ -1,7 +1,7 @@ import { IPublicTypeCustomView, IPublicModelEditor } from '@alilc/lowcode-types'; import { isCustomView } from '@alilc/lowcode-utils'; import { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; -import { SettingEntry } from './setting-entry'; +import { ISettingEntry } from './setting-entry'; import { SettingField } from './setting-field'; import { SettingPropEntry } from './setting-prop-entry'; import { INode } from '../../document'; @@ -16,7 +16,7 @@ function generateSessionId(nodes: INode[]) { .join(','); } -export interface ISettingTopEntry extends SettingEntry { +export interface ISettingTopEntry extends ISettingEntry { } export class SettingTopEntry implements ISettingTopEntry { diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index 8972c4ad75..0b470557b3 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -3,7 +3,7 @@ import { shallowIntl, observer, obx, engineConfig, runInAction, globalContext } import { createContent, isJSSlot, isSetterConfig, isSettingField } from '@alilc/lowcode-utils'; import { Skeleton } from '@alilc/lowcode-editor-skeleton'; import { IPublicTypeCustomView } from '@alilc/lowcode-types'; -import { SettingField, SettingTopEntry, SettingEntry, ComponentMeta } from '@alilc/lowcode-designer'; +import { SettingField, SettingTopEntry, ISettingEntry, ComponentMeta } from '@alilc/lowcode-designer'; import { createField } from '../field'; import PopupService, { PopupPipe } from '../popup'; import { SkeletonContext } from '../../context'; @@ -58,7 +58,7 @@ class SettingFieldView extends Component{field.items.map((item, index) => createSettingFieldView(item, field, index))}, @@ -324,7 +324,7 @@ class SettingGroupView extends Component { } } -export function createSettingFieldView(item: SettingField | IPublicTypeCustomView, field: SettingEntry, index?: number) { +export function createSettingFieldView(item: SettingField | IPublicTypeCustomView, field: ISettingEntry, index?: number) { if (isSettingField(item)) { if (item.isGroup) { return ; diff --git a/packages/engine/src/modules/shell-model-factory.ts b/packages/engine/src/modules/shell-model-factory.ts index 05c7b19cb7..bd3f795eb6 100644 --- a/packages/engine/src/modules/shell-model-factory.ts +++ b/packages/engine/src/modules/shell-model-factory.ts @@ -1,5 +1,5 @@ import { - Node as InnerNode, + INode, SettingField as InnerSettingField, } from '@alilc/lowcode-designer'; import { IShellModelFactory, IPublicModelNode, IPublicModelSettingPropEntry } from '@alilc/lowcode-types'; @@ -8,7 +8,7 @@ import { SettingPropEntry, } from '@alilc/lowcode-shell'; class ShellModelFactory implements IShellModelFactory { - createNode(node: InnerNode | null | undefined): IPublicModelNode | null { + createNode(node: INode | null | undefined): IPublicModelNode | null { return Node.create(node); } createSettingPropEntry(prop: InnerSettingField): IPublicModelSettingPropEntry { diff --git a/packages/shell/src/model/setting-prop-entry.ts b/packages/shell/src/model/setting-prop-entry.ts index 88861cac47..94d39a5226 100644 --- a/packages/shell/src/model/setting-prop-entry.ts +++ b/packages/shell/src/model/setting-prop-entry.ts @@ -1,4 +1,4 @@ -import { SettingField, SettingEntry } from '@alilc/lowcode-designer'; +import { SettingField, ISettingEntry } from '@alilc/lowcode-designer'; import { IPublicTypeCompositeValue, IPublicTypeFieldConfig, @@ -233,7 +233,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @returns */ getProps(): IPublicModelSettingTopEntry { - return ShellSettingTopEntry.create(this[settingPropEntrySymbol].getProps() as SettingEntry); + return ShellSettingTopEntry.create(this[settingPropEntrySymbol].getProps() as ISettingEntry); } /** diff --git a/packages/shell/src/model/setting-top-entry.ts b/packages/shell/src/model/setting-top-entry.ts index ddcd16471e..7947baffa6 100644 --- a/packages/shell/src/model/setting-top-entry.ts +++ b/packages/shell/src/model/setting-top-entry.ts @@ -1,17 +1,17 @@ -import { SettingEntry } from '@alilc/lowcode-designer'; +import { ISettingEntry } from '@alilc/lowcode-designer'; import { settingTopEntrySymbol } from '../symbols'; import { Node as ShellNode } from './node'; import { SettingPropEntry as ShellSettingPropEntry } from './setting-prop-entry'; import { IPublicModelSettingTopEntry, IPublicModelNode, IPublicModelSettingPropEntry } from '@alilc/lowcode-types'; export class SettingTopEntry implements IPublicModelSettingTopEntry { - private readonly [settingTopEntrySymbol]: SettingEntry; + private readonly [settingTopEntrySymbol]: ISettingEntry; - constructor(prop: SettingEntry) { + constructor(prop: ISettingEntry) { this[settingTopEntrySymbol] = prop; } - static create(prop: SettingEntry): IPublicModelSettingTopEntry { + static create(prop: ISettingEntry): IPublicModelSettingTopEntry { return new SettingTopEntry(prop); } From 810ef478e5796d50f1cf52eedb0603a714a4f5a9 Mon Sep 17 00:00:00 2001 From: AugustEnd <1543259203@qq.com> Date: Wed, 1 Mar 2023 14:54:41 +0800 Subject: [PATCH 020/469] fix: add protection logic for node-helper.ts when using callbacks --- packages/utils/src/node-helper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/node-helper.ts b/packages/utils/src/node-helper.ts index 1293cec2e1..66a514364e 100644 --- a/packages/utils/src/node-helper.ts +++ b/packages/utils/src/node-helper.ts @@ -23,7 +23,7 @@ export const getClosestNode = ( * @returns {boolean} 是否可点击,true表示可点击 */ export const canClickNode = (node: IPublicModelNode, e: unknown): boolean => { - const onClickHook = node.componentMeta?.advanced.callbacks?.onClickHook; + const onClickHook = node.componentMeta?.advanced?.callbacks?.onClickHook; const canClick = typeof onClickHook === 'function' ? onClickHook(e as MouseEvent, node) : true; return canClick; }; From 9cec5d833c224665bd41f74b20b9014327c6abfa Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 1 Mar 2023 18:32:10 +0800 Subject: [PATCH 021/469] feat: update the ts definition of the shell module --- .eslintrc.js | 1 + .../src/views/tree-branches.tsx | 4 ++-- packages/types/src/shell/api/canvas.ts | 8 ++++++++ packages/types/src/shell/api/material.ts | 17 +++++++++++++++++ packages/types/src/shell/api/workspace.ts | 6 ++++-- packages/types/src/shell/model/node-children.ts | 14 ++++++++++++++ packages/utils/src/schema.ts | 6 +++--- packages/workspace/src/context/base-context.ts | 2 ++ packages/workspace/src/workspace.ts | 10 +++++++--- 9 files changed, 58 insertions(+), 10 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index f3ebedbbef..4f9620d3d8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -48,6 +48,7 @@ module.exports = { "afterLineComment": false, "allowBlockStart": true, }], + "no-unused-vars": ['error', { "destructuredArrayIgnorePattern": "^_" }], "@typescript-eslint/member-ordering": [ "error", { "default": ["signature", "field", "constructor", "method"] } diff --git a/packages/plugin-outline-pane/src/views/tree-branches.tsx b/packages/plugin-outline-pane/src/views/tree-branches.tsx index 9af2dbd096..eb20845082 100644 --- a/packages/plugin-outline-pane/src/views/tree-branches.tsx +++ b/packages/plugin-outline-pane/src/views/tree-branches.tsx @@ -2,7 +2,7 @@ import { Component } from 'react'; import classNames from 'classnames'; import TreeNode from '../controllers/tree-node'; import TreeNodeView from './tree-node'; -import { IPublicModelPluginContext, IPublicModelExclusiveGroup } from '@alilc/lowcode-types'; +import { IPublicModelPluginContext, IPublicModelExclusiveGroup, IPublicTypeDisposable } from '@alilc/lowcode-types'; export default class TreeBranches extends Component<{ treeNode: TreeNode; @@ -73,7 +73,7 @@ class TreeNodeChildren extends Component<{ keywords: null, dropDetail: null, }; - offLocationChanged: () => void; + offLocationChanged: IPublicTypeDisposable; componentDidMount() { const { treeNode, pluginContext } = this.props; const { project } = pluginContext; diff --git a/packages/types/src/shell/api/canvas.ts b/packages/types/src/shell/api/canvas.ts index b7ad196ce3..6cb3df9fc5 100644 --- a/packages/types/src/shell/api/canvas.ts +++ b/packages/types/src/shell/api/canvas.ts @@ -2,12 +2,14 @@ import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, import { IPublicTypeLocationData, IPublicTypeScrollable } from '../type'; /** + * canvas - 画布 API * @since v1.1.0 */ export interface IPublicApiCanvas { /** * 创一个滚动控制器 Scroller,赋予一个视图滚动的基本能力, + * * a Scroller is a controller that gives a view (IPublicTypeScrollable) the ability scrolling * to some cordination by api scrollTo. * @@ -20,6 +22,7 @@ export interface IPublicApiCanvas { /** * 创建一个 ScrollTarget,与 Scroller 一起发挥作用,详见 createScroller 中的描述 + * * this works with Scroller, refer to createScroller`s description * @since v1.1.0 */ @@ -27,6 +30,7 @@ export interface IPublicApiCanvas { /** * 创建一个文档插入位置对象,该对象用来描述一个即将插入的节点在文档中的位置 + * * create a drop location for document, drop location describes a location in document * @since v1.1.0 */ @@ -34,6 +38,7 @@ export interface IPublicApiCanvas { /** * 获取拖拽操作对象的实例 + * * get dragon instance, you can use this to obtain draging related abilities and lifecycle hooks * @since v1.1.0 */ @@ -41,6 +46,7 @@ export interface IPublicApiCanvas { /** * 获取活动追踪器实例 + * * get activeTracker instance, which is a singleton running in engine. * it tracks document`s current focusing node/node[], and notify it`s subscribers that when * focusing node/node[] changed. @@ -50,6 +56,7 @@ export interface IPublicApiCanvas { /** * 是否处于 LiveEditing 状态 + * * check if canvas is in liveEditing state * @since v1.1.0 */ @@ -57,6 +64,7 @@ export interface IPublicApiCanvas { /** * 获取全局剪贴板实例 + * * get clipboard instance * * @since v1.1.0 diff --git a/packages/types/src/shell/api/material.ts b/packages/types/src/shell/api/material.ts index 19e42e4a82..7771aa6baa 100644 --- a/packages/types/src/shell/api/material.ts +++ b/packages/types/src/shell/api/material.ts @@ -76,8 +76,25 @@ export interface IPublicApiMaterial { /** * 在设计器辅助层增加一个扩展 action + * * add an action button in canvas context menu area * @param action + * @example + * ```ts + * import { plugins } from '@alilc/lowcode-engine'; + * import { IPublicModelPluginContext } from '@alilc/lowcode-types'; + * + * const removeCopyAction = (ctx: IPublicModelPluginContext) => { + * return { + * async init() { + * const { removeBuiltinComponentAction } = ctx.material; + * removeBuiltinComponentAction('copy'); + * } + * } + * }; + * removeCopyAction.pluginName = 'removeCopyAction'; + * await plugins.register(removeCopyAction); + * ``` */ addBuiltinComponentAction(action: IPublicTypeComponentAction): void; diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index 8f8b16e39e..c1be4cb7e6 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -1,7 +1,9 @@ import { IPublicModelWindow } from '../model'; import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; -export interface IPublicApiWorkspace { +export interface IPublicApiWorkspace< + Plugins = IPublicApiPlugins +> { /** 是否启用 workspace 模式 */ isActive: boolean; @@ -9,7 +11,7 @@ export interface IPublicApiWorkspace { /** 当前设计器窗口 */ window: IPublicModelWindow; - plugins: IPublicApiPlugins; + plugins: Plugins; /** 当前设计器的编辑窗口 */ windows: IPublicModelWindow[]; diff --git a/packages/types/src/shell/model/node-children.ts b/packages/types/src/shell/model/node-children.ts index ecab5fd338..f2be13250b 100644 --- a/packages/types/src/shell/model/node-children.ts +++ b/packages/types/src/shell/model/node-children.ts @@ -27,6 +27,7 @@ export interface IPublicModelNodeChildren< /** * 是否为空 + * * @returns */ get isEmptyNode(): boolean; @@ -44,6 +45,7 @@ export interface IPublicModelNodeChildren< /** * 删除指定节点 + * * delete the node * @param node */ @@ -51,6 +53,7 @@ export interface IPublicModelNodeChildren< /** * 插入一个节点 + * * insert a node at specific position * @param node 待插入节点 * @param at 插入下标 @@ -60,6 +63,7 @@ export interface IPublicModelNodeChildren< /** * 返回指定节点的下标 + * * get index of node in current children * @param node * @returns @@ -68,6 +72,7 @@ export interface IPublicModelNodeChildren< /** * 类似数组 splice 操作 + * * provide the same function with {Array.prototype.splice} * @param start * @param deleteCount @@ -77,6 +82,7 @@ export interface IPublicModelNodeChildren< /** * 返回指定下标的节点 + * * get node with index * @param index * @returns @@ -85,6 +91,7 @@ export interface IPublicModelNodeChildren< /** * 是否包含指定节点 + * * check if node exists in current children * @param node * @returns @@ -93,6 +100,7 @@ export interface IPublicModelNodeChildren< /** * 类似数组的 forEach + * * provide the same function with {Array.prototype.forEach} * @param fn */ @@ -100,12 +108,14 @@ export interface IPublicModelNodeChildren< /** * 类似数组的 reverse + * * provide the same function with {Array.prototype.reverse} */ reverse(): Node[]; /** * 类似数组的 map + * * provide the same function with {Array.prototype.map} * @param fn */ @@ -141,6 +151,7 @@ export interface IPublicModelNodeChildren< /** * 类似数组的 reduce + * * provide the same function with {Array.prototype.reduce} * @param fn */ @@ -148,6 +159,7 @@ export interface IPublicModelNodeChildren< /** * 导入 schema + * * import schema * @param data */ @@ -155,6 +167,7 @@ export interface IPublicModelNodeChildren< /** * 导出 schema + * * export schema * @param stage */ @@ -162,6 +175,7 @@ export interface IPublicModelNodeChildren< /** * 执行新增、删除、排序等操作 + * * excute remove/add/sort operations * @param remover * @param adder diff --git a/packages/utils/src/schema.ts b/packages/utils/src/schema.ts index 58dfb30458..2e7dec70fa 100644 --- a/packages/utils/src/schema.ts +++ b/packages/utils/src/schema.ts @@ -79,7 +79,7 @@ export function compatibleLegaoSchema(props: any): any { } export function getNodeSchemaById(schema: IPublicTypeNodeSchema, nodeId: string): IPublicTypeNodeSchema | undefined { - let found: NodeSIPublicTypeNodeSchemachema | undefined; + let found: IPublicTypeNodeSchema | undefined; if (schema.id === nodeId) { return schema; } @@ -100,7 +100,7 @@ export function getNodeSchemaById(schema: IPublicTypeNodeSchema, nodeId: string) function getNodeSchemaFromPropsById(props: any, nodeId: string): IPublicTypeNodeSchema | undefined { let found: IPublicTypeNodeSchema | undefined; - for (const [key, value] of Object.entries(props)) { + for (const [_key, value] of Object.entries(props)) { if (isJSSlot(value)) { // value 是数组类型 { type: 'JSSlot', value: IPublicTypeNodeSchema[] } if (Array.isArray(value.value)) { @@ -123,7 +123,7 @@ function getNodeSchemaFromPropsById(props: any, nodeId: string): IPublicTypeNode * TODO: not sure if this is used anywhere * @deprecated */ -export function applyActivities(pivotSchema: IPublicTypeRootSchema, activities: any, options?: any): IPublicTypeRootSchema { +export function applyActivities(pivotSchema: IPublicTypeRootSchema, activities: any): IPublicTypeRootSchema { let schema = { ...pivotSchema }; if (!Array.isArray(activities)) { activities = [activities]; diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index 37ce7fafad..b67842fe8d 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -30,6 +30,7 @@ import { import { IPluginPreferenceMananger, IPublicApiEvent, + IPublicApiWorkspace, IPublicModelPluginContext, IPublicTypePluginMeta, } from '@alilc/lowcode-types'; @@ -59,6 +60,7 @@ export class BasicContext implements IPublicModelPluginContext { canvas: Canvas; pluginEvent: IPublicApiEvent; preference: IPluginPreferenceMananger; + workspace: IPublicApiWorkspace; constructor(innerWorkspace: InnerWorkspace, viewName: string, public editorWindow?: EditorWindow) { const editor = new Editor(viewName, true); diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 0b7181cd87..f7d49ed49e 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -1,4 +1,4 @@ -import { Designer } from '@alilc/lowcode-designer'; +import { Designer, LowCodePluginManager } from '@alilc/lowcode-designer'; import { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; import { Plugins } from '@alilc/lowcode-shell'; import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types'; @@ -15,7 +15,11 @@ enum event { const CHANGE_EVENT = 'resource.list.change'; -export class Workspace implements IPublicApiWorkspace { +interface IWorkspace extends Omit, 'resourceList'> {} + +export class Workspace implements IWorkspace { context: BasicContext; private emitter: IEventBus = createModuleEventBus('workspace'); @@ -134,7 +138,7 @@ export class Workspace implements IPublicApiWorkspace { this.emitChangeWindow(); } - removeEditorWindow(resourceName: string, title: string) { + removeEditorWindow(resourceName: string) { const index = this.windows.findIndex(d => (d.resource.name === resourceName && d.title)); this.remove(index); } From 9228a2baa702eb72eb556967c25a73d175c534bd Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 1 Mar 2023 16:49:39 +0800 Subject: [PATCH 022/469] feat: lowcode component add error placeholder --- .../react-simulator-renderer/src/renderer.ts | 119 +++++++++--------- .../renderer-core/src/renderer/renderer.tsx | 12 +- packages/renderer-core/src/types/index.ts | 8 +- 3 files changed, 74 insertions(+), 65 deletions(-) diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index e76bfb5855..7661500280 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -39,10 +39,6 @@ export class DocumentInstance { private disposeFunctions: Array<() => void> = []; - constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) { - makeObservable(this); - } - @obx.ref private _components: any = {}; @computed get components(): object { @@ -98,6 +94,10 @@ export class DocumentInstance { return this.document.id; } + constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) { + makeObservable(this); + } + private unmountInstance(id: string, instance: ReactInstance) { const instances = this.instancesMap.get(id); if (instances) { @@ -170,8 +170,7 @@ export class DocumentInstance { host.setInstance(this.document.id, id, instances); } - mountContext(docId: string, id: string, ctx: object) { - // this.ctxMap.set(id, ctx); + mountContext() { } getNode(id: string): Node | null { @@ -195,6 +194,60 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { return this._documentInstances; } + @obx private _layout: any = null; + + @computed get layout(): any { + // TODO: parse layout Component + return this._layout; + } + + set layout(value: any) { + this._layout = value; + } + + private _libraryMap: { [key: string]: string } = {}; + + private _components: any = {}; + + get components(): object { + // 根据 device 选择不同组件,进行响应式 + // 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl + return this._components; + } + // context from: utils、constants、history、location、match + @obx.ref private _appContext: any = {}; + @computed get context(): any { + return this._appContext; + } + @obx.ref private _designMode: string = 'design'; + @computed get designMode(): any { + return this._designMode; + } + @obx.ref private _device: string = 'default'; + @computed get device() { + return this._device; + } + @obx.ref private _locale: string | undefined = undefined; + @computed get locale() { + return this._locale; + } + @obx.ref private _componentsMap = {}; + @computed get componentsMap(): any { + return this._componentsMap; + } + + /** + * 是否为画布自动渲染 + */ + autoRender = true; + + /** + * 画布是否自动监听事件来重绘节点 + */ + autoRepaintNode = true; + + private _running = false; + constructor() { makeObservable(this); this.autoRender = host.autoRender; @@ -306,19 +359,6 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { }); } - @obx private _layout: any = null; - - @computed get layout(): any { - // TODO: parse layout Component - return this._layout; - } - - set layout(value: any) { - this._layout = value; - } - - private _libraryMap: { [key: string]: string } = {}; - private buildComponents() { this._components = buildComponents( this._libraryMap, @@ -330,44 +370,6 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { ...this._components, }; } - private _components: any = {}; - - get components(): object { - // 根据 device 选择不同组件,进行响应式 - // 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl - return this._components; - } - // context from: utils、constants、history、location、match - @obx.ref private _appContext: any = {}; - @computed get context(): any { - return this._appContext; - } - @obx.ref private _designMode: string = 'design'; - @computed get designMode(): any { - return this._designMode; - } - @obx.ref private _device: string = 'default'; - @computed get device() { - return this._device; - } - @obx.ref private _locale: string | undefined = undefined; - @computed get locale() { - return this._locale; - } - @obx.ref private _componentsMap = {}; - @computed get componentsMap(): any { - return this._componentsMap; - } - - /** - * 是否为画布自动渲染 - */ - autoRender = true; - - /** - * 画布是否自动监听事件来重绘节点 - */ - autoRepaintNode = true; /** * 加载资源 @@ -457,6 +459,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { appHelper: renderer.context, rendererName: 'LowCodeRenderer', thisRequiredInJSE: host.thisRequiredInJSE, + faultComponent: host.faultComponent, customCreateElement: (Comp: any, props: any, children: any) => { const componentMeta = host.currentDocument?.getComponentMeta(Comp.displayName); if (componentMeta?.isModal) { @@ -479,8 +482,6 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { return LowCodeComp; } - private _running = false; - run() { if (this._running) { return; diff --git a/packages/renderer-core/src/renderer/renderer.tsx b/packages/renderer-core/src/renderer/renderer.tsx index c0f1c2afc6..d936b7d91f 100644 --- a/packages/renderer-core/src/renderer/renderer.tsx +++ b/packages/renderer-core/src/renderer/renderer.tsx @@ -86,8 +86,9 @@ export default function rendererFactory(): IRenderComponent { debug(`entry.componentWillUnmount - ${this.props?.schema?.componentName}`); } - async componentDidCatch(e: any) { - console.warn(e); + componentDidCatch(error: Error) { + this.state.engineRenderError = true; + this.state.error = error; } shouldComponentUpdate(nextProps: IRendererProps) { @@ -182,6 +183,13 @@ export default function rendererFactory(): IRenderComponent { } } + if (this.state && this.state.engineRenderError) { + return createElement(this.getFaultComponent(), { + ...this.props, + error: this.state.error, + }); + } + if (Comp) { return createElement(AppContext.Provider, { value: { appHelper, diff --git a/packages/renderer-core/src/types/index.ts b/packages/renderer-core/src/types/index.ts index 4e44dd312f..067bf21533 100644 --- a/packages/renderer-core/src/types/index.ts +++ b/packages/renderer-core/src/types/index.ts @@ -323,10 +323,10 @@ export interface IRenderComponent { new(props: IRendererProps, context: any): IGeneralComponent & { [x: string]: any; __getRef: (ref: any) => void; - componentDidMount(): Promise; - componentDidUpdate(): Promise; - componentWillUnmount(): Promise; - componentDidCatch(e: any): Promise; + componentDidMount(): Promise | void; + componentDidUpdate(): Promise | void; + componentWillUnmount(): Promise | void; + componentDidCatch(e: any): Promise | void; shouldComponentUpdate(nextProps: IRendererProps): boolean; isValidComponent(SetComponent: any): any; patchDidCatch(SetComponent: any): void; From a2d857b143ac11342ba076bebc02e05618b31f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= Date: Thu, 2 Mar 2023 10:38:31 +0800 Subject: [PATCH 023/469] feat: add file name as the third argument which passed to module post processor --- .eslintrc.js | 26 ++++++++--------- .../src/generator/ModuleBuilder.ts | 5 ++-- modules/code-generator/src/types/core.ts | 29 ++++++++----------- 3 files changed, 27 insertions(+), 33 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 1ec3834e6a..eba1bac041 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -15,7 +15,6 @@ module.exports = { 'no-prototype-builtins': 1, 'no-useless-constructor': 1, 'no-empty-function': 1, - '@typescript-eslint/member-ordering': 0, 'lines-between-class-members': 0, 'no-await-in-loop': 0, 'no-plusplus': 0, @@ -35,22 +34,23 @@ module.exports = { '@typescript-eslint/indent': 0, 'import/no-cycle': 0, '@typescript-eslint/no-shadow': 0, - "@typescript-eslint/method-signature-style": 0, - "@typescript-eslint/consistent-type-assertions": 0, - "@typescript-eslint/no-useless-constructor": 0, + '@typescript-eslint/method-signature-style': 0, + '@typescript-eslint/consistent-type-assertions': 0, + '@typescript-eslint/no-useless-constructor': 0, '@typescript-eslint/dot-notation': 0, // for lint performance '@typescript-eslint/restrict-plus-operands': 0, // for lint performance 'no-unexpected-multiline': 1, - 'no-multiple-empty-lines': ['error', { "max": 1 }], + 'no-multiple-empty-lines': ['error', { max: 1 }], 'lines-around-comment': ['error', { - "beforeBlockComment": true, - "afterBlockComment": false, - "afterLineComment": false, - "allowBlockStart": true, + beforeBlockComment: true, + afterBlockComment: false, + afterLineComment: false, + allowBlockStart: true, }], - "@typescript-eslint/member-ordering": [ - "error", - { "default": ["signature", "field", "constructor", "method"] } + 'comma-dangle': ['error', 'always-multiline'], + '@typescript-eslint/member-ordering': [ + 'error', + { default: ['signature', 'field', 'constructor', 'method'] }, ], - } + }, }; \ No newline at end of file diff --git a/modules/code-generator/src/generator/ModuleBuilder.ts b/modules/code-generator/src/generator/ModuleBuilder.ts index 755ca20c6c..e172f716e5 100644 --- a/modules/code-generator/src/generator/ModuleBuilder.ts +++ b/modules/code-generator/src/generator/ModuleBuilder.ts @@ -62,10 +62,9 @@ export function createModuleBuilder( if (options.postProcessors.length > 0) { files = files.map((file) => { - let { content } = file; - const type = file.ext; + let { content, ext: type, name } = file; options.postProcessors.forEach((processer) => { - content = processer(content, type); + content = processer(content, type, name); }); return createResultFile(file.name, type, content); diff --git a/modules/code-generator/src/types/core.ts b/modules/code-generator/src/types/core.ts index 30c86a7e9e..1a85db965d 100644 --- a/modules/code-generator/src/types/core.ts +++ b/modules/code-generator/src/types/core.ts @@ -1,20 +1,15 @@ import { - IPublicTypeJSONArray, - IPublicTypeJSONObject, IPublicTypeCompositeArray, - IPublicTypeCompositeObject, - ResultDir, + IPublicTypeCompositeObject, IPublicTypeJSExpression, + IPublicTypeJSFunction, IPublicTypeJSONArray, + IPublicTypeJSONObject, IPublicTypeJSSlot, IPublicTypeNodeDataType, + IPublicTypeProjectSchema, ResultDir, ResultFile, - IPublicTypeNodeDataType, - IPublicTypeProjectSchema, - IPublicTypeJSExpression, - IPublicTypeJSFunction, - IPublicTypeJSSlot, } from '@alilc/lowcode-types'; -import { IParseResult } from './intermediate'; -import { IScopeBindings } from '../utils/ScopeBindings'; import type { ProjectBuilderInitOptions } from '../generator/ProjectBuilder'; +import { IScopeBindings } from '../utils/ScopeBindings'; +import { IParseResult } from './intermediate'; export enum FileType { CSS = 'css', @@ -69,16 +64,16 @@ export interface ICodeStruct extends IBaseCodeStruct { /** 上下文数据,用来在插件之间共享一些数据 */ export interface IContextData extends IProjectBuilderOptions { - /** - * 是否使用了 Ref 的 API (this.$/this.$$) - * */ - useRefApi?: boolean; - /** * 其他自定义数据 * (三方自定义插件也可以在此放一些数据,建议起个长一点的名称,用自己的插件名做前缀,以防冲突) */ [key: string]: any; + + /** + * 是否使用了 Ref 的 API (this.$/this.$$) + * */ + useRefApi?: boolean; } export type BuilderComponentPlugin = (initStruct: ICodeStruct) => Promise; @@ -202,7 +197,7 @@ export type ProjectPostProcessor = ( export type PostProcessorFactory = (config?: T) => PostProcessor; /** 模块级别的后置处理器 */ -export type PostProcessor = (content: string, fileType: string) => string; +export type PostProcessor = (content: string, fileType: string, name: string) => string; // TODO: temp interface, need modify export interface IPluginOptions { From 964833128b92aafe3266f5096b3d83e7af261372 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 28 Feb 2023 17:41:19 +0800 Subject: [PATCH 024/469] feat: add getDOMNode api definition in node module --- docs/docs/api/model/node.md | 11 ++ packages/designer/jest.config.js | 1 + packages/designer/src/designer/designer.ts | 2 + .../src/designer/setting/setting-top-entry.ts | 1 + .../designer/src/document/document-model.ts | 18 +- .../src/document/node/exclusive-group.ts | 50 +++-- .../src/document/node/node-children.ts | 8 +- packages/designer/src/document/node/node.ts | 170 ++++++++--------- .../designer/src/document/node/props/prop.ts | 10 +- .../designer/src/document/node/props/props.ts | 8 +- .../document-model/document-model.test.ts | 2 +- .../tests/document/node/node.add.test.ts | 174 +++++++++--------- packages/shell/src/model/condition-group.ts | 42 +++++ packages/shell/src/model/node.ts | 12 +- packages/shell/src/symbols.ts | 1 + .../types/src/shell/model/exclusive-group.ts | 12 +- packages/types/src/shell/model/node.ts | 26 ++- packages/types/src/shell/model/prop.ts | 8 +- packages/types/src/shell/type/metadata.ts | 4 +- packages/utils/src/check-types/is-dom-text.ts | 2 +- .../utils/src/check-types/is-node-schema.ts | 2 +- 21 files changed, 335 insertions(+), 229 deletions(-) create mode 100644 packages/shell/src/model/condition-group.ts diff --git a/docs/docs/api/model/node.md b/docs/docs/api/model/node.md index 333e973f01..bbf8e559ff 100644 --- a/docs/docs/api/model/node.md +++ b/docs/docs/api/model/node.md @@ -645,3 +645,14 @@ setConditionalVisible(): void; ``` **@since v1.1.0** + +### getDOMNode +获取节点实例对应的 dom 节点 + +```typescript +/** + * 获取节点实例对应的 dom 节点 + */ +getDOMNode(): HTMLElement; + +``` \ No newline at end of file diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index 788c0ac79a..594eb6f365 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -15,6 +15,7 @@ const jestConfig = { // testMatch: ['**/document-model.test.ts'], // testMatch: ['**/prop.test.ts'], // testMatch: ['(/tests?/.*(test))\\.[jt]s$'], + // testMatch: ['**/document/node/node.add.test.ts'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index d40082d82f..3e2ff6dd21 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -71,6 +71,8 @@ export interface IDesigner { get editor(): IPublicModelEditor; + get detecting(): Detecting; + createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller; /** diff --git a/packages/designer/src/designer/setting/setting-top-entry.ts b/packages/designer/src/designer/setting/setting-top-entry.ts index 5c3c1c250e..04f00afc31 100644 --- a/packages/designer/src/designer/setting/setting-top-entry.ts +++ b/packages/designer/src/designer/setting/setting-top-entry.ts @@ -17,6 +17,7 @@ function generateSessionId(nodes: INode[]) { } export interface ISettingTopEntry extends ISettingEntry { + purge(): void; } export class SettingTopEntry implements ISettingTopEntry { diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 63fe094db7..7c4344c31e 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -87,6 +87,8 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel< get active(): boolean; + get nodesMap(): Map; + /** * 根据 id 获取节点 */ @@ -114,6 +116,12 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel< onChangeNodeVisible(fn: (node: INode, visible: boolean) => void): IPublicTypeDisposable; addWillPurge(node: INode): void; + + removeWillPurge(node: INode): void; + + getComponentMeta(componentName: string): IComponentMeta; + + insertNodes(parent: INode, thing: INode[] | IPublicTypeNodeData[], at?: number | null, copy?: boolean): INode[]; } export class DocumentModel implements IDocumentModel { @@ -379,7 +387,7 @@ export class DocumentModel implements IDocumentModel { * 根据 schema 创建一个节点 */ @action - createNode(data: GetDataType, checkId: boolean = true): T { + createNode(data: GetDataType): T { let schema: any; if (isDOMText(data) || isJSExpression(data)) { schema = { @@ -410,7 +418,7 @@ export class DocumentModel implements IDocumentModel { } } if (!node) { - node = new Node(this, schema, { checkId }); + node = new Node(this, schema); // will add // todo: this.activeNodes?.push(node); } @@ -429,7 +437,7 @@ export class DocumentModel implements IDocumentModel { /** * 插入一个节点 */ - insertNode(parent: INode, thing: INode | IPublicTypeNodeData, at?: number | null, copy?: boolean): INode { + insertNode(parent: INode, thing: INode | IPublicTypeNodeData, at?: number | null, copy?: boolean): INode | null { return insertChild(parent, thing, at, copy); } @@ -445,7 +453,7 @@ export class DocumentModel implements IDocumentModel { */ removeNode(idOrNode: string | INode) { let id: string; - let node: INode | null; + let node: INode | null = null; if (typeof idOrNode === 'string') { id = idOrNode; node = this.getNode(id); @@ -859,7 +867,7 @@ export class DocumentModel implements IDocumentModel { onReady(fn: Function) { this.designer.editor.eventBus.on('document-open', fn); return () => { - this.designer.editor.removeListener('document-open', fn); + this.designer.editor.eventBus.off('document-open', fn); }; } diff --git a/packages/designer/src/document/node/exclusive-group.ts b/packages/designer/src/document/node/exclusive-group.ts index 014715fd1b..8cf9930950 100644 --- a/packages/designer/src/document/node/exclusive-group.ts +++ b/packages/designer/src/document/node/exclusive-group.ts @@ -1,18 +1,30 @@ import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core'; import { uniqueId } from '@alilc/lowcode-utils'; import { IPublicTypeTitleContent, IPublicModelExclusiveGroup } from '@alilc/lowcode-types'; -import { Node } from './node'; +import { INode } from './node'; import { intl } from '../../locale'; +export interface IExclusiveGroup extends IPublicModelExclusiveGroup { + readonly name: string; + + remove(node: INode): void; + + add(node: INode): void; + + isVisible(node: INode): boolean; +} + // modals assoc x-hide value, initial: check is Modal, yes will put it in modals, cross levels // if-else-if assoc conditionGroup value, should be the same level, // and siblings, need renderEngine support -export class ExclusiveGroup implements IPublicModelExclusiveGroup { +export class ExclusiveGroup implements IExclusiveGroup { readonly isExclusiveGroup = true; readonly id = uniqueId('exclusive'); - @obx.shallow readonly children: Node[] = []; + readonly title: IPublicTypeTitleContent; + + @obx.shallow readonly children: INode[] = []; @obx private visibleIndex = 0; @@ -28,11 +40,11 @@ export class ExclusiveGroup implements IPublicModelExclusiveGroup { return this.children.length; } - @computed get visibleNode(): Node { + @computed get visibleNode(): INode { return this.children[this.visibleIndex]; } - @computed get firstNode(): Node { + @computed get firstNode(): INode { return this.children[0]!; } @@ -40,8 +52,16 @@ export class ExclusiveGroup implements IPublicModelExclusiveGroup { return this.firstNode.index; } - add(node: Node) { - if (node.nextSibling && node.nextSibling.conditionGroup === this) { + constructor(readonly name: string, title?: IPublicTypeTitleContent) { + makeObservable(this); + this.title = title || { + type: 'i18n', + intl: intl('Condition Group'), + }; + } + + add(node: INode) { + if (node.nextSibling && node.nextSibling.conditionGroup?.id === this.id) { const i = this.children.indexOf(node.nextSibling); this.children.splice(i, 0, node); } else { @@ -49,7 +69,7 @@ export class ExclusiveGroup implements IPublicModelExclusiveGroup { } } - remove(node: Node) { + remove(node: INode) { const i = this.children.indexOf(node); if (i > -1) { this.children.splice(i, 1); @@ -61,27 +81,17 @@ export class ExclusiveGroup implements IPublicModelExclusiveGroup { } } - setVisible(node: Node) { + setVisible(node: INode) { const i = this.children.indexOf(node); if (i > -1) { this.visibleIndex = i; } } - isVisible(node: Node) { + isVisible(node: INode) { const i = this.children.indexOf(node); return i === this.visibleIndex; } - - readonly title: IPublicTypeTitleContent; - - constructor(readonly name: string, title?: IPublicTypeTitleContent) { - makeObservable(this); - this.title = title || { - type: 'i18n', - intl: intl('Condition Group'), - }; - } } export function isExclusiveGroup(obj: any): obj is ExclusiveGroup { diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index ff85b2231d..51e921a935 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -1,6 +1,6 @@ import { obx, computed, globalContext, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { Node, INode } from './node'; -import { IPublicTypeNodeData, IPublicModelNodeChildren, IPublicEnumTransformStage } from '@alilc/lowcode-types'; +import { IPublicTypeNodeData, IPublicModelNodeChildren, IPublicEnumTransformStage, IPublicTypeDisposable } from '@alilc/lowcode-types'; import { shallowEqual, compatStage, isNodeSchema } from '@alilc/lowcode-utils'; import { foreachReverse } from '../../utils/tree'; import { NodeRemoveOptions } from '../../types'; @@ -18,6 +18,8 @@ export interface INodeChildren extends Omit, > { get owner(): INode; + get length(): number; + unlinkChild(node: INode): void; /** @@ -58,6 +60,8 @@ export interface INodeChildren extends Omit, internalInitParent(): void; + onChange(fn: (info?: IOnChangeOptions) => void): IPublicTypeDisposable; + /** overriding methods end */ } export class NodeChildren implements INodeChildren { @@ -478,7 +482,7 @@ export class NodeChildren implements INodeChildren { } } - onChange(fn: (info?: IOnChangeOptions) => void): () => void { + onChange(fn: (info?: IOnChangeOptions) => void): IPublicTypeDisposable { this.emitter.on('change', fn); return () => { this.emitter.removeListener('change', fn); diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index efa860c8db..77f5bddd40 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -18,14 +18,14 @@ import { IPublicTypeDisposable, IBaseModelNode, } from '@alilc/lowcode-types'; -import { compatStage, isDOMText, isJSExpression, isNode } from '@alilc/lowcode-utils'; -import { ISettingTopEntry, SettingTopEntry } from '@alilc/lowcode-designer'; +import { compatStage, isDOMText, isJSExpression, isNode, isNodeSchema } from '@alilc/lowcode-utils'; +import { ISettingTopEntry } from '@alilc/lowcode-designer'; import { Props, getConvertedExtraKey, IProps } from './props/props'; -import { DocumentModel, IDocumentModel } from '../document-model'; +import { IDocumentModel } from '../document-model'; import { NodeChildren, INodeChildren } from './node-children'; import { IProp, Prop } from './props/prop'; -import { ComponentMeta, IComponentMeta } from '../../component-meta'; -import { ExclusiveGroup, isExclusiveGroup } from './exclusive-group'; +import { IComponentMeta } from '../../component-meta'; +import { ExclusiveGroup, IExclusiveGroup, isExclusiveGroup } from './exclusive-group'; import { includeSlot, removeSlot } from '../../utils/slot'; import { foreachReverse } from '../../utils/tree'; import { NodeRemoveOptions, EDITOR_EVENT } from '../../types'; @@ -42,14 +42,11 @@ export interface INode extends Omit, - 'slots' | - 'slotFor' | - 'props' | - 'getProp' | - 'getExtraProp' | - 'replaceChild' | 'isRoot' | 'isPage' | 'isComponent' | @@ -64,29 +61,21 @@ export interface INode extends Omit { - get slots(): INode[]; - - /** - * 关联属性 - */ - get slotFor(): IProp | null; - - get props(): IProps; + isNode: boolean; get componentMeta(): IComponentMeta; - get settingEntry(): SettingTopEntry; + get settingEntry(): ISettingTopEntry; get isPurged(): boolean; - setVisible(flag: boolean): void; + get index(): number | undefined; - getVisible(): boolean; + get isPurging(): boolean; /** * 内部方法,请勿使用 @@ -100,7 +89,7 @@ export interface INode extends Omit any): () => void; - getProp(path: string, createIfNone?: boolean): IProp | null; - - getExtraProp(key: string, createIfNone?: boolean): IProp | null; - - replaceChild(node: INode, data: any): INode; - getSuitablePlace(node: INode, ref: any): any; - onChildrenChange(fn: (param?: { type: string; node: INode }) => void): IPublicTypeDisposable; + onChildrenChange(fn: (param?: { type: string; node: INode }) => void): IPublicTypeDisposable | undefined; onPropChange(func: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable; @@ -153,13 +136,17 @@ export interface INode extends Omit return !!this._isRGLContainer; } - private _slotFor?: IProp | null = null; + get isEmptyNode() { + return this.isEmpty(); + } + + private _slotFor?: IProp | null | undefined = null; @obx.shallow _slots: INode[] = []; @@ -331,10 +322,10 @@ export class Node } /* istanbul ignore next */ - @obx.ref private _conditionGroup: IPublicModelExclusiveGroup | null = null; + @obx.ref private _conditionGroup: IExclusiveGroup | null = null; /* istanbul ignore next */ - get conditionGroup(): IPublicModelExclusiveGroup | null { + get conditionGroup(): IExclusiveGroup | null { return this._conditionGroup; } @@ -518,7 +509,7 @@ export class Node this.document.addWillPurge(this); } - didDropIn(dragment: Node) { + didDropIn(dragment: INode) { const { callbacks } = this.componentMeta.advanced; if (callbacks?.onNodeAdd) { const cbThis = this.internalToShellNode(); @@ -529,7 +520,7 @@ export class Node } } - didDropOut(dragment: Node) { + didDropOut(dragment: INode) { const { callbacks } = this.componentMeta.advanced; if (callbacks?.onNodeRemove) { const cbThis = this.internalToShellNode(); @@ -590,7 +581,7 @@ export class Node /** * 关联属性 */ - get slotFor(): IProp | null { + get slotFor(): IProp | null | undefined { return this._slotFor; } @@ -610,10 +601,10 @@ export class Node }); } if (this.isSlot()) { - this.parent.removeSlot(this, purge); - this.parent.children.internalDelete(this, purge, useMutator, { suppressRemoveEvent: true }); + this.parent.removeSlot(this); + this.parent.children?.internalDelete(this, purge, useMutator, { suppressRemoveEvent: true }); } else { - this.parent.children.internalDelete(this, purge, useMutator, { suppressRemoveEvent: true }); + this.parent.children?.internalDelete(this, purge, useMutator, { suppressRemoveEvent: true }); } } } @@ -653,7 +644,7 @@ export class Node /** * 节点组件描述 */ - @computed get componentMeta(): ComponentMeta { + @computed get componentMeta(): IComponentMeta { return this.document.getComponentMeta(this.componentName); } @@ -670,6 +661,7 @@ export class Node /* istanbul ignore next */ setConditionGroup(grp: IPublicModelExclusiveGroup | string | null) { + let _grp: IExclusiveGroup | null = null; if (!grp) { this.getExtraProp('conditionGroup', false)?.remove(); if (this._conditionGroup) { @@ -680,20 +672,20 @@ export class Node } if (!isExclusiveGroup(grp)) { if (this.prevSibling?.conditionGroup?.name === grp) { - grp = this.prevSibling.conditionGroup; + _grp = this.prevSibling.conditionGroup; } else if (this.nextSibling?.conditionGroup?.name === grp) { - grp = this.nextSibling.conditionGroup; - } else { - grp = new ExclusiveGroup(grp); + _grp = this.nextSibling.conditionGroup; + } else if (typeof grp === 'string') { + _grp = new ExclusiveGroup(grp); } } - if (this._conditionGroup !== grp) { - this.getExtraProp('conditionGroup', true)?.setValue(grp.name); + if (_grp && this._conditionGroup !== _grp) { + this.getExtraProp('conditionGroup', true)?.setValue(_grp.name); if (this._conditionGroup) { this._conditionGroup.remove(this); } - this._conditionGroup = grp; - grp.add(this); + this._conditionGroup = _grp; + _grp?.add(this); } } @@ -749,13 +741,17 @@ export class Node * @param {INode} node * @param {object} data */ - replaceChild(node: INode, data: any): INode { + replaceChild(node: INode, data: any): INode | null { if (this.children?.has(node)) { const selected = this.document.selection.has(node.id); delete data.id; const newNode = this.document.createNode(data); + if (!isNode(newNode)) { + return null; + } + this.insertBefore(newNode, node, false); node.remove(false); @@ -838,39 +834,45 @@ export class Node /** * 获取节点在父容器中的索引 */ - @computed get index(): number { + @computed get index(): number | undefined { if (!this.parent) { return -1; } - return this.parent.children.indexOf(this); + return this.parent.children?.indexOf(this); } /** * 获取下一个兄弟节点 */ - get nextSibling(): INode | null { + get nextSibling(): INode | null | undefined { if (!this.parent) { return null; } const { index } = this; + if (typeof index !== 'number') { + return null; + } if (index < 0) { return null; } - return this.parent.children.get(index + 1); + return this.parent.children?.get(index + 1); } /** * 获取上一个兄弟节点 */ - get prevSibling(): INode | null { + get prevSibling(): INode | null | undefined { if (!this.parent) { return null; } const { index } = this; + if (typeof index !== 'number') { + return null; + } if (index < 1) { return null; } - return this.parent.children.get(index - 1); + return this.parent.children?.get(index - 1); } /** @@ -889,7 +891,7 @@ export class Node if (this.isSlot()) { foreachReverse( this.children!, - (subNode: Node) => { + (subNode: INode) => { subNode.remove(true, true); }, (iterable, idx) => (iterable as NodeChildren).get(idx), @@ -954,7 +956,7 @@ export class Node ...this.document.designer.transformProps(_extras_, this, stage), }; - if (this.isParental() && this.children.size > 0 && !options.bypassChildren) { + if (this.isParental() && this.children && this.children.size > 0 && !options.bypassChildren) { schema.children = this.children.export(stage); } @@ -971,7 +973,7 @@ export class Node /** * 获取特定深度的父亲节点 */ - getZLevelTop(zLevel: number): Node | null { + getZLevelTop(zLevel: number): INode | null { return getZLevelTop(this, zLevel); } @@ -983,11 +985,11 @@ export class Node * 2 thisNode before or after otherNode * 0 thisNode same as otherNode */ - comparePosition(otherNode: Node): PositionNO { + comparePosition(otherNode: INode): PositionNO { return comparePosition(this, otherNode); } - unlinkSlot(slotNode: Node) { + unlinkSlot(slotNode: INode) { const i = this._slots.indexOf(slotNode); if (i < 0) { return false; @@ -998,7 +1000,7 @@ export class Node /** * 删除一个Slot节点 */ - removeSlot(slotNode: Node): boolean { + removeSlot(slotNode: INode): boolean { // if (purge) { // // should set parent null // slotNode?.internalSetParent(null, false); @@ -1039,7 +1041,7 @@ export class Node * 删除一个节点 * @param node */ - removeChild(node: Node) { + removeChild(node: INode) { this.children?.delete(node); } @@ -1090,7 +1092,7 @@ export class Node return this.componentName; } - insert(node: Node, ref?: INode, useMutator = true) { + insert(node: INode, ref?: INode, useMutator = true) { this.insertAfter(node, ref, useMutator); } @@ -1101,7 +1103,7 @@ export class Node insertAfter(node: any, ref?: INode, useMutator = true) { const nodeInstance = ensureNode(node, this.document); - this.children?.internalInsert(nodeInstance, ref ? ref.index + 1 : null, useMutator); + this.children?.internalInsert(nodeInstance, ref ? (ref.index || 0) + 1 : null, useMutator); } getParent() { @@ -1128,7 +1130,7 @@ export class Node return this.props; } - onChildrenChange(fn: (param?: { type: string; node: INode }) => void): IPublicTypeDisposable { + onChildrenChange(fn: (param?: { type: string; node: INode }) => void): IPublicTypeDisposable | undefined { const wrappedFunc = wrapWithEventSwitch(fn); return this.children?.onChange(wrappedFunc); } @@ -1330,7 +1332,7 @@ export class Node } } -function ensureNode(node: any, document: DocumentModel): Node { +function ensureNode(node: any, document: IDocumentModel): INode { let nodeInstance = node; if (!isNode(node)) { if (node.getComponentName) { @@ -1443,20 +1445,24 @@ export function insertChild( thing: INode | IPublicTypeNodeData, at?: number | null, copy?: boolean, -): INode { - let node: INode; - if (isNode(thing) && (copy || thing.isSlot())) { - thing = thing.export(IPublicEnumTransformStage.Clone); - } - if (isNode(thing)) { +): INode | null { + let node: INode | null | RootNode | undefined; + let nodeSchema: IPublicTypeNodeSchema; + if (isNode(thing) && (copy || thing.isSlot())) { + nodeSchema = thing.export(IPublicEnumTransformStage.Clone); + node = container.document?.createNode(nodeSchema); + } else if (isNode(thing)) { node = thing; - } else { - node = container.document.createNode(thing); + } else if (isNodeSchema(thing)) { + node = container.document?.createNode(thing); } - container.children.insert(node, at); + if (isNode(node)) { + container.children?.insert(node, at); + return node; + } - return node; + return null; } export function insertChildren( diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 90d72668a3..bb6797d456 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -11,14 +11,14 @@ export const UNSET = Symbol.for('unset'); // eslint-disable-next-line no-redeclare export type UNSET = typeof UNSET; -export interface IProp extends Omit { +export interface IProp extends Omit, 'exportSchema' | 'node' > { readonly props: IProps; readonly owner: INode; - get slotNode(): INode | null; - delete(prop: Prop): void; export(stage: IPublicEnumTransformStage): IPublicTypeCompositeValue; @@ -26,6 +26,10 @@ export interface IProp extends Omit, | 'getExtraProp' | 'getExtraPropValue' | 'setExtraPropValue' | 'node'> { @@ -52,6 +50,12 @@ export interface IProps extends Omit, | 'getExtraProp' | }; merge(value: IPublicTypePropsMap, extras?: IPublicTypePropsMap): void; + + purge(): void; + + query(path: string, createIfNone: boolean): Prop | null; + + import(value?: IPublicTypePropsMap | IPublicTypePropsList | null, extras?: ExtrasObject): void; } export class Props implements IProps, IPropParent { diff --git a/packages/designer/tests/document/document-model/document-model.test.ts b/packages/designer/tests/document/document-model/document-model.test.ts index 753c840a58..b47200cbaf 100644 --- a/packages/designer/tests/document/document-model/document-model.test.ts +++ b/packages/designer/tests/document/document-model/document-model.test.ts @@ -23,7 +23,7 @@ describe('document-model 测试', () => { it('empty schema', () => { const doc = new DocumentModel(project); - expect(doc.rootNode.id).toBe('root'); + expect(doc.rootNode?.id).toBe('root'); expect(doc.currentRoot).toBe(doc.rootNode); expect(doc.root).toBe(doc.rootNode); expect(doc.modalNode).toBeUndefined(); diff --git a/packages/designer/tests/document/node/node.add.test.ts b/packages/designer/tests/document/node/node.add.test.ts index bede021969..87a4222cd0 100644 --- a/packages/designer/tests/document/node/node.add.test.ts +++ b/packages/designer/tests/document/node/node.add.test.ts @@ -1,8 +1,8 @@ import set from 'lodash/set'; import cloneDeep from 'lodash/cloneDeep'; import '../../fixtures/window'; -import { Project } from '../../../src/project/project'; -import { Node } from '../../../src/document/node/node'; +import { Project, IProject } from '../../../src/project/project'; +import { Node, INode } from '../../../src/document/node/node'; import { Designer } from '../../../src/designer/designer'; import formSchema from '../../fixtures/schema/form'; import { getIdsFromSchema, getNodeFromSchemaById } from '../../utils'; @@ -37,7 +37,7 @@ beforeAll(() => { describe('schema 生成节点模型测试', () => { describe('block ❌ | component ❌ | slot ❌', () => { - let project: Project; + let project: IProject; beforeEach(() => { project = new Project(designer, { componentsTree: [ @@ -52,12 +52,12 @@ describe('schema 生成节点模型测试', () => { it('基本的节点模型初始化,模型导出', () => { expect(project).toBeTruthy(); const { currentDocument } = project; - const { nodesMap } = currentDocument; + const nodesMap = currentDocument?.nodesMap; const ids = getIdsFromSchema(formSchema); const expectedNodeCnt = ids.length; - expect(nodesMap.size).toBe(expectedNodeCnt); + expect(nodesMap?.size).toBe(expectedNodeCnt); ids.forEach(id => { - expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName); + expect(nodesMap?.get(id)?.componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName); }); const pageNode = currentDocument?.getNode('page'); @@ -76,18 +76,18 @@ describe('schema 生成节点模型测试', () => { it('基本的节点模型初始化,节点深度', () => { expect(project).toBeTruthy(); const { currentDocument } = project; - const getNode = currentDocument.getNode.bind(currentDocument); - - const pageNode = getNode('page'); - const rootHeaderNode = getNode('node_k1ow3cba'); - const rootContentNode = getNode('node_k1ow3cbb'); - const rootFooterNode = getNode('node_k1ow3cbc'); - const formNode = getNode('form'); - const cardNode = getNode('node_k1ow3cbj'); - const cardContentNode = getNode('node_k1ow3cbk'); - const columnsLayoutNode = getNode('node_k1ow3cbw'); - const columnNode = getNode('node_k1ow3cbx'); - const textFieldNode = getNode('node_k1ow3cbz'); + const getNode = currentDocument?.getNode.bind(currentDocument); + + const pageNode = getNode?.('page'); + const rootHeaderNode = getNode?.('node_k1ow3cba'); + const rootContentNode = getNode?.('node_k1ow3cbb'); + const rootFooterNode = getNode?.('node_k1ow3cbc'); + const formNode = getNode?.('form'); + const cardNode = getNode?.('node_k1ow3cbj'); + const cardContentNode = getNode?.('node_k1ow3cbk'); + const columnsLayoutNode = getNode?.('node_k1ow3cbw'); + const columnNode = getNode?.('node_k1ow3cbx'); + const textFieldNode = getNode?.('node_k1ow3cbz'); expect(pageNode?.zLevel).toBe(0); expect(rootHeaderNode?.zLevel).toBe(1); @@ -131,7 +131,7 @@ describe('schema 生成节点模型测试', () => { const textFieldNode = getNode('node_k1ow3cbz'); expect(pageNode?.index).toBe(-1); - expect(pageNode?.children.toString()).toBe('[object Array]'); + expect(pageNode?.children?.toString()).toBe('[object Array]'); expect(pageNode?.children?.get(1)).toBe(rootContentNode); expect(pageNode?.getChildren()?.get(1)).toBe(rootContentNode); expect(pageNode?.getNode()).toBe(pageNode); @@ -162,20 +162,20 @@ describe('schema 生成节点模型测试', () => { it('基本的节点模型初始化,节点新建、删除等事件', () => { expect(project).toBeTruthy(); const { currentDocument } = project; - const getNode = currentDocument.getNode.bind(currentDocument); - const createNode = currentDocument.createNode.bind(currentDocument); + const getNode = currentDocument?.getNode.bind(currentDocument); + const createNode = currentDocument?.createNode.bind(currentDocument); - const pageNode = getNode('page'); + const pageNode = getNode?.('page'); const nodeCreateHandler = jest.fn(); const offCreate = currentDocument?.onNodeCreate(nodeCreateHandler); - const node = createNode({ + const node = createNode?.({ componentName: 'TextInput', props: { propA: 'haha', }, }); - currentDocument?.insertNode(pageNode, node); + pageNode && node && currentDocument?.insertNode(pageNode, node); expect(nodeCreateHandler).toHaveBeenCalledTimes(1); expect(nodeCreateHandler.mock.calls[0][0]).toBe(node); @@ -184,7 +184,7 @@ describe('schema 生成节点模型测试', () => { const nodeDestroyHandler = jest.fn(); const offDestroy = currentDocument?.onNodeDestroy(nodeDestroyHandler); - node.remove(); + node?.remove(); expect(nodeDestroyHandler).toHaveBeenCalledTimes(1); expect(nodeDestroyHandler.mock.calls[0][0]).toBe(node); expect(nodeDestroyHandler.mock.calls[0][0].componentName).toBe('TextInput'); @@ -290,9 +290,9 @@ describe('schema 生成节点模型测试', () => { expect(project).toBeTruthy(); const ids = getIdsFromSchema(formSchema); const { currentDocument } = project; - const { nodesMap } = currentDocument; - const formNode = nodesMap.get('form'); - currentDocument?.insertNode(formNode, { + const nodesMap = currentDocument?.nodesMap; + const formNode = nodesMap?.get('form'); + formNode && currentDocument?.insertNode(formNode, { componentName: 'TextInput', id: 'nodeschema-id1', props: { @@ -300,11 +300,11 @@ describe('schema 生成节点模型测试', () => { propB: 3, }, }, 0); - expect(nodesMap.size).toBe(ids.length + 1); - expect(formNode.children.length).toBe(4); - const insertedNode = formNode.children.get(0); - expect(insertedNode.componentName).toBe('TextInput'); - expect(insertedNode.propsData).toEqual({ + expect(nodesMap?.size).toBe(ids.length + 1); + expect(formNode?.children?.length).toBe(4); + const insertedNode = formNode?.children?.get(0); + expect(insertedNode?.componentName).toBe('TextInput'); + expect(insertedNode?.propsData).toEqual({ propA: 'haha', propB: 3, }); @@ -316,9 +316,9 @@ describe('schema 生成节点模型测试', () => { expect(project).toBeTruthy(); const ids = getIdsFromSchema(formSchema); const { currentDocument } = project; - const { nodesMap } = currentDocument; - const formNode = nodesMap.get('form'); - currentDocument?.insertNode(formNode, { + const nodesMap = currentDocument?.nodesMap; + const formNode = nodesMap?.get('form'); + formNode && currentDocument?.insertNode(formNode, { componentName: 'TextInput', id: 'nodeschema-id1', props: { @@ -326,11 +326,11 @@ describe('schema 生成节点模型测试', () => { propB: 3, }, }, 1); - expect(nodesMap.size).toBe(ids.length + 1); - expect(formNode.children.length).toBe(4); - const insertedNode = formNode.children.get(1); - expect(insertedNode.componentName).toBe('TextInput'); - expect(insertedNode.propsData).toEqual({ + expect(nodesMap?.size).toBe(ids.length + 1); + expect(formNode?.children?.length).toBe(4); + const insertedNode = formNode?.children?.get(1); + expect(insertedNode?.componentName).toBe('TextInput'); + expect(insertedNode?.propsData).toEqual({ propA: 'haha', propB: 3, }); @@ -342,8 +342,8 @@ describe('schema 生成节点模型测试', () => { expect(project).toBeTruthy(); const ids = getIdsFromSchema(formSchema); const { currentDocument } = project; - const { nodesMap } = currentDocument; - const formNode = nodesMap.get('form') as Node; + const nodesMap = currentDocument?.nodesMap; + const formNode = nodesMap?.get('form') as INode; currentDocument?.insertNode(formNode, { componentName: 'ParentNode', props: { @@ -367,8 +367,8 @@ describe('schema 生成节点模型测试', () => { }, ], }); - expect(nodesMap.size).toBe(ids.length + 3); - expect(formNode.children.length).toBe(4); + expect(nodesMap?.size).toBe(ids.length + 3); + expect(formNode.children?.length).toBe(4); expect(formNode.children?.get(3)?.componentName).toBe('ParentNode'); expect(formNode.children?.get(3)?.children?.get(0)?.componentName).toBe('SubNode'); expect(formNode.children?.get(3)?.children?.get(1)?.componentName).toBe('SubNode2'); @@ -378,9 +378,9 @@ describe('schema 生成节点模型测试', () => { expect(project).toBeTruthy(); const ids = getIdsFromSchema(formSchema); const { currentDocument } = project; - const { nodesMap } = currentDocument; - const formNode = nodesMap.get('form'); - currentDocument?.insertNode(formNode, { + const nodesMap = currentDocument?.nodesMap; + const formNode = nodesMap?.get('form'); + formNode && currentDocument?.insertNode(formNode, { componentName: 'TextInput', id: 'nodeschema-id1', props: { @@ -388,17 +388,17 @@ describe('schema 生成节点模型测试', () => { propB: 3, }, }); - expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput'); - expect(nodesMap.size).toBe(ids.length + 1); + expect(nodesMap?.get('nodeschema-id1')?.componentName).toBe('TextInput'); + expect(nodesMap?.size).toBe(ids.length + 1); }); it.skip('场景一:插入 NodeSchema,id 与现有 schema 里的 id 重复,但关闭了 id 检测器', () => { expect(project).toBeTruthy(); const ids = getIdsFromSchema(formSchema); const { currentDocument } = project; - const { nodesMap } = currentDocument; - const formNode = nodesMap.get('form'); - currentDocument?.insertNode(formNode, { + const nodesMap = currentDocument?.nodesMap; + const formNode = nodesMap?.get('form'); + formNode && currentDocument?.insertNode(formNode, { componentName: 'TextInput', id: 'nodeschema-id1', props: { @@ -406,16 +406,16 @@ describe('schema 生成节点模型测试', () => { propB: 3, }, }); - expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput'); - expect(nodesMap.size).toBe(ids.length + 1); + expect(nodesMap?.get('nodeschema-id1')?.componentName).toBe('TextInput'); + expect(nodesMap?.size).toBe(ids.length + 1); }); it('场景二:插入 Node 实例', () => { expect(project).toBeTruthy(); const ids = getIdsFromSchema(formSchema); const { currentDocument } = project; - const { nodesMap } = currentDocument; - const formNode = nodesMap.get('form'); + const nodesMap = currentDocument?.nodesMap; + const formNode = nodesMap?.get('form'); const inputNode = currentDocument?.createNode({ componentName: 'TextInput', id: 'nodeschema-id2', @@ -424,22 +424,22 @@ describe('schema 生成节点模型测试', () => { propB: 3, }, }); - currentDocument?.insertNode(formNode, inputNode); - expect(formNode.children?.get(3)?.componentName).toBe('TextInput'); - expect(nodesMap.size).toBe(ids.length + 1); + formNode && currentDocument?.insertNode(formNode, inputNode); + expect(formNode?.children?.get(3)?.componentName).toBe('TextInput'); + expect(nodesMap?.size).toBe(ids.length + 1); }); it('场景三:插入 JSExpression', () => { expect(project).toBeTruthy(); const ids = getIdsFromSchema(formSchema); const { currentDocument } = project; - const { nodesMap } = currentDocument; - const formNode = nodesMap.get('form') as Node; + const nodesMap = currentDocument?.nodesMap; + const formNode = nodesMap?.get('form') as Node; currentDocument?.insertNode(formNode, { type: 'JSExpression', value: 'just a expression', }); - expect(nodesMap.size).toBe(ids.length + 1); + expect(nodesMap?.size).toBe(ids.length + 1); expect(formNode.children?.get(3)?.componentName).toBe('Leaf'); // expect(formNode.children?.get(3)?.children).toEqual({ // type: 'JSExpression', @@ -450,10 +450,10 @@ describe('schema 生成节点模型测试', () => { expect(project).toBeTruthy(); const ids = getIdsFromSchema(formSchema); const { currentDocument } = project; - const { nodesMap } = currentDocument; - const formNode = nodesMap.get('form') as Node; + const nodesMap = currentDocument?.nodesMap; + const formNode = nodesMap?.get('form') as Node; currentDocument?.insertNode(formNode, 'just a string'); - expect(nodesMap.size).toBe(ids.length + 1); + expect(nodesMap?.size).toBe(ids.length + 1); expect(formNode.children?.get(3)?.componentName).toBe('Leaf'); // expect(formNode.children?.get(3)?.children).toBe('just a string'); }); @@ -473,8 +473,8 @@ describe('schema 生成节点模型测试', () => { expect(project).toBeTruthy(); const ids = getIdsFromSchema(formSchema); const { currentDocument } = project; - const { nodesMap } = currentDocument; - const formNode = nodesMap.get('form') as Node; + const nodesMap = currentDocument?.nodesMap; + const formNode = nodesMap?.get('form') as Node; const formNode2 = currentDocument?.getNode('form'); expect(formNode).toEqual(formNode2); currentDocument?.insertNodes(formNode, [ @@ -493,17 +493,17 @@ describe('schema 生成节点模型测试', () => { }, }, ], 1); - expect(nodesMap.size).toBe(ids.length + 2); + expect(nodesMap?.size).toBe(ids.length + 2); expect(formNode.children?.length).toBe(5); - const insertedNode1 = formNode.children.get(1); - const insertedNode2 = formNode.children.get(2); - expect(insertedNode1.componentName).toBe('TextInput'); - expect(insertedNode1.propsData).toEqual({ + const insertedNode1 = formNode.children?.get(1); + const insertedNode2 = formNode.children?.get(2); + expect(insertedNode1?.componentName).toBe('TextInput'); + expect(insertedNode1?.propsData).toEqual({ propA: 'haha2', propB: 3, }); - expect(insertedNode2.componentName).toBe('TextInput2'); - expect(insertedNode2.propsData).toEqual({ + expect(insertedNode2?.componentName).toBe('TextInput2'); + expect(insertedNode2?.propsData).toEqual({ propA: 'haha', propB: 3, }); @@ -513,8 +513,8 @@ describe('schema 生成节点模型测试', () => { expect(project).toBeTruthy(); const ids = getIdsFromSchema(formSchema); const { currentDocument } = project; - const { nodesMap } = currentDocument; - const formNode = nodesMap.get('form') as Node; + const nodesMap = currentDocument?.nodesMap; + const formNode = nodesMap?.get('form') as INode; const formNode2 = currentDocument?.getNode('form'); expect(formNode).toEqual(formNode2); const createdNode1 = currentDocument?.createNode({ @@ -532,17 +532,17 @@ describe('schema 生成节点模型测试', () => { }, }); currentDocument?.insertNodes(formNode, [createdNode1, createdNode2], 1); - expect(nodesMap.size).toBe(ids.length + 2); + expect(nodesMap?.size).toBe(ids.length + 2); expect(formNode.children?.length).toBe(5); - const insertedNode1 = formNode.children.get(1); - const insertedNode2 = formNode.children.get(2); - expect(insertedNode1.componentName).toBe('TextInput'); - expect(insertedNode1.propsData).toEqual({ + const insertedNode1 = formNode.children?.get(1); + const insertedNode2 = formNode.children?.get(2); + expect(insertedNode1?.componentName).toBe('TextInput'); + expect(insertedNode1?.propsData).toEqual({ propA: 'haha2', propB: 3, }); - expect(insertedNode2.componentName).toBe('TextInput2'); - expect(insertedNode2.propsData).toEqual({ + expect(insertedNode2?.componentName).toBe('TextInput2'); + expect(insertedNode2?.propsData).toEqual({ propA: 'haha', propB: 3, }); @@ -561,13 +561,13 @@ describe('schema 生成节点模型测试', () => { project.open(); expect(project).toBeTruthy(); const { currentDocument } = project; - const { nodesMap } = currentDocument; + const nodesMap = currentDocument?.nodesMap; const ids = getIdsFromSchema(formSchema); // 目前每个 slot 会新增(1 + children.length)个节点 const expectedNodeCnt = ids.length + 2; - expect(nodesMap.size).toBe(expectedNodeCnt); + expect(nodesMap?.size).toBe(expectedNodeCnt); // PageHeader - expect(nodesMap.get('node_k1ow3cbd').slots).toHaveLength(1); + expect(nodesMap?.get('node_k1ow3cbd')?.slots).toHaveLength(1); }); }); }); diff --git a/packages/shell/src/model/condition-group.ts b/packages/shell/src/model/condition-group.ts new file mode 100644 index 0000000000..22b926615a --- /dev/null +++ b/packages/shell/src/model/condition-group.ts @@ -0,0 +1,42 @@ +import { IExclusiveGroup } from '@alilc/lowcode-designer'; +import { IPublicModelExclusiveGroup, IPublicModelNode } from '@alilc/lowcode-types'; +import { conditionGroupSymbol, nodeSymbol } from '../symbols'; +import { Node } from './node'; + +export class ConditionGroup implements IPublicModelExclusiveGroup { + private [conditionGroupSymbol]: IExclusiveGroup | null; + + constructor(conditionGroup: IExclusiveGroup | null) { + this[conditionGroupSymbol] = conditionGroup; + } + + get id() { + return this[conditionGroupSymbol]?.id; + } + + get title() { + return this[conditionGroupSymbol]?.title; + } + + get firstNode() { + return Node.create(this[conditionGroupSymbol]?.firstNode); + } + + setVisible(node: IPublicModelNode) { + this[conditionGroupSymbol]?.setVisible((node as any)[nodeSymbol] ? (node as any)[nodeSymbol] : node); + } + + static create(conditionGroup: IExclusiveGroup | null) { + if (!conditionGroup) { + return null; + } + // @ts-ignore + if (conditionGroup[conditionGroupSymbol]) { + return (conditionGroup as any)[conditionGroupSymbol]; + } + const shellConditionGroup = new ConditionGroup(conditionGroup); + // @ts-ignore + shellConditionGroup[conditionGroupSymbol] = shellConditionGroup; + return shellConditionGroup; + } +} \ No newline at end of file diff --git a/packages/shell/src/model/node.ts b/packages/shell/src/model/node.ts index 9b407de5cf..249e87f46e 100644 --- a/packages/shell/src/model/node.ts +++ b/packages/shell/src/model/node.ts @@ -27,6 +27,7 @@ import { ComponentMeta as ShellComponentMeta } from './component-meta'; import { SettingTopEntry as ShellSettingTopEntry } from './setting-top-entry'; import { documentSymbol, nodeSymbol } from '../symbols'; import { ReactElement } from 'react'; +import { ConditionGroup } from './condition-group'; const shellNodeSymbol = Symbol('shellNodeSymbol'); @@ -289,7 +290,7 @@ export class Node implements IPublicModelNode { /** * 当前节点为插槽节点时,返回节点对应的属性实例 */ - get slotFor(): IPublicModelProp | null { + get slotFor(): IPublicModelProp | null | undefined { return ShellProp.create(this[nodeSymbol].slotFor); } @@ -349,7 +350,6 @@ export class Node implements IPublicModelNode { /** * 获取节点实例对应的 dom 节点 - * @deprecated */ getDOMNode() { return (this[nodeSymbol] as any).getDOMNode(); @@ -362,9 +362,9 @@ export class Node implements IPublicModelNode { * @param sorter */ mergeChildren( - remover: (node: Node, idx: number) => boolean, - adder: (children: Node[]) => any, - sorter: (firstNode: Node, secondNode: Node) => number, + remover: (node: IPublicModelNode, idx: number) => boolean, + adder: (children: IPublicModelNode[]) => any, + sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number, ): any { return this.children?.mergeChildren(remover, adder, sorter); } @@ -641,7 +641,7 @@ export class Node implements IPublicModelNode { * @since v1.1.0 */ get conditionGroup(): IPublicModelExclusiveGroup | null { - return this[nodeSymbol].conditionGroup; + return ConditionGroup.create(this[nodeSymbol].conditionGroup); } /** diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index 91ad609ac9..83d831747b 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -33,3 +33,4 @@ export const resourceTypeSymbol = Symbol('resourceType'); export const resourceSymbol = Symbol('resource'); export const clipboardSymbol = Symbol('clipboard'); export const configSymbol = Symbol('configSymbol'); +export const conditionGroupSymbol = Symbol('conditionGroup'); diff --git a/packages/types/src/shell/model/exclusive-group.ts b/packages/types/src/shell/model/exclusive-group.ts index 1fbfe089aa..b930a13444 100644 --- a/packages/types/src/shell/model/exclusive-group.ts +++ b/packages/types/src/shell/model/exclusive-group.ts @@ -1,8 +1,10 @@ -import { IPublicModelNode } from '..'; +import { IPublicModelNode, IPublicTypeTitleContent } from '..'; -export interface IPublicModelExclusiveGroup { - readonly id: string; - readonly title: string; - get firstNode(): IPublicModelNode; +export interface IPublicModelExclusiveGroup< + Node = IPublicModelNode, +> { + readonly id: string | undefined; + readonly title: IPublicTypeTitleContent | undefined; + get firstNode(): Node | null; setVisible(node: Node): void; } diff --git a/packages/types/src/shell/model/node.ts b/packages/types/src/shell/model/node.ts index dd6db71bf2..ba924d6d59 100644 --- a/packages/types/src/shell/model/node.ts +++ b/packages/types/src/shell/model/node.ts @@ -8,7 +8,10 @@ export interface IBaseModelNode< Node = IPublicModelNode, NodeChildren = IPublicModelNodeChildren, ComponentMeta = IPublicModelComponentMeta, - SettingTopEntry = IPublicModelSettingTopEntry + SettingTopEntry = IPublicModelSettingTopEntry, + Props = IPublicModelProps, + Prop = IPublicModelProp, + ExclusiveGroup = IPublicModelExclusiveGroup > { /** @@ -167,7 +170,7 @@ export interface IBaseModelNode< * 下标 * index */ - get index(): number; + get index(): number | undefined; /** * 图标 @@ -203,13 +206,13 @@ export interface IBaseModelNode< * 获取当前节点的前一个兄弟节点 * get previous sibling of this node */ - get prevSibling(): Node | null; + get prevSibling(): Node | null | undefined; /** * 获取当前节点的后一个兄弟节点 * get next sibling of this node */ - get nextSibling(): Node | null; + get nextSibling(): Node | null | undefined; /** * 获取当前节点的父亲节点 @@ -233,13 +236,13 @@ export interface IBaseModelNode< * 当前节点为插槽节点时,返回节点对应的属性实例 * return coresponding prop when this node is a slot node */ - get slotFor(): IPublicModelProp | null; + get slotFor(): Prop | null | undefined; /** * 返回节点的属性集 * get props */ - get props(): IPublicModelProps | null; + get props(): Props | null; /** * 返回节点的属性集 @@ -250,7 +253,7 @@ export interface IBaseModelNode< /** * get conditionGroup */ - get conditionGroup(): IPublicModelExclusiveGroup | null; + get conditionGroup(): ExclusiveGroup | null; /** * 获取符合搭建协议 - 节点 schema 结构 @@ -295,7 +298,7 @@ export interface IBaseModelNode< * get prop by path * @param path 属性路径,支持 a / a.b / a.0 等格式 */ - getProp(path: string, createIfNone: boolean): IPublicModelProp | null; + getProp(path: string, createIfNone: boolean): Prop | null; /** * 获取指定 path 的属性模型实例值 @@ -313,7 +316,7 @@ export interface IBaseModelNode< * @param path 属性路径,支持 a / a.b / a.0 等格式 * @param createIfNone 当没有属性的时候,是否创建一个属性 */ - getExtraProp(path: string, createIfNone?: boolean): IPublicModelProp | null; + getExtraProp(path: string, createIfNone?: boolean): Prop | null; /** * 获取指定 path 的属性模型实例, @@ -481,6 +484,11 @@ export interface IBaseModelNode< * @since v1.1.0 */ setConditionalVisible(): void; + + /** + * 获取节点实例对应的 dom 节点 + */ + getDOMNode(): HTMLElement; } export interface IPublicModelNode extends IBaseModelNode {} \ No newline at end of file diff --git a/packages/types/src/shell/model/prop.ts b/packages/types/src/shell/model/prop.ts index 7ac906762e..71442e64ab 100644 --- a/packages/types/src/shell/model/prop.ts +++ b/packages/types/src/shell/model/prop.ts @@ -2,7 +2,9 @@ import { IPublicEnumTransformStage } from '../enum'; import { IPublicTypeCompositeValue } from '../type'; import { IPublicModelNode } from './'; -export interface IPublicModelProp { +export interface IPublicModelProp< + Node = IPublicModelNode +> { /** * id @@ -25,14 +27,14 @@ export interface IPublicModelProp { * 返回所属的节点实例 * get node instance, which this prop belongs to */ - get node(): IPublicModelNode | null; + get node(): Node | null; /** * 当本 prop 代表一个 Slot 时,返回对应的 slotNode * return the slot node (only if the current prop represents a slot) * @since v1.1.0 */ - get slotNode(): IPublicModelNode | undefined | null; + get slotNode(): Node | undefined | null; /** * 是否是 Prop , 固定返回 true diff --git a/packages/types/src/shell/type/metadata.ts b/packages/types/src/shell/type/metadata.ts index 7ee0228c97..39022d48fe 100644 --- a/packages/types/src/shell/type/metadata.ts +++ b/packages/types/src/shell/type/metadata.ts @@ -195,8 +195,8 @@ export interface IPublicTypeCallbacks { onChildMoveHook?: (childNode: IPublicModelNode, currentNode: IPublicModelNode) => boolean; // events - onNodeRemove?: (removedNode: IPublicModelNode, currentNode: IPublicModelNode) => void; - onNodeAdd?: (addedNode: IPublicModelNode, currentNode: IPublicModelNode) => void; + onNodeRemove?: (removedNode: IPublicModelNode | null, currentNode: IPublicModelNode | null) => void; + onNodeAdd?: (addedNode: IPublicModelNode | null, currentNode: IPublicModelNode | null) => void; onSubtreeModified?: (currentNode: IPublicModelNode, options: any) => void; onResize?: ( e: MouseEvent & { diff --git a/packages/utils/src/check-types/is-dom-text.ts b/packages/utils/src/check-types/is-dom-text.ts index 47edec139a..9509544409 100644 --- a/packages/utils/src/check-types/is-dom-text.ts +++ b/packages/utils/src/check-types/is-dom-text.ts @@ -1,3 +1,3 @@ -export function isDOMText(data: any): boolean { +export function isDOMText(data: any): data is string { return typeof data === 'string'; } diff --git a/packages/utils/src/check-types/is-node-schema.ts b/packages/utils/src/check-types/is-node-schema.ts index 0bfb4d0354..bfc3ff3f2b 100644 --- a/packages/utils/src/check-types/is-node-schema.ts +++ b/packages/utils/src/check-types/is-node-schema.ts @@ -1,5 +1,5 @@ import { IPublicTypeNodeSchema } from '@alilc/lowcode-types'; export function isNodeSchema(data: any): data is IPublicTypeNodeSchema { - return data && data.componentName; + return data && data.componentName && !data.isNode; } From 29b91846fb22f01a94b6f1be282b93095eeb6403 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 2 Mar 2023 11:49:08 +0800 Subject: [PATCH 025/469] fix: componentList in remote component desc not written into asset --- packages/editor-core/src/editor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index 062b7e6699..737a9fa26c 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -123,6 +123,7 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor await (new AssetLoader()).load(url); function setAssetsComponent(component: any, extraNpmInfo: any = {}) { const components = component.components; + assets.componentList = assets.componentList?.concat(component.componentList || []); if (Array.isArray(components)) { components.forEach(d => { assets.components = assets.components.concat({ @@ -144,7 +145,6 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor ...component.components, } || []); } - // assets.componentList = assets.componentList.concat(component.componentList || []); } function setArrayAssets(value: any[], preExportName: string = '', preSubName: string = '') { value.forEach((d: any, i: number) => { From 676e49ee2c48b01807d9220e6a554e24126aa6cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= Date: Thu, 2 Mar 2023 19:37:59 +0800 Subject: [PATCH 026/469] fix: use original moduleName --- modules/code-generator/src/parser/SchemaParser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/src/parser/SchemaParser.ts b/modules/code-generator/src/parser/SchemaParser.ts index 3108fee477..24fc686878 100644 --- a/modules/code-generator/src/parser/SchemaParser.ts +++ b/modules/code-generator/src/parser/SchemaParser.ts @@ -161,7 +161,7 @@ export class SchemaParser implements ISchemaParser { ...subRoot, componentName: getRootComponentName(subRoot.componentName, compDeps), containerType: subRoot.componentName, - moduleName: ensureValidClassName(changeCase.pascalCase(subRoot.fileName)), + moduleName: subRoot.fileName, }; return container; }); From 5db418efe41f8421a644d54926db6ce8d2164eed Mon Sep 17 00:00:00 2001 From: liujuping Date: Fri, 3 Mar 2023 17:08:04 +0800 Subject: [PATCH 027/469] fix: when the component is configured in a loop, the key value changes and renders error --- packages/renderer-core/src/renderer/base.tsx | 5 +++++ packages/types/src/shell/api/plugins.ts | 10 ++++++++++ packages/types/src/shell/type/props-map.ts | 4 ++-- packages/types/src/shell/type/value-type.ts | 4 ++-- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 311493736a..a965549086 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -774,6 +774,11 @@ export default function baseRendererFactory(): IBaseRenderComponent { { ...schema, loop: undefined, + props: { + ...schema.props, + // 循环下 key 不能为常量,这样会造成 key 值重复,渲染异常 + key: isJSExpression(schema.props?.key) ? schema.props?.key : null, + }, }, loopSelf, parentInfo, diff --git a/packages/types/src/shell/api/plugins.ts b/packages/types/src/shell/api/plugins.ts index 518362b97a..a930162909 100644 --- a/packages/types/src/shell/api/plugins.ts +++ b/packages/types/src/shell/api/plugins.ts @@ -13,6 +13,11 @@ export interface IPluginPreferenceMananger { export type PluginOptionsType = string | number | boolean | object; export interface IPublicApiPlugins { + /** + * 可以通过 plugin api 获取其他插件 export 导出的内容 + */ + [key: string]: any; + register( pluginModel: IPublicTypePlugin, options?: Record, @@ -21,6 +26,7 @@ export interface IPublicApiPlugins { /** * 引擎初始化时可以提供全局配置给到各插件,通过这个方法可以获得本插件对应的配置 + * * use this to get preference config for this plugin when engine.init() called */ getPluginPreference( @@ -29,24 +35,28 @@ export interface IPublicApiPlugins { /** * 获取指定插件 + * * get plugin instance by name */ get(pluginName: string): IPublicModelPluginInstance | null; /** * 获取所有的插件实例 + * * get all plugin instances */ getAll(): IPublicModelPluginInstance[]; /** * 判断是否有指定插件 + * * check if plugin with certain name exists */ has(pluginName: string): boolean; /** * 删除指定插件 + * * delete plugin instance by name */ delete(pluginName: string): void; diff --git a/packages/types/src/shell/type/props-map.ts b/packages/types/src/shell/type/props-map.ts index e43095757b..1b93f46252 100644 --- a/packages/types/src/shell/type/props-map.ts +++ b/packages/types/src/shell/type/props-map.ts @@ -1,3 +1,3 @@ -import { IPublicTypeCompositeObject } from './'; +import { IPublicTypeCompositeObject, IPublicTypeNodeData } from './'; -export type IPublicTypePropsMap = IPublicTypeCompositeObject; +export type IPublicTypePropsMap = IPublicTypeCompositeObject; diff --git a/packages/types/src/shell/type/value-type.ts b/packages/types/src/shell/type/value-type.ts index c0c0125447..16fb789a26 100644 --- a/packages/types/src/shell/type/value-type.ts +++ b/packages/types/src/shell/type/value-type.ts @@ -131,6 +131,6 @@ export interface IPublicTypeJSONObject { } export type IPublicTypeCompositeArray = IPublicTypeCompositeValue[]; -export interface IPublicTypeCompositeObject { - [key: string]: IPublicTypeCompositeValue; +export interface IPublicTypeCompositeObject { + [key: string]: IPublicTypeCompositeValue | T; } \ No newline at end of file From 39f455e13fb3742f56ee5a18b36761f8c85930ab Mon Sep 17 00:00:00 2001 From: liujuping Date: Fri, 3 Mar 2023 17:51:59 +0800 Subject: [PATCH 028/469] feat: optimize error component output information --- packages/renderer-core/src/renderer/renderer.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/renderer-core/src/renderer/renderer.tsx b/packages/renderer-core/src/renderer/renderer.tsx index d936b7d91f..4968f269a2 100644 --- a/packages/renderer-core/src/renderer/renderer.tsx +++ b/packages/renderer-core/src/renderer/renderer.tsx @@ -19,10 +19,9 @@ export default function rendererFactory(): IRenderComponent { const debug = Debug('renderer:entry'); - class FaultComponent extends PureComponent { + class FaultComponent extends PureComponent { render() { - // FIXME: errorlog - console.error('render error', this.props); + logger.error(`%c组件渲染异常, 异常原因: ${this.props.error?.message || this.props.error || '未知'}`, 'color: #ff0000;'); return createElement(Div, { style: { width: '100%', From 7bef50762c2032ce640aedcc10a16739e9471885 Mon Sep 17 00:00:00 2001 From: huxingyi1997 Date: Fri, 3 Mar 2023 19:02:19 +0800 Subject: [PATCH 029/469] feat: disable behaviors according to components in outline-tree --- .../src/views/tree-title.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 7a3718366d..05fa0f7be7 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -6,7 +6,6 @@ import { IPublicModelPluginContext, IPublicApiEvent } from '@alilc/lowcode-types import TreeNode from '../controllers/tree-node'; import { IconLock, IconUnlock, IconArrowRight, IconEyeClose, IconEye, IconCond, IconLoop, IconRadioActive, IconRadio, IconSetting } from '../icons'; - function emitOutlineEvent(event: IPublicApiEvent, type: string, treeNode: TreeNode, rest?: Record) { const node = treeNode?.node; const npm = node?.componentMeta?.npm; @@ -35,6 +34,8 @@ export default class TreeTitle extends Component<{ title: '', }; + private lastInput?: HTMLInputElement; + private enableEdit = (e) => { e.preventDefault(); this.setState({ @@ -66,8 +67,6 @@ export default class TreeTitle extends Component<{ } }; - private lastInput?: HTMLInputElement; - private setCaret = (input: HTMLInputElement | null) => { if (!input || this.lastInput === input) { return; @@ -96,6 +95,8 @@ export default class TreeTitle extends Component<{ const { editing } = this.state; const isCNode = !treeNode.isRoot(); const { node } = treeNode; + const { componentMeta } = node; + const availableActions = componentMeta ? componentMeta.availableActions.map((availableAction) => availableAction.name) : []; const isNodeParent = node.isParentalNode; const isContainer = node.isContainerNode; let style: any; @@ -112,8 +113,11 @@ export default class TreeTitle extends Component<{ const { intlNode, common, config } = pluginContext; const Tip = common.editorCabin.Tip; const Title = common.editorCabin.Title; - const shouldShowHideBtn = isCNode && isNodeParent && !isModal; - const shouldShowLockBtn = config.get('enableCanvasLock', false) && isContainer && isCNode && isNodeParent; + const couldHide = availableActions.includes('hide'); + const couldLock = availableActions.includes('lock'); + const couldUnlock = availableActions.includes('unlock'); + const shouldShowHideBtn = isCNode && isNodeParent && !isModal && couldHide; + const shouldShowLockBtn = config.get('enableCanvasLock', false) && isContainer && isCNode && isNodeParent && ((couldLock && !node.isLocked) || (couldUnlock && node.isLocked)); const shouldEditBtn = isCNode && isNodeParent; return (

); } -} \ No newline at end of file +} From 2d80d11475b1e26894ce877a071d57adb052aa7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8B=97=E7=A9=BA?= Date: Wed, 1 Mar 2023 10:06:44 +0800 Subject: [PATCH 030/469] =?UTF-8?q?fix(designer):=20=E4=BF=AE=E5=A4=8DVC?= =?UTF-8?q?=E7=BB=84=E4=BB=B6canResizing=E5=8F=91=E7=94=9F=E5=8F=98?= =?UTF-8?q?=E5=8C=96=E6=97=B6=E6=97=A0=E6=B3=95=E6=8B=96=E6=8B=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTOR.md | 1 + .../bem-tools/border-resizing.tsx | 201 ++++++++++-------- 2 files changed, 109 insertions(+), 93 deletions(-) diff --git a/CONTRIBUTOR.md b/CONTRIBUTOR.md index 89757bac92..11d50baade 100644 --- a/CONTRIBUTOR.md +++ b/CONTRIBUTOR.md @@ -24,5 +24,6 @@ - [Ychangqing](https://github.com/Ychangqing) - [yize](https://github.com/yize) - [youluna](https://github.com/youluna) +- [ibreathebsb](https://github.com/ibreathebsb) 如果您贡献过低代码引擎,但是没有看到您的名字,为我们的疏忽感到抱歉。欢迎您通过 PR 补充上自己的名字。 diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx index e174c4ad61..29401ca6b6 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx @@ -236,17 +236,22 @@ export class BoxResizingInstance extends Component<{ render() { const { observed } = this.props; - if (!observed.hasOffset) { - return null; - } - - const { node, offsetWidth, offsetHeight, offsetTop, offsetLeft } = observed; let triggerVisible: any = []; - const { advanced } = node.componentMeta; - if (advanced.getResizingHandlers) { - triggerVisible = advanced.getResizingHandlers(node.internalToShellNode()); + let offsetWidth = 0; + let offsetHeight = 0; + let offsetTop = 0; + let offsetLeft = 0; + if (observed.hasOffset) { + offsetWidth = observed.offsetWidth; + offsetHeight = observed.offsetHeight; + offsetTop = observed.offsetTop; + offsetLeft = observed.offsetLeft; + const { node } = observed; + const metadata = node.componentMeta.getMetadata(); + if (metadata.configure?.advanced?.getResizingHandlers) { + triggerVisible = metadata.configure.advanced.getResizingHandlers(node.internalToShellNode()); + } } - triggerVisible = normalizeTriggers(triggerVisible); const baseSideClass = 'lc-borders lc-resize-side'; @@ -254,90 +259,100 @@ export class BoxResizingInstance extends Component<{ return (
- {triggerVisible.includes('N') && ( -
{ this.outlineN = ref; }} - className={classNames(baseSideClass, 'n')} - style={{ - height: 20, - transform: `translate(${offsetLeft}px, ${offsetTop - 10}px)`, - width: offsetWidth, - }} - /> - )} - {triggerVisible.includes('NE') && ( -
{ this.outlineNE = ref; }} - className={classNames(baseCornerClass, 'ne')} - style={{ - transform: `translate(${offsetLeft + offsetWidth - 5}px, ${offsetTop - 3}px)`, - cursor: 'nesw-resize', - }} - /> - )} - {triggerVisible.includes('E') && ( -
{ this.outlineE = ref; }} - style={{ - height: offsetHeight, - transform: `translate(${offsetLeft + offsetWidth - 10}px, ${offsetTop}px)`, - width: 20, - }} - /> - )} - {triggerVisible.includes('SE') && ( -
{ this.outlineSE = ref; }} - className={classNames(baseCornerClass, 'se')} - style={{ - transform: `translate(${offsetLeft + offsetWidth - 5}px, ${offsetTop + offsetHeight - 5}px)`, - cursor: 'nwse-resize', - }} - /> - )} - {triggerVisible.includes('S') && ( -
{ this.outlineS = ref; }} - className={classNames(baseSideClass, 's')} - style={{ - height: 20, - transform: `translate(${offsetLeft}px, ${offsetTop + offsetHeight - 10}px)`, - width: offsetWidth, - }} - /> - )} - {triggerVisible.includes('SW') && ( -
{ this.outlineSW = ref; }} - className={classNames(baseCornerClass, 'sw')} - style={{ - transform: `translate(${offsetLeft - 3}px, ${offsetTop + offsetHeight - 5}px)`, - cursor: 'nesw-resize', - }} - /> - )} - {triggerVisible.includes('W') && ( -
{ this.outlineW = ref; }} - className={classNames(baseSideClass, 'w')} - style={{ - height: offsetHeight, - transform: `translate(${offsetLeft - 10}px, ${offsetTop}px)`, - width: 20, - }} - /> - )} - {triggerVisible.includes('NW') && ( -
{ this.outlineNW = ref; }} - className={classNames(baseCornerClass, 'nw')} - style={{ - transform: `translate(${offsetLeft - 3}px, ${offsetTop - 3}px)`, - cursor: 'nwse-resize', - }} - /> - )} +
{ + this.outlineN = ref; + }} + className={classNames(baseSideClass, 'n')} + style={{ + height: 20, + transform: `translate(${offsetLeft}px, ${offsetTop - 10}px)`, + width: offsetWidth, + display: triggerVisible.includes('N') ? 'flex' : 'none', + }} + /> +
{ + this.outlineNE = ref; + }} + className={classNames(baseCornerClass, 'ne')} + style={{ + transform: `translate(${offsetLeft + offsetWidth - 5}px, ${offsetTop - 3}px)`, + cursor: 'nesw-resize', + display: triggerVisible.includes('NE') ? 'flex' : 'none', + }} + /> +
{ + this.outlineE = ref; + }} + style={{ + height: offsetHeight, + transform: `translate(${offsetLeft + offsetWidth - 10}px, ${offsetTop}px)`, + width: 20, + display: triggerVisible.includes('E') ? 'flex' : 'none', + }} + /> +
{ + this.outlineSE = ref; + }} + className={classNames(baseCornerClass, 'se')} + style={{ + transform: `translate(${offsetLeft + offsetWidth - 5}px, ${ + offsetTop + offsetHeight - 5 + }px)`, + cursor: 'nwse-resize', + display: triggerVisible.includes('SE') ? 'flex' : 'none', + }} + /> +
{ + this.outlineS = ref; + }} + className={classNames(baseSideClass, 's')} + style={{ + height: 20, + transform: `translate(${offsetLeft}px, ${offsetTop + offsetHeight - 10}px)`, + width: offsetWidth, + display: triggerVisible.includes('S') ? 'flex' : 'none', + }} + /> +
{ + this.outlineSW = ref; + }} + className={classNames(baseCornerClass, 'sw')} + style={{ + transform: `translate(${offsetLeft - 3}px, ${offsetTop + offsetHeight - 5}px)`, + cursor: 'nesw-resize', + display: triggerVisible.includes('SW') ? 'flex' : 'none', + }} + /> +
{ + this.outlineW = ref; + }} + className={classNames(baseSideClass, 'w')} + style={{ + height: offsetHeight, + transform: `translate(${offsetLeft - 10}px, ${offsetTop}px)`, + width: 20, + display: triggerVisible.includes('W') ? 'flex' : 'none', + }} + /> +
{ + this.outlineNW = ref; + }} + className={classNames(baseCornerClass, 'nw')} + style={{ + transform: `translate(${offsetLeft - 3}px, ${offsetTop - 3}px)`, + cursor: 'nwse-resize', + display: triggerVisible.includes('NW') ? 'flex' : 'none', + }} + />
); } From 76ec15f5b77aa484cefcecc0de430d0b6c8a7bc9 Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 6 Mar 2023 15:17:14 +0800 Subject: [PATCH 031/469] fix: fix the problem that the outline pane tree cannot be expanded --- .../src/controllers/tree-node.ts | 77 +++++++++++++++---- .../src/views/tree-branches.tsx | 12 +-- .../src/views/tree-node.tsx | 24 +++--- .../src/views/tree-title.tsx | 4 +- 4 files changed, 82 insertions(+), 35 deletions(-) diff --git a/packages/plugin-outline-pane/src/controllers/tree-node.ts b/packages/plugin-outline-pane/src/controllers/tree-node.ts index 1babdbe61e..1f15405e56 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-node.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-node.ts @@ -3,8 +3,10 @@ import { IPublicTypeLocationChildrenDetail, IPublicModelNode, IPublicModelPluginContext, + IPublicTypeDisposable, } from '@alilc/lowcode-types'; import { isI18nData, isLocationChildrenDetail } from '@alilc/lowcode-utils'; +import EventEmitter from 'events'; import { Tree } from './tree'; /** @@ -21,14 +23,61 @@ export interface FilterResult { keywords: string; } +enum EVENT_NAMES { + filterResultChanged = 'filterResultChanged', + + expandedChanged = 'expandedChanged', + + hiddenChanged = 'hiddenChanged', + + lockedChanged = 'lockedChanged', + + titleLabelChanged = 'titleLabelChanged', + + expandableChanged = 'expandableChanged', +} + export default class TreeNode { readonly pluginContext: IPublicModelPluginContext; - onFilterResultChanged: () => void; - onExpandedChanged: (expanded: boolean) => void; - onHiddenChanged: (hidden: boolean) => void; - onLockedChanged: (locked: boolean) => void; - onTitleLabelChanged: (treeNode: TreeNode) => void; - onExpandableChanged: (expandable: boolean) => void; + event = new EventEmitter(); + + onFilterResultChanged(fn: () => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.filterResultChanged, fn); + return () => { + this.event.off(EVENT_NAMES.filterResultChanged, fn); + } + }; + onExpandedChanged(fn: (expanded: boolean) => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.expandedChanged, fn); + return () => { + this.event.off(EVENT_NAMES.expandedChanged, fn); + } + }; + onHiddenChanged(fn: (hidden: boolean) => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.hiddenChanged, fn); + return () => { + this.event.off(EVENT_NAMES.hiddenChanged, fn); + } + }; + onLockedChanged(fn: (locked: boolean) => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.lockedChanged, fn); + return () => { + this.event.off(EVENT_NAMES.lockedChanged, fn); + } + }; + onTitleLabelChanged(fn: (treeNode: TreeNode) => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.titleLabelChanged, fn); + + return () => { + this.event.off(EVENT_NAMES.titleLabelChanged, fn); + } + }; + onExpandableChanged(fn: (expandable: boolean) => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.expandableChanged, fn); + return () => { + this.event.off(EVENT_NAMES.expandableChanged, fn); + } + } get id(): string { return this.node.id; @@ -46,7 +95,7 @@ export default class TreeNode { * 触发 onExpandableChanged 回调 */ notifyExpandableChanged(): void { - this.onExpandableChanged && this.onExpandableChanged(this.expandable); + this.event.emit(EVENT_NAMES.expandableChanged, this.expandable); } /** @@ -99,7 +148,7 @@ export default class TreeNode { setExpanded(value: boolean) { this._expanded = value; - this.onExpandedChanged && this.onExpandedChanged(value); + this.event.emit(EVENT_NAMES.expandedChanged, value); } get detecting() { @@ -120,7 +169,7 @@ export default class TreeNode { return; } this.node.visible = !flag; - this.onHiddenChanged && this.onHiddenChanged(flag); + this.event.emit(EVENT_NAMES.hiddenChanged, flag); } get locked(): boolean { @@ -129,7 +178,7 @@ export default class TreeNode { setLocked(flag: boolean) { this.node.lock(flag); - this.onLockedChanged && this.onLockedChanged(flag); + this.event.emit(EVENT_NAMES.lockedChanged, flag); } get selected(): boolean { @@ -174,11 +223,11 @@ export default class TreeNode { } else { this.node.getExtraProp('title', true)?.setValue(label); } - this.onTitleLabelChanged && this.onTitleLabelChanged(this); + this.event.emit(EVENT_NAMES.titleLabelChanged, this); } get icon() { - return this.node.componentMeta.icon; + return this.node.componentMeta?.icon; } get parent(): TreeNode | null { @@ -282,8 +331,6 @@ export default class TreeNode { setFilterReult(val: FilterResult) { this._filterResult = val; - if (this.onFilterResultChanged) { - this.onFilterResultChanged(); - } + this.event.emit(EVENT_NAMES.filterResultChanged) } } diff --git a/packages/plugin-outline-pane/src/views/tree-branches.tsx b/packages/plugin-outline-pane/src/views/tree-branches.tsx index eb20845082..d9b0f83a87 100644 --- a/packages/plugin-outline-pane/src/views/tree-branches.tsx +++ b/packages/plugin-outline-pane/src/views/tree-branches.tsx @@ -25,10 +25,10 @@ export default class TreeBranches extends Component<{ componentDidMount() { const { treeNode } = this.props; - treeNode.onFilterResultChanged = () => { + treeNode.onFilterResultChanged(() => { const { filterWorking: newFilterWorking, matchChild: newMatchChild } = treeNode.filterReult; this.setState({ filterWorking: newFilterWorking, matchChild: newMatchChild }); - }; + }); } componentWillUnmount(): void { @@ -73,7 +73,7 @@ class TreeNodeChildren extends Component<{ keywords: null, dropDetail: null, }; - offLocationChanged: IPublicTypeDisposable; + offLocationChanged: IPublicTypeDisposable | undefined; componentDidMount() { const { treeNode, pluginContext } = this.props; const { project } = pluginContext; @@ -85,7 +85,7 @@ class TreeNodeChildren extends Component<{ keywords, dropDetail, }); - treeNode.onFilterResultChanged = () => { + treeNode.onFilterResultChanged(() => { const { filterWorking: newFilterWorking, matchSelf: newMatchChild, @@ -96,7 +96,7 @@ class TreeNodeChildren extends Component<{ matchSelf: newMatchChild, keywords: newKeywords, }); - }; + }); this.offLocationChanged = project.currentDocument?.onDropLocationChanged( () => { this.setState({ dropDetail: treeNode.dropDetail }); @@ -118,7 +118,7 @@ class TreeNodeChildren extends Component<{ const endGroup = () => { if (groupContents.length > 0) { children.push( -
+
void> = []; + eventOffCallbacks: Array<IPublicTypeDisposable | undefined> = []; constructor(props: any) { super(props); @@ -104,18 +104,18 @@ export default class TreeNodeView extends Component<{ const doc = project.currentDocument; - treeNode.onExpandedChanged = ((expanded: boolean) => { + treeNode.onExpandedChanged(((expanded: boolean) => { this.setState({ expanded }); - }); - treeNode.onHiddenChanged = (hidden: boolean) => { + })); + treeNode.onHiddenChanged((hidden: boolean) => { this.setState({ hidden }); - }; - treeNode.onLockedChanged = (locked: boolean) => { + }); + treeNode.onLockedChanged((locked: boolean) => { this.setState({ locked }); - }; - treeNode.onExpandableChanged = (expandable: boolean) => { + }); + treeNode.onExpandableChanged((expandable: boolean) => { this.setState({ expandable }); - }; + }); this.eventOffCallbacks.push( doc?.onDropLocationChanged((document: IPublicModelDocumentModel) => { @@ -135,8 +135,8 @@ export default class TreeNodeView extends Component<{ this.eventOffCallbacks.push(offDetectingChange!); } componentWillUnmount(): void { - this.eventOffCallbacks?.forEach((offFun: () => void) => { - offFun(); + this.eventOffCallbacks?.forEach((offFun: IPublicTypeDisposable | undefined) => { + offFun && offFun(); }); } diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 05fa0f7be7..51d0fcf805 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -83,11 +83,11 @@ export default class TreeTitle extends Component<{ editing: false, title: treeNode.titleLabel, }); - treeNode.onTitleLabelChanged = () => { + treeNode.onTitleLabelChanged(() => { this.setState({ title: treeNode.titleLabel, }); - }; + }); } render() { From aaedee159db7ac770578905eb9ed77945f599a06 Mon Sep 17 00:00:00 2001 From: silinchen <silinccc@gmail.com> Date: Mon, 6 Mar 2023 18:30:37 +0800 Subject: [PATCH 032/469] fix: misspelled words --- packages/engine/README-zh_CN.md | 2 +- packages/engine/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/engine/README-zh_CN.md b/packages/engine/README-zh_CN.md index 2761233919..b5256af9ca 100644 --- a/packages/engine/README-zh_CN.md +++ b/packages/engine/README-zh_CN.md @@ -71,7 +71,7 @@ skeleton.add({ area: 'topArea', type: 'Widget', name: 'logo', - content: YourFantaticLogo, + content: YourFantasticLogo, contentProps: { logo: 'https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png', diff --git a/packages/engine/README.md b/packages/engine/README.md index 4f0543c7a0..2d1254e4a5 100644 --- a/packages/engine/README.md +++ b/packages/engine/README.md @@ -71,7 +71,7 @@ skeleton.add({ area: 'topArea', type: 'Widget', name: 'logo', - content: YourFantaticLogo, + content: YourFantasticLogo, contentProps: { logo: 'https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png', From 88961aa6409c52ebd7af67efd5134baf3c8ab424 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 8 Mar 2023 18:07:36 +0800 Subject: [PATCH 033/469] feat: optimize ts definition --- packages/designer/src/document/document-model.ts | 2 +- .../designer/src/document/node/modal-nodes-manager.ts | 2 +- packages/engine/src/engine-core.ts | 1 + packages/shell/src/model/resource.ts | 4 ++-- packages/types/src/shell/model/document-model.ts | 4 ++-- packages/types/src/shell/model/resource.ts | 6 +++++- packages/types/src/shell/type/on-change-options.ts | 6 ++++-- packages/types/src/shell/type/prop-change-options.ts | 6 ++++-- packages/types/src/shell/type/resource-list.ts | 9 ++++++++- packages/workspace/src/resource.ts | 4 ++-- 10 files changed, 30 insertions(+), 14 deletions(-) diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 7c4344c31e..89856d2eb6 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -326,7 +326,7 @@ export class DocumentModel implements IDocumentModel { }; } - onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): IPublicTypeDisposable { + onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions<INode>) => void): IPublicTypeDisposable { this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_VISIBLE_CHANGE, fn); return () => { diff --git a/packages/designer/src/document/node/modal-nodes-manager.ts b/packages/designer/src/document/node/modal-nodes-manager.ts index 8e04f72fc5..21c31ab46a 100644 --- a/packages/designer/src/document/node/modal-nodes-manager.ts +++ b/packages/designer/src/document/node/modal-nodes-manager.ts @@ -83,7 +83,7 @@ export class ModalNodesManager implements IModalNodesManager { } private addNode(node: INode) { - if (node.componentMeta.isModal) { + if (node?.componentMeta.isModal) { this.hideModalNodes(); this.modalNodes.push(node); this.addNodeEvent(node); diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index ea0554cad2..b038df8188 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -119,6 +119,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.canvas = canvas; context.plugins = plugins; context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); + context.workspace = workspace; }, }; diff --git a/packages/shell/src/model/resource.ts b/packages/shell/src/model/resource.ts index 1f037c6061..63435cdea2 100644 --- a/packages/shell/src/model/resource.ts +++ b/packages/shell/src/model/resource.ts @@ -37,7 +37,7 @@ export class Resource implements IPublicModelResource { return this[resourceSymbol].children.map((child) => new Resource(child)); } - get viewType() { - return this[resourceSymbol].viewType; + get viewName() { + return this[resourceSymbol].viewName; } } \ No newline at end of file diff --git a/packages/types/src/shell/model/document-model.ts b/packages/types/src/shell/model/document-model.ts index 99086d20db..b11ac6f085 100644 --- a/packages/types/src/shell/model/document-model.ts +++ b/packages/types/src/shell/model/document-model.ts @@ -179,13 +179,13 @@ export interface IPublicModelDocumentModel< * 当前 document 的节点 children 变更事件 * @param fn */ - onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): IPublicTypeDisposable; + onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions<Node>) => void): IPublicTypeDisposable; /** * 当前 document 节点属性修改事件 * @param fn */ - onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable; + onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions<Node>) => void): IPublicTypeDisposable; /** * import schema event diff --git a/packages/types/src/shell/model/resource.ts b/packages/types/src/shell/model/resource.ts index 5f26c8d7b9..c817766598 100644 --- a/packages/types/src/shell/model/resource.ts +++ b/packages/types/src/shell/model/resource.ts @@ -5,11 +5,15 @@ export interface IPublicModelResource { get icon(): ReactElement | undefined; - get options(): Object; + get options(): Record<string, any>; get name(): string | undefined; get type(): string | undefined; get category(): string | undefined; + + get children(): IPublicModelResource[]; + + get viewName(): string | undefined; } \ No newline at end of file diff --git a/packages/types/src/shell/type/on-change-options.ts b/packages/types/src/shell/type/on-change-options.ts index a1b0c314d5..47b88d72f7 100644 --- a/packages/types/src/shell/type/on-change-options.ts +++ b/packages/types/src/shell/type/on-change-options.ts @@ -1,6 +1,8 @@ import { IPublicModelNode } from '..'; -export interface IPublicTypeOnChangeOptions { +export interface IPublicTypeOnChangeOptions< + Node = IPublicModelNode +> { type: string; - node: IPublicModelNode; + node: Node; } diff --git a/packages/types/src/shell/type/prop-change-options.ts b/packages/types/src/shell/type/prop-change-options.ts index 2a351a2d60..b515aec537 100644 --- a/packages/types/src/shell/type/prop-change-options.ts +++ b/packages/types/src/shell/type/prop-change-options.ts @@ -3,10 +3,12 @@ import { IPublicModelProp, } from '../model'; -export interface IPublicTypePropChangeOptions { +export interface IPublicTypePropChangeOptions< + Node = IPublicModelNode +> { key?: string | number; prop?: IPublicModelProp; - node: IPublicModelNode; + node: Node; newValue: any; oldValue: any; } diff --git a/packages/types/src/shell/type/resource-list.ts b/packages/types/src/shell/type/resource-list.ts index bd5e4a3b05..db5e33dc8a 100644 --- a/packages/types/src/shell/type/resource-list.ts +++ b/packages/types/src/shell/type/resource-list.ts @@ -1,14 +1,21 @@ import { ReactElement } from 'react'; export interface IPublicResourceData { + /** 资源名字 */ resourceName: string; + /** 资源标题 */ title: string; + /** 分类 */ category?: string; - viewType?: string; + /** 资源视图 */ + viewName?: string; + /** 资源 icon */ icon?: ReactElement; + /** 资源其他配置 */ options: { [key: string]: any; }; + /** 资源子元素 */ children?: IPublicResourceData[]; } diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index 119bcc4881..ffb60ff6ac 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -17,8 +17,8 @@ export class Resource implements IPublicModelResource { return this.resourceType.name; } - get viewType() { - return this.resourceData.viewType; + get viewName() { + return this.resourceData.viewName || (this.resourceData as any).viewType; } get description() { From f6800be0e6529e0ea7dda439d46217108fdf738d Mon Sep 17 00:00:00 2001 From: kit101 <qkssk1711@163.com> Date: Thu, 9 Mar 2023 14:04:47 +0800 Subject: [PATCH 034/469] docs: fix incorrect content for emit method in event api --- docs/docs/api/event.md | 9 +++++---- packages/types/src/shell/api/event.ts | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/docs/api/event.md b/docs/docs/api/event.md index 0eb8b97382..9e2bdf641b 100644 --- a/docs/docs/api/event.md +++ b/docs/docs/api/event.md @@ -43,12 +43,13 @@ off(event: string, listener: (...args: any[]) => void): void; ```typescript /** - * 取消监听事件 - * cancel a monitor from a event + * 触发事件 + * emit a message for a event * @param event 事件名称 - * @param listener 事件回调 + * @param args 事件参数 + * @returns */ -off(event: string, listener: (...args: any[]) => void): void; +emit(event: string, ...args: any[]): void; ``` ## 使用示例 diff --git a/packages/types/src/shell/api/event.ts b/packages/types/src/shell/api/event.ts index 18e76febe0..02b8bc5b3f 100644 --- a/packages/types/src/shell/api/event.ts +++ b/packages/types/src/shell/api/event.ts @@ -21,7 +21,7 @@ export interface IPublicApiEvent { /** * 触发事件 - * emit a message fot a event + * emit a message for a event * @param event 事件名称 * @param args 事件参数 * @returns From 53ada7bf104cb5412eed6cd69b56c19cd57304d4 Mon Sep 17 00:00:00 2001 From: kit101 <qkssk1711@163.com> Date: Thu, 9 Mar 2023 14:04:47 +0800 Subject: [PATCH 035/469] docs: fix incorrect content for emit method in event api --- docs/docs/api/event.md | 9 +++++---- packages/types/src/shell/api/event.ts | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/docs/api/event.md b/docs/docs/api/event.md index 0eb8b97382..9e2bdf641b 100644 --- a/docs/docs/api/event.md +++ b/docs/docs/api/event.md @@ -43,12 +43,13 @@ off(event: string, listener: (...args: any[]) => void): void; ```typescript /** - * 取消监听事件 - * cancel a monitor from a event + * 触发事件 + * emit a message for a event * @param event 事件名称 - * @param listener 事件回调 + * @param args 事件参数 + * @returns */ -off(event: string, listener: (...args: any[]) => void): void; +emit(event: string, ...args: any[]): void; ``` ## 使用示例 diff --git a/packages/types/src/shell/api/event.ts b/packages/types/src/shell/api/event.ts index 18e76febe0..02b8bc5b3f 100644 --- a/packages/types/src/shell/api/event.ts +++ b/packages/types/src/shell/api/event.ts @@ -21,7 +21,7 @@ export interface IPublicApiEvent { /** * 触发事件 - * emit a message fot a event + * emit a message for a event * @param event 事件名称 * @param args 事件参数 * @returns From a8ab86ebb558c6aaba2b2384590c6db969029074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Thu, 9 Mar 2023 20:02:35 +0800 Subject: [PATCH 036/469] feat: add static field displayName for Component type --- .../src/plugins/component/react/containerClass.ts | 14 +++++++++++++- modules/code-generator/src/types/deps.ts | 2 +- modules/code-generator/src/utils/common.ts | 13 +++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/modules/code-generator/src/plugins/component/react/containerClass.ts b/modules/code-generator/src/plugins/component/react/containerClass.ts index 0758c893e2..b4c474b38a 100644 --- a/modules/code-generator/src/plugins/component/react/containerClass.ts +++ b/modules/code-generator/src/plugins/component/react/containerClass.ts @@ -26,7 +26,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { // 将模块名转换成 PascalCase 的格式,并添加特定后缀,防止命名冲突 const componentClassName = ensureValidClassName( - `${changeCase.pascalCase(ir.moduleName)}$$Page`, + `${changeCase.pascalCase(ir.moduleName)}$$${ir.containerType}`, ); next.chunks.push({ @@ -43,6 +43,18 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { ], }); + if (ir.containerType === 'Component') { + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: CLASS_DEFINE_CHUNK_NAME.InsVar, + content: `static displayName = '${changeCase.pascalCase(ir.moduleName)}';`, + linkAfter: [ + CLASS_DEFINE_CHUNK_NAME.Start, + ], + }); + } + next.chunks.push({ type: ChunkType.STRING, fileType: FileType.JSX, diff --git a/modules/code-generator/src/types/deps.ts b/modules/code-generator/src/types/deps.ts index cb2fb5eac4..a6531092d5 100644 --- a/modules/code-generator/src/types/deps.ts +++ b/modules/code-generator/src/types/deps.ts @@ -35,4 +35,4 @@ export interface IDependency { main?: string; // 包导出组件入口文件路径 /lib/input dependencyType?: DependencyType; // 依赖类型 内/外 componentName?: string; // 导入后名称 -} +} \ No newline at end of file diff --git a/modules/code-generator/src/utils/common.ts b/modules/code-generator/src/utils/common.ts index d822fdf811..fa7ab30a95 100644 --- a/modules/code-generator/src/utils/common.ts +++ b/modules/code-generator/src/utils/common.ts @@ -1,6 +1,7 @@ import type { IPublicTypeJSExpression, IPublicTypeJSFunction } from '@alilc/lowcode-types'; import changeCase from 'change-case'; import short from 'short-uuid'; +import { DependencyType, IDependency, IExternalDependency, IInternalDependency } from '../types'; // Doc: https://www.npmjs.com/package/change-case @@ -43,4 +44,16 @@ export function getStaticExprValue<T>(expr: string): T { export function isJSExpressionFn(data: any): data is IPublicTypeJSFunction { return data?.type === 'JSExpression' && data?.extType === 'function'; +} + +export function isInternalDependency( + dependency: IDependency, +): dependency is IInternalDependency { + return dependency.dependencyType === DependencyType.Internal; +} + +export function isExternalDependency( + dependency: IDependency, +): dependency is IExternalDependency { + return dependency.dependencyType === DependencyType.External; } \ No newline at end of file From 8474644e9991c5d4c2c837c7eade2684d857d186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Fri, 10 Mar 2023 10:37:18 +0800 Subject: [PATCH 037/469] chore: make the second argument of module post processor optional --- modules/code-generator/src/types/core.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/src/types/core.ts b/modules/code-generator/src/types/core.ts index 1a85db965d..33abad1d10 100644 --- a/modules/code-generator/src/types/core.ts +++ b/modules/code-generator/src/types/core.ts @@ -197,7 +197,7 @@ export type ProjectPostProcessor = ( export type PostProcessorFactory<T> = (config?: T) => PostProcessor; /** 模块级别的后置处理器 */ -export type PostProcessor = (content: string, fileType: string, name: string) => string; +export type PostProcessor = (content: string, fileType: string, name?: string) => string; // TODO: temp interface, need modify export interface IPluginOptions { From c61694581b5dd0dbb9456c196178b00f04048df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Fri, 10 Mar 2023 10:37:33 +0800 Subject: [PATCH 038/469] Revert "fix: use original moduleName" This reverts commit 676e49ee2c48b01807d9220e6a554e24126aa6cc. --- modules/code-generator/src/parser/SchemaParser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/src/parser/SchemaParser.ts b/modules/code-generator/src/parser/SchemaParser.ts index 24fc686878..3108fee477 100644 --- a/modules/code-generator/src/parser/SchemaParser.ts +++ b/modules/code-generator/src/parser/SchemaParser.ts @@ -161,7 +161,7 @@ export class SchemaParser implements ISchemaParser { ...subRoot, componentName: getRootComponentName(subRoot.componentName, compDeps), containerType: subRoot.componentName, - moduleName: subRoot.fileName, + moduleName: ensureValidClassName(changeCase.pascalCase(subRoot.fileName)), }; return container; }); From 531cc9c09d94ca137517c1a320dd703c5c583cb9 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 10 Mar 2023 11:43:14 +0800 Subject: [PATCH 039/469] chore(release): publish 1.1.3 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 10 +++++----- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 67 insertions(+), 67 deletions(-) diff --git a/lerna.json b/lerna.json index 8ca861e34c..b1ce00bbf5 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.2", + "version": "1.1.3", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 663e5d91c4..ec63d191c5 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.2", + "version": "1.1.3", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index a3e799761a..87022ad09b 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.1.2", + "version": "1.1.3", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 3477ba1d5c..d799bb68ba 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.1.2", + "version": "1.1.3", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -18,10 +18,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 6edbe7ac02..768b80ffd4 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.2", + "version": "1.1.3", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-editor-skeleton": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-editor-skeleton": "1.1.3", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.2", - "@alilc/lowcode-plugin-outline-pane": "1.1.2", - "@alilc/lowcode-shell": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", - "@alilc/lowcode-workspace": "1.1.2", + "@alilc/lowcode-plugin-designer": "1.1.3", + "@alilc/lowcode-plugin-outline-pane": "1.1.3", + "@alilc/lowcode-shell": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-workspace": "1.1.3", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 92f19ca676..71ea2b4c0b 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.2", + "version": "1.1.3", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index fd0a246a68..ca426b6ebc 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.1.2", + "version": "1.1.3", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 5a9147a8d2..ff05813c4f 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.1.2", + "version": "1.1.3", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,10 +13,10 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index d6270e1f82..50209be4ed 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.1.2", + "version": "1.1.3", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-renderer-core": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 2ff493c2eb..e5b08717da 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.1.2", + "version": "1.1.3", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-rax-renderer": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-rax-renderer": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 7ac9336479..b897eea682 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.1.2", + "version": "1.1.3", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.1.2" + "@alilc/lowcode-renderer-core": "1.1.3" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 7c5868f3cd..49c991f2ac 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.1.2", + "version": "1.1.3", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-react-renderer": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-react-renderer": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index deb30be11e..aa1c7d2046 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.1.2", + "version": "1.1.3", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index a475a05bf3..7608df5f5d 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.2", + "version": "1.1.3", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,12 +15,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-editor-skeleton": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", - "@alilc/lowcode-workspace": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-editor-skeleton": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-workspace": "1.1.3", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index d36e7fb210..351c0311d2 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.2", + "version": "1.1.3", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 7ed3787a75..4f391d23c4 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.2", + "version": "1.1.3", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.2", + "@alilc/lowcode-types": "1.1.3", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 4bd99eaf9a..ef80c7d671 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.2", + "version": "1.1.3", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-editor-skeleton": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-editor-skeleton": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 9ab2934aacbceea75e4317a8e758489f45d2ddea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Fri, 10 Mar 2023 14:52:09 +0800 Subject: [PATCH 040/469] chore(release): code-generator - 1.0.8 --- modules/code-generator/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index 97863584cd..72388a4ac4 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-code-generator", - "version": "1.0.7", + "version": "1.0.8", "description": "出码引擎 for LowCode Engine", "license": "MIT", "main": "lib/index.js", From 108108cf51e26e9aeafb2b9e98ac530c54f205d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Fri, 10 Mar 2023 16:00:00 +0800 Subject: [PATCH 041/469] chore: fix ts errors --- modules/code-generator/src/types/core.ts | 3 ++- modules/code-generator/src/utils/nodeToJSX.ts | 2 +- modules/code-generator/src/utils/schema.ts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/code-generator/src/types/core.ts b/modules/code-generator/src/types/core.ts index 33abad1d10..fb2a780c10 100644 --- a/modules/code-generator/src/types/core.ts +++ b/modules/code-generator/src/types/core.ts @@ -178,7 +178,8 @@ export interface IProjectBuilder { } /** 项目级别的前置处理器 */ -export type ProjectPreProcessor = (schema: IPublicTypeProjectSchema) => Promise<IPublicTypeProjectSchema> | IPublicTypeProjectSchema; +export type ProjectPreProcessor = (schema: IPublicTypeProjectSchema) => + Promise<IPublicTypeProjectSchema> | IPublicTypeProjectSchema; export interface ProjectPostProcessorOptions { parseResult?: IParseResult; diff --git a/modules/code-generator/src/utils/nodeToJSX.ts b/modules/code-generator/src/utils/nodeToJSX.ts index 73dba862cf..ad79288bab 100644 --- a/modules/code-generator/src/utils/nodeToJSX.ts +++ b/modules/code-generator/src/utils/nodeToJSX.ts @@ -126,7 +126,7 @@ function generateAttrs( if (props) { if (!Array.isArray(props)) { Object.keys(props).forEach((propName: string) => { - pieces = pieces.concat(generateAttr(propName, props[propName], scope, config)); + pieces = pieces.concat(generateAttr(propName, props[propName] as IPublicTypeCompositeValue, scope, config)); }); } else { props.forEach((prop) => { diff --git a/modules/code-generator/src/utils/schema.ts b/modules/code-generator/src/utils/schema.ts index 0b8295aac3..831b38965a 100644 --- a/modules/code-generator/src/utils/schema.ts +++ b/modules/code-generator/src/utils/schema.ts @@ -101,7 +101,7 @@ export function handleSubNodes<T>( }); } else { Object.values(child.props).forEach((value) => { - const childRes = handleCompositeValueInProps(value); + const childRes = handleCompositeValueInProps(value as IPublicTypeCompositeValue); childrenRes.push(...childRes); }); } From 608b99eb97baddc20d68b448f6f14195f8669718 Mon Sep 17 00:00:00 2001 From: BARM <284942955@qq.com> Date: Fri, 10 Mar 2023 16:22:05 +0800 Subject: [PATCH 042/469] docs: update skeleton.md (#1699) * docs: update skeleton.md --- docs/docs/api/skeleton.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index 6c8d898ff1..43a1423178 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -90,7 +90,7 @@ Widget 形式是直接渲染在当前编辑器的对应位置上。如 demo 中 接入可以参考代码: ```javascript -import {skeleton} from "@alilc/lowcode-engine"; +import { skeleton } from "@alilc/lowcode-engine"; // 注册 logo 面板 skeleton.add({ area: "topArea", @@ -119,18 +119,15 @@ skeleton.add({ area: "leftArea", type: "Dock", name: "opener", - content: Opener, // Widget 组件实例 - contentProps: { // Widget 插件 props - xxx: "1", - }, props: { + icon: Icon, // Icon 组件实例 align: "bottom", - }, - onClick: function() { - // 打开外部链接 - window.open('https://lowcode-engine.cn'); - // 显示 widget - skeleton.showWidget('xxx'); + onClick: function () { + // 打开外部链接 + window.open('https://lowcode-engine.cn'); + // 显示 widget + skeleton.showWidget('xxx'); + } } }); ``` From 303e445eda5ca0ac6220b1d2a59e2f308128b0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 13 Mar 2023 14:28:52 +0800 Subject: [PATCH 043/469] docs: update docs/docs/article/index.md (#1708) --- docs/docs/article/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index ed8b05ec06..5a065e9971 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -4,6 +4,7 @@ title: 低代码引擎相关文章资料 ## 官方文章 +- [基于 LowCodeEngine 的低代码组件体系的建设和实践](https://mp.weixin.qq.com/s/rnvbGHImGt6oJuX2wCtaqw) - [低代码多分支协同开发的建设与实践](https://mp.weixin.qq.com/s/DmwxL67htHfTUP1U966N-Q) - [低代码引擎半岁啦,来跟大家唠唠嗑...](https://segmentfault.com/a/1190000042884409) - [低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ) From a09ef543c55a39fdc0944000d43c10eb26df9e25 Mon Sep 17 00:00:00 2001 From: BARM <ccz_work@189.cn> Date: Mon, 13 Mar 2023 10:35:06 +0800 Subject: [PATCH 044/469] Update skeleton.md --- docs/docs/api/skeleton.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index 43a1423178..bcf4225db0 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -156,7 +156,7 @@ IWidgetBaseConfig 定义如下: | --- | --- | --- | | name | 面板名称 | | | area | 扩展区位置,可选值:'topArea' | 'leftArea' | 'rightArea' | 'toolbar' | 'bottomArea' | 'mainArea' | | -| type | 面板类型,可选值:'Widget' | 'PanelDock' | 'Panel' | 详见前文中对**展示类型**的描述 | +| type | 面板类型,可选值:'Widget' | 'PanelDock' | 'Panel' | Dock | 详见前文中对**展示类型**的描述 | | content | 面板的实现类/节点,类型是 ReactClass | ReactElement | | | props | 面板属性 | align: 'top' | 'bottom' | 'left' | 'center' | 'right'; // 指定面板 icon 位置区域<br />icon: string | ReactElement;  // icon 为字符串时,请确定当前 fusion 主题包中包含该 icon<br />description: string;<br />condition: Function; // 指定当前面板的显影状态 | | contentProps | 面板的实现类/节点的参数 | | @@ -417,7 +417,7 @@ skeleton.disableWidget('sourceEditor'); import { skeleton } from '@alilc/lowcode-engine'; skeleton.add({ - name: 'bottomAreaPanelName', + name: 'bottomAreaPanelName', area: 'bottomArea', type: 'Panel', content: () => 'demoText', From 4433b2ee78590e39113efa22044ffe10154d5c8c Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 14 Mar 2023 11:08:42 +0800 Subject: [PATCH 045/469] fix: fix ts error --- .../designer/src/builtin-simulator/host.ts | 66 +++++++++++-------- .../src/builtin-simulator/renderer.ts | 3 +- .../src/builtin-simulator/utils/clickable.ts | 4 +- packages/designer/src/component-meta.ts | 8 ++- packages/designer/src/designer/designer.ts | 39 ++++++----- packages/designer/src/designer/dragon.ts | 11 ++-- packages/designer/src/designer/location.ts | 2 +- .../src/designer/setting/setting-entry.ts | 31 +++++---- .../src/designer/setting/setting-field.ts | 44 +++++++++---- .../designer/setting/setting-prop-entry.ts | 21 +++--- .../designer/src/document/document-model.ts | 49 ++++++++++---- .../designer/src/document/document-view.tsx | 6 +- packages/designer/src/document/history.ts | 10 +-- .../src/document/node/exclusive-group.ts | 6 ++ .../src/document/node/node-children.ts | 4 +- packages/designer/src/document/node/node.ts | 25 ++++--- .../designer/src/document/node/props/prop.ts | 14 ++-- packages/designer/src/document/selection.ts | 2 +- packages/designer/src/project/project.ts | 18 ++--- packages/designer/src/simulator.ts | 6 +- .../src/components/settings/settings-pane.tsx | 21 +++--- .../settings/settings-primary-pane.tsx | 19 ++++-- packages/editor-skeleton/src/types.ts | 2 +- packages/types/src/shell/api/project.ts | 22 ++++--- packages/types/src/shell/model/dragon.ts | 6 +- packages/types/src/shell/model/index.ts | 2 + packages/types/src/shell/model/node.ts | 3 +- packages/types/src/shell/model/sensor.ts | 7 +- .../types/src/shell/model/setting-entry.ts | 20 ++++++ .../types/src/shell/model/setting-field.ts | 5 ++ .../types/src/shell/model/setting-target.ts | 18 +++-- .../types/src/shell/type/dynamic-setter.ts | 5 +- packages/types/src/shell/type/location.ts | 6 +- packages/types/src/shell/type/metadata.ts | 6 +- .../types/src/shell/type/node-instance.ts | 7 +- .../types/src/shell/type/title-content.ts | 4 +- .../utils/src/check-types/is-i18n-data.ts | 4 +- .../is-location-children-detail.ts | 4 +- .../check-types/is-procode-component-type.ts | 4 +- .../utils/src/check-types/is-setting-field.ts | 4 +- .../utils/src/check-types/is-title-config.ts | 4 +- packages/utils/src/node-helper.ts | 10 +-- 42 files changed, 356 insertions(+), 196 deletions(-) create mode 100644 packages/types/src/shell/model/setting-entry.ts create mode 100644 packages/types/src/shell/model/setting-field.ts diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 1eb228f295..6415a1b4c6 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -67,7 +67,7 @@ import { BuiltinSimulatorRenderer } from './renderer'; import { clipboard } from '../designer/clipboard'; import { LiveEditing } from './live-editing/live-editing'; import { Project } from '../project'; -import { Scroller } from '../designer/scroller'; +import { IScroller } from '../designer/scroller'; import { isElementNode, isDOMNodeVisible } from '../utils/misc'; import { debounce } from 'lodash'; @@ -170,7 +170,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp readonly viewport = new Viewport(); - readonly scroller: Scroller; + readonly scroller: IScroller; readonly emitter: IEventBus = createModuleEventBus('BuiltinSimulatorHost'); @@ -381,7 +381,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp // todo } - mountViewport(viewport: Element | null) { + mountViewport(viewport: HTMLElement | null) { this.viewport.mount(viewport); } @@ -510,7 +510,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp // TODO: dispose the bindings } - async setupComponents(library) { + async setupComponents(library: LibraryItem[]) { const libraryAsset: AssetList = this.buildLibrary(library); await this.renderer?.load(libraryAsset); if (Object.keys(this.asyncLibraryMap).length > 0) { @@ -576,7 +576,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp const isRGLNode = rglNode?.isRGLContainer; if (isRGLNode) { // 如果拖拽的是磁铁块的右下角 handle,则直接跳过 - if (downEvent.target.classList.contains('react-resizable-handle')) return; + if (downEvent.target?.classList.contains('react-resizable-handle')) return; // 禁止多选 isMulti = false; designer.dragon.emitter.emit('rgl.switch', { @@ -605,7 +605,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp if (!isShaken(downEvent, e) || isRGLNode) { let { id } = node; designer.activeTracker.track({ node, instance: nodeInst?.instance }); - if (isMulti && !node.contains(focusNode) && selection.has(id)) { + if (isMulti && focusNode && !node.contains(focusNode) && selection.has(id)) { selection.remove(id); } else { // TODO: 避免选中 Page 组件,默认选中第一个子节点;新增规则 或 判断 Live 模式 @@ -613,7 +613,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp const firstChildId = node.getChildren()?.get(0)?.getId(); if (firstChildId) id = firstChildId; } - selection.select(node.contains(focusNode) ? focusNode.id : id); + if (focusNode) { + selection.select(node.contains(focusNode) ? focusNode.id : id); + } // dirty code should refector const editor = this.designer?.editor; @@ -629,8 +631,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp } }; - if (isLeftButton && !node.contains(focusNode)) { - let nodes: Node[] = [node]; + if (isLeftButton && focusNode && !node.contains(focusNode)) { + let nodes: INode[] = [node]; let ignoreUpSelected = false; if (isMulti) { // multi select mode, directily add @@ -639,7 +641,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp selection.add(node.id); ignoreUpSelected = true; } - selection.remove(focusNode.id); + focusNode?.id && selection.remove(focusNode.id); // 获得顶层 nodes nodes = selection.getTopNodes(); } else if (selection.containsNode(node, true)) { @@ -727,7 +729,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp if (nodeInst?.node) { let { node } = nodeInst; const focusNode = node.document?.focusNode; - if (node.contains(focusNode)) { + if (focusNode && node.contains(focusNode)) { node = focusNode; } detecting.capture(node); @@ -738,7 +740,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp e.stopPropagation(); } }; - const leave = () => detecting.leave(this.project.currentDocument); + const leave = () => { + this.project.currentDocument && detecting.leave(this.project.currentDocument) + }; doc.addEventListener('mouseover', hover, true); doc.addEventListener('mouseleave', leave, false); @@ -912,8 +916,11 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp /** * @see ISimulator */ - getComponentInstances(node: Node, context?: IPublicTypeNodeInstance): IPublicTypeComponentInstance[] | null { - const docId = node.document.id; + getComponentInstances(node: INode, context?: IPublicTypeNodeInstance): IPublicTypeComponentInstance[] | null { + const docId = node.document?.id; + if (!docId) { + return null; + } const instances = this.instancesMap[docId]?.get(node.id) || null; if (!instances || !context) { @@ -946,7 +953,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp /** * @see ISimulator */ - computeRect(node: Node): IPublicTypeRect | null { + computeRect(node: INode): IPublicTypeRect | null { const instances = this.getComponentInstances(node); if (!instances) { return null; @@ -1042,7 +1049,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp /** * 通过 DOM 节点获取节点,依赖 simulator 的接口 */ - getNodeInstanceFromElement(target: Element | null): IPublicTypeNodeInstance<IPublicTypeComponentInstance> | null { + getNodeInstanceFromElement(target: Element | null): IPublicTypeNodeInstance<IPublicTypeComponentInstance, INode> | null { if (!target) { return null; } @@ -1215,7 +1222,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp return null; } const dropContainer = this.getDropContainer(e); - const lockedNode = getClosestNode(dropContainer?.container as Node, (node) => node.isLocked); + const lockedNode = getClosestNode(dropContainer?.container, (node) => node.isLocked); if (lockedNode) return null; if ( !dropContainer @@ -1257,7 +1264,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp e.dragObject && e.dragObject.nodes && e.dragObject.nodes.length && - e.dragObject.nodes[0].componentMeta.isModal + e.dragObject.nodes[0].componentMeta.isModal && + document.focusNode ) { return this.designer.createLocation({ target: document.focusNode, @@ -1372,8 +1380,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp const isAny = isDragAnyObject(dragObject); const document = this.project.currentDocument!; const { currentRoot } = document; - let container: INode; - let nodeInstance: IPublicTypeNodeInstance<IPublicTypeComponentInstance> | undefined; + let container: INode | null; + let nodeInstance: IPublicTypeNodeInstance<IPublicTypeComponentInstance, INode> | undefined; if (target) { const ref = this.getNodeInstanceFromElement(target); @@ -1391,8 +1399,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp container = currentRoot; } - if (!container.isParental()) { - container = container.parent || currentRoot; + if (!container?.isParental()) { + container = container?.parent || currentRoot; } // TODO: use spec container to accept specialData @@ -1402,7 +1410,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp } // get common parent, avoid drop container contains by dragObject - const drillDownExcludes = new Set<Node>(); + const drillDownExcludes = new Set<INode>(); if (isDragNodeObject(dragObject)) { const { nodes } = dragObject; let i = nodes.length; @@ -1414,7 +1422,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp } if (p !== container) { container = p || document.focusNode; - drillDownExcludes.add(container); + container && drillDownExcludes.add(container); } } @@ -1425,11 +1433,11 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp } else { instance = this.getClosestNodeInstance( nodeInstance.instance as any, - container.id, + container?.id, )?.instance; } } else { - instance = this.getComponentInstances(container)?.[0]; + instance = container && this.getComponentInstances(container)?.[0]; } let dropContainer: DropContainer = { @@ -1457,7 +1465,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp container = container.parent; instance = this.getClosestNodeInstance(dropContainer.instance, container.id)?.instance; dropContainer = { - container: container as INode, + container: container, instance, }; } else { @@ -1500,7 +1508,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp */ getNearByContainer( { container, instance }: DropContainer, - drillDownExcludes: Set<Node>, + drillDownExcludes: Set<INode>, e: ILocateEvent, ) { const { children } = container; @@ -1519,7 +1527,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp } if (child.conditionGroup) { const bn = child.conditionGroup; - i = bn.index + bn.length - 1; + i = (bn.index || 0) + bn.length - 1; child = bn.visibleNode; } if (!child.isParental() || drillDownExcludes.has(child)) { diff --git a/packages/designer/src/builtin-simulator/renderer.ts b/packages/designer/src/builtin-simulator/renderer.ts index d9171c355a..43a1532229 100644 --- a/packages/designer/src/builtin-simulator/renderer.ts +++ b/packages/designer/src/builtin-simulator/renderer.ts @@ -1,5 +1,5 @@ import { Component } from '../simulator'; -import { IPublicTypeNodeSchema, IPublicTypeComponentInstance, IPublicTypeNodeInstance } from '@alilc/lowcode-types'; +import { IPublicTypeNodeSchema, IPublicTypeComponentInstance, IPublicTypeNodeInstance, Asset } from '@alilc/lowcode-types'; export interface BuiltinSimulatorRenderer { readonly isSimulatorRenderer: true; @@ -22,6 +22,7 @@ export interface BuiltinSimulatorRenderer { stopAutoRepaintNode(): void; enableAutoRepaintNode(): void; run(): void; + load(asset: Asset): Promise<any>; } export function isSimulatorRenderer(obj: any): obj is BuiltinSimulatorRenderer { diff --git a/packages/designer/src/builtin-simulator/utils/clickable.ts b/packages/designer/src/builtin-simulator/utils/clickable.ts index d1646254d3..5413ad5c52 100644 --- a/packages/designer/src/builtin-simulator/utils/clickable.ts +++ b/packages/designer/src/builtin-simulator/utils/clickable.ts @@ -1,5 +1,5 @@ import { getClosestNode, canClickNode } from '@alilc/lowcode-utils'; -import { Node } from '../../document'; +import { INode } from '../../document'; /** * 获取离当前节点最近的可点击节点 @@ -7,7 +7,7 @@ import { Node } from '../../document'; * @param event */ export const getClosestClickableNode = ( - currentNode: Node | undefined | null, + currentNode: INode | undefined | null, event: MouseEvent, ) => { let node = currentNode; diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 2691a89717..80f99c05bc 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -58,6 +58,10 @@ export function buildFilter(rule?: string | string[] | RegExp | IPublicTypeNesti export interface IComponentMeta extends IPublicModelComponentMeta<INode> { prototype?: any; + + setMetadata(metadata: IPublicTypeComponentMetadata): void; + + get rootSelector(): string | undefined; } export class ComponentMeta implements IComponentMeta { @@ -332,7 +336,7 @@ export class ComponentMeta implements IComponentMeta { if (this.parentWhitelist) { return this.parentWhitelist( parent.internalToShellNode(), - isNode(my) ? my.internalToShellNode() : my, + isNode<INode>(my) ? my.internalToShellNode() : my, ); } return true; @@ -343,7 +347,7 @@ export class ComponentMeta implements IComponentMeta { if (this.childWhitelist) { const _target: any = !Array.isArray(target) ? [target] : target; return _target.every((item: Node | IPublicTypeNodeSchema) => { - const _item = !isNode(item) ? new Node(my.document, item) : item; + const _item = !isNode<INode>(item) ? new Node(my.document, item) : item; return ( this.childWhitelist && this.childWhitelist(_item.internalToShellNode(), my.internalToShellNode()) diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 3e2ff6dd21..c26d9fb4b3 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -18,6 +18,7 @@ import { IPublicEnumTransformStage, IPublicModelDragon, IPublicModelDropLocation, + IPublicModelLocateEvent, } from '@alilc/lowcode-types'; import { megreAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils'; import { Project } from '../project'; @@ -45,15 +46,15 @@ export interface DesignerProps { defaultSchema?: IPublicTypeProjectSchema; hotkeys?: object; viewName?: string; - simulatorProps?: object | ((document: DocumentModel) => object); + simulatorProps?: Record<string, any> | ((document: DocumentModel) => object); simulatorComponent?: ComponentType<any>; dragGhostComponent?: ComponentType<any>; suspensed?: boolean; componentMetadatas?: IPublicTypeComponentMetadata[]; globalComponentActions?: IPublicTypeComponentAction[]; onMount?: (designer: Designer) => void; - onDragstart?: (e: ILocateEvent) => void; - onDrag?: (e: ILocateEvent) => void; + onDragstart?: (e: IPublicModelLocateEvent) => void; + onDrag?: (e: IPublicModelLocateEvent) => void; onDragend?: ( e: { dragObject: IPublicModelDragObject; copy: boolean }, loc?: DropLocation, @@ -73,12 +74,14 @@ export interface IDesigner { get detecting(): Detecting; + get simulatorComponent(): ComponentType<any> | undefined; + createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller; /** * 创建插入位置,考虑放到 dragon 中 */ - createLocation(locationData: IPublicTypeLocationData): IPublicModelDropLocation; + createLocation(locationData: IPublicTypeLocationData<INode>): DropLocation; get componentsMap(): { [key: string]: IPublicTypeNpmInfo | Component }; @@ -100,6 +103,8 @@ export interface IDesigner { transformProps(props: IPublicTypeCompositeObject | IPublicTypePropsList, node: Node, stage: IPublicEnumTransformStage): IPublicTypeCompositeObject | IPublicTypePropsList; createSettingEntry(nodes: INode[]): ISettingTopEntry; + + autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions<any, any>): IReactionDisposer; } export class Designer implements IDesigner { @@ -196,7 +201,7 @@ export class Designer implements IDesigner { const loc = this._dropLocation; if (loc) { if (isLocationChildrenDetail(loc.detail) && loc.detail.valid !== false) { - let nodes: Node[] | undefined; + let nodes: INode[] | undefined; if (isDragNodeObject(dragObject)) { nodes = insertChildren(loc.target, [...dragObject.nodes], loc.detail.index, copy); } else if (isDragNodeDataObject(dragObject)) { @@ -209,7 +214,7 @@ export class Designer implements IDesigner { nodes = insertChildren(loc.target, nodeData, loc.detail.index); } if (nodes) { - loc.document.selection.selectAll(nodes.map((o) => o.id)); + loc.document?.selection.selectAll(nodes.map((o) => o.id)); setTimeout(() => this.activeTracker.track(nodes![0]), 10); } } @@ -222,7 +227,7 @@ export class Designer implements IDesigner { }); this.activeTracker.onChange(({ node, detail }) => { - node.document.simulator?.scrollToNode(node, detail); + node.document?.simulator?.scrollToNode(node, detail); }); let historyDispose: undefined | (() => void); @@ -264,8 +269,8 @@ export class Designer implements IDesigner { currentSelection.selected.length === 0 && this.simulatorProps?.designMode === 'live' ) { - const rootNodeChildrens = this.currentDocument.getRoot().getChildren().children; - if (rootNodeChildrens.length > 0) { + const rootNodeChildrens = this.currentDocument?.getRoot()?.getChildren()?.children; + if (rootNodeChildrens && rootNodeChildrens.length > 0) { currentSelection.select(rootNodeChildrens[0].id); } } @@ -288,14 +293,16 @@ export class Designer implements IDesigner { /** * 创建插入位置,考虑放到 dragon 中 */ - createLocation(locationData: IPublicTypeLocationData): DropLocation { + createLocation(locationData: IPublicTypeLocationData<INode>): DropLocation { const loc = new DropLocation(locationData); - if (this._dropLocation && this._dropLocation.document !== loc.document) { + if (this._dropLocation && this._dropLocation.document && this._dropLocation.document !== loc.document) { this._dropLocation.document.dropLocation = null; } this._dropLocation = loc; this.postEvent('dropLocation.change', loc); - loc.document.dropLocation = loc; + if (loc.document) { + loc.document.dropLocation = loc; + } this.activeTracker.track({ node: loc.target, detail: loc.detail }); return loc; } @@ -304,7 +311,7 @@ export class Designer implements IDesigner { * 清除插入位置 */ clearLocation() { - if (this._dropLocation) { + if (this._dropLocation && this._dropLocation.document) { this._dropLocation.document.dropLocation = null; } this.postEvent('dropLocation.change', undefined); @@ -376,7 +383,7 @@ export class Designer implements IDesigner { } else { // FIXME!!, parent maybe null target = refNode.parent!; - index = refNode.index + 1; + index = (refNode.index || 0) + 1; } if (target && insertNode && !target.componentMeta.checkNestingDown(target, insertNode)) { @@ -467,7 +474,7 @@ export class Designer implements IDesigner { return this._simulatorComponent; } - @computed get simulatorProps(): object { + @computed get simulatorProps(): Record<string, any> { if (typeof this._simulatorProps === 'function') { return this._simulatorProps(this.project); } @@ -622,7 +629,7 @@ export class Designer implements IDesigner { } } - autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions): IReactionDisposer { + autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions<any, any>): IReactionDisposer { return autorun(effect, options); } diff --git a/packages/designer/src/designer/dragon.ts b/packages/designer/src/designer/dragon.ts index 29a67a9ab2..2fc0ca3e5b 100644 --- a/packages/designer/src/designer/dragon.ts +++ b/packages/designer/src/designer/dragon.ts @@ -23,7 +23,6 @@ export interface ILocateEvent extends IPublicModelLocateEvent { * 激活的感应器 */ sensor?: IPublicModelSensor; - } /** @@ -97,7 +96,7 @@ function isDragEvent(e: any): e is DragEvent { } export interface IDragon extends IPublicModelDragon { - + emitter: IEventBus; } /** @@ -106,6 +105,8 @@ export interface IDragon extends IPublicModelDragon { export class Dragon implements IDragon { private sensors: IPublicModelSensor[] = []; + private nodeInstPointerEvents: boolean; + key = Math.random(); /** @@ -127,7 +128,7 @@ export class Dragon implements IDragon { viewName: string | undefined; - private emitter: IEventBus = createModuleEventBus('Dragon'); + emitter: IEventBus = createModuleEventBus('Dragon'); constructor(readonly designer: Designer) { makeObservable(this); @@ -356,8 +357,8 @@ export class Dragon implements IDragon { rglNode, node: tarNode, }); - const { selection } = designer.project.currentDocument; - selection.select(tarNode.id); + const selection = designer.project.currentDocument?.selection; + selection?.select(tarNode.id); } } } diff --git a/packages/designer/src/designer/location.ts b/packages/designer/src/designer/location.ts index ccf26e325a..00ee4681cf 100644 --- a/packages/designer/src/designer/location.ts +++ b/packages/designer/src/designer/location.ts @@ -122,7 +122,7 @@ export class DropLocation implements IDropLocation { return this.target.document; } - constructor({ target, detail, source, event }: IPublicTypeLocationData) { + constructor({ target, detail, source, event }: IPublicTypeLocationData<INode>) { this.target = target; this.detail = detail; this.source = source; diff --git a/packages/designer/src/designer/setting/setting-entry.ts b/packages/designer/src/designer/setting/setting-entry.ts index 39f978a707..9b0d4846a3 100644 --- a/packages/designer/src/designer/setting/setting-entry.ts +++ b/packages/designer/src/designer/setting/setting-entry.ts @@ -1,17 +1,26 @@ -import { IPublicModelSettingTarget } from '@alilc/lowcode-types'; +import { IBaseModelSettingEntry, IPublicModelSettingPropEntry, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; import { IComponentMeta } from '../../component-meta'; -import { Designer } from '../designer'; +import { IDesigner } from '../designer'; import { INode } from '../../document'; -export interface ISettingEntry extends IPublicModelSettingTarget { - readonly nodes: INode[]; - readonly componentMeta: IComponentMeta | null; - readonly designer: Designer; +export interface ISettingEntry extends IBaseModelSettingEntry< + INode, + IComponentMeta, + ISettingEntry +> { + readonly designer: IDesigner; - // 顶端 - readonly top: ISettingEntry; - // 父级 - readonly parent: ISettingEntry; + readonly isGroup: boolean; - get: (propName: string | number) => ISettingEntry | null; + readonly id: string; + + get name(): string | number | undefined; + + internalToShellPropEntry(): IPublicModelSettingPropEntry; + + valueChange(options: IPublicTypeSetValueOptions): void; + + get valueState(): number; + + clearValue(): void; } diff --git a/packages/designer/src/designer/setting/setting-field.ts b/packages/designer/src/designer/setting/setting-field.ts index c073e28548..da374f9bb6 100644 --- a/packages/designer/src/designer/setting/setting-field.ts +++ b/packages/designer/src/designer/setting/setting-field.ts @@ -1,3 +1,4 @@ +import { ReactNode } from 'react'; import { IPublicTypeTitleContent, IPublicTypeSetterType, @@ -25,8 +26,29 @@ function getSettingFieldCollectorKey(parent: ISettingEntry, config: IPublicTypeF return path.join('.'); } -export interface ISettingField extends ISettingEntry { +export interface ISettingField extends Omit<ISettingEntry, 'setValue'> { + get items(): Array<ISettingField | IPublicTypeCustomView>; + get title(): string | ReactNode | undefined; + + purge(): void; + + extraProps: IPublicTypeFieldExtraProps; + + get setter(): IPublicTypeSetterType | null; + + get expanded(): boolean; + + readonly isRequired: boolean; + + setExpanded(value: boolean): void; + + setValue( + val: any, + isHotValue?: boolean, + force?: boolean, + extraOptions?: IPublicTypeSetValueOptions, + ): void; } export class SettingField extends SettingPropEntry implements ISettingField { @@ -57,12 +79,12 @@ export class SettingField extends SettingPropEntry implements ISettingField { @obx.ref private _expanded = true; - private _items: Array<SettingField | IPublicTypeCustomView> = []; + private _items: Array<ISettingField | IPublicTypeCustomView> = []; constructor( parent: ISettingEntry, config: IPublicTypeFieldConfig, - private settingFieldCollector?: (name: string | number, field: SettingField) => void, + private settingFieldCollector?: (name: string | number, field: ISettingField) => void, ) { super(parent, config.name, config.type); makeObservable(this); @@ -97,7 +119,7 @@ export class SettingField extends SettingPropEntry implements ISettingField { if (isDynamicSetter(this._setter)) { return untracked(() => { const shellThis = this.internalToShellPropEntry(); - return this._setter.call(shellThis, shellThis); + return (this._setter as IPublicTypeDynamicSetter)?.call(shellThis, shellThis); }); } return this._setter; @@ -111,7 +133,7 @@ export class SettingField extends SettingPropEntry implements ISettingField { this._expanded = value; } - get items(): Array<SettingField | IPublicTypeCustomView> { + get items(): Array<ISettingField | IPublicTypeCustomView> { return this._items; } @@ -122,8 +144,8 @@ export class SettingField extends SettingPropEntry implements ISettingField { private initItems( items: Array<IPublicTypeFieldConfig | IPublicTypeCustomView>, settingFieldCollector?: { - (name: string | number, field: SettingField): void; - (name: string, field: SettingField): void; + (name: string | number, field: ISettingField): void; + (name: string, field: ISettingField): void; }, ) { this._items = items.map((item) => { @@ -140,7 +162,7 @@ export class SettingField extends SettingPropEntry implements ISettingField { } // 创建子配置项,通常用于 object/array 类型数据 - createField(config: IPublicTypeFieldConfig): SettingField { + createField(config: IPublicTypeFieldConfig): ISettingField { this.settingFieldCollector?.(getSettingFieldCollectorKey(this.parent, config), this); return new SettingField(this, config, this.settingFieldCollector); } @@ -161,8 +183,8 @@ export class SettingField extends SettingPropEntry implements ISettingField { } getItems( - filter?: (item: SettingField | IPublicTypeCustomView) => boolean, - ): Array<SettingField | IPublicTypeCustomView> { + filter?: (item: ISettingField | IPublicTypeCustomView) => boolean, + ): Array<ISettingField | IPublicTypeCustomView> { return this._items.filter((item) => { if (filter) { return filter(item); @@ -252,6 +274,6 @@ export class SettingField extends SettingPropEntry implements ISettingField { /** * @deprecated use same function from '@alilc/lowcode-utils' instead */ -export function isSettingField(obj: any): obj is SettingField { +export function isSettingField(obj: any): obj is ISettingField { return obj && obj.isSettingField; } diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts index ed20964bad..392301b7da 100644 --- a/packages/designer/src/designer/setting/setting-prop-entry.ts +++ b/packages/designer/src/designer/setting/setting-prop-entry.ts @@ -1,11 +1,10 @@ import { obx, computed, makeObservable, runInAction, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; -import { GlobalEvent, IPublicModelEditor, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; +import { GlobalEvent, IPublicApiSetters, IPublicModelEditor, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; import { uniqueId, isJSExpression, isSettingField } from '@alilc/lowcode-utils'; -import { Setters } from '@alilc/lowcode-shell'; import { ISettingEntry } from './setting-entry'; import { INode } from '../../document'; import { IComponentMeta } from '../../component-meta'; -import { Designer } from '../designer'; +import { IDesigner } from '../designer'; import { ISettingField } from './setting-field'; export class SettingPropEntry implements ISettingEntry { @@ -18,13 +17,13 @@ export class SettingPropEntry implements ISettingEntry { readonly isSingle: boolean; - readonly setters: Setters; + readonly setters: IPublicApiSetters; readonly nodes: INode[]; readonly componentMeta: IComponentMeta | null; - readonly designer: Designer; + readonly designer: IDesigner; readonly top: ISettingEntry; @@ -37,7 +36,7 @@ export class SettingPropEntry implements ISettingEntry { readonly emitter: IEventBus = createModuleEventBus('SettingPropEntry'); // ==== dynamic properties ==== - @obx.ref private _name: string | number; + @obx.ref private _name: string | number | undefined; get name() { return this._name; @@ -45,7 +44,7 @@ export class SettingPropEntry implements ISettingEntry { @computed get path() { const path = this.parent.path.slice(); - if (this.type === 'field') { + if (this.type === 'field' && this.name) { path.push(this.name); } return path; @@ -53,7 +52,7 @@ export class SettingPropEntry implements ISettingEntry { extraProps: any = {}; - constructor(readonly parent: ISettingEntry | ISettingField, name: string | number, type?: 'field' | 'group') { + constructor(readonly parent: ISettingEntry | ISettingField, name: string | number | undefined, type?: 'field' | 'group') { makeObservable(this); if (type == null) { const c = typeof name === 'string' ? name.slice(0, 1) : ''; @@ -161,7 +160,7 @@ export class SettingPropEntry implements ISettingEntry { */ getValue(): any { let val: any; - if (this.type === 'field') { + if (this.type === 'field' && this.name) { val = this.parent.getPropValue(this.name); } const { getValue } = this.extraProps; @@ -179,7 +178,7 @@ export class SettingPropEntry implements ISettingEntry { setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: IPublicTypeSetValueOptions) { const oldValue = this.getValue(); if (this.type === 'field') { - this.parent.setPropValue(this.name, val); + this.name && this.parent.setPropValue(this.name, val); } const { setValue } = this.extraProps; @@ -203,7 +202,7 @@ export class SettingPropEntry implements ISettingEntry { */ clearValue() { if (this.type === 'field') { - this.parent.clearPropValue(this.name); + this.name && this.parent.clearPropValue(this.name); } const { setValue } = this.extraProps; if (setValue) { diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 89856d2eb6..e44e21d35a 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -39,7 +39,7 @@ import { IProject, Project } from '../project'; import { ISimulatorHost } from '../simulator'; import { IComponentMeta } from '../component-meta'; import { IDesigner, IHistory } from '../designer'; -import { insertChildren, insertChild, RootNode, INode } from './node/node'; +import { insertChildren, insertChild, IRootNode, INode } from './node/node'; import { Selection, ISelection } from './selection'; import { History } from './history'; import { IModalNodesManager, ModalNodesManager, Node } from './node'; @@ -56,7 +56,7 @@ export type GetDataType<T, NodeType> = T extends undefined export interface IDocumentModel extends Omit< IPublicModelDocumentModel< ISelection, IHistory, - INode | RootNode, + INode | IRootNode, IDropLocation, IModalNodesManager, IProject @@ -89,11 +89,26 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel< get nodesMap(): Map<string, INode>; + /** + * 是否为非激活状态 + */ + get suspensed(): boolean; + + get fileName(): string; + + get currentRoot(): INode | null; + + selection: ISelection; + + isBlank(): boolean; + /** * 根据 id 获取节点 */ getNode(id: string): INode | null; + getRoot(): INode | null; + getHistory(): IHistory; checkNesting( @@ -122,13 +137,21 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel< getComponentMeta(componentName: string): IComponentMeta; insertNodes(parent: INode, thing: INode[] | IPublicTypeNodeData[], at?: number | null, copy?: boolean): INode[]; + + open(): DocumentModel; + + remove(): void; + + suspense(): void; + + close(): void; } export class DocumentModel implements IDocumentModel { /** * 根节点 类型有:Page/Component/Block */ - rootNode: INode | null; + rootNode: IRootNode | null; /** * 文档编号 @@ -280,7 +303,7 @@ export class DocumentModel implements IDocumentModel { return this.rootNode; } - constructor(project: Project, schema?: IPublicTypeRootSchema) { + constructor(project: IProject, schema?: IPublicTypeRootSchema) { makeObservable(this); this.project = project; this.designer = this.project?.designer; @@ -346,7 +369,7 @@ export class DocumentModel implements IDocumentModel { } isBlank() { - return this._blank && !this.isModified(); + return !!(this._blank && !this.isModified()); } /** @@ -552,7 +575,7 @@ export class DocumentModel implements IDocumentModel { /** * 是否已修改 */ - isModified() { + isModified(): boolean { return this.history.isSavePoint(); } @@ -641,7 +664,7 @@ export class DocumentModel implements IDocumentModel { items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data]; } else if (isDragNodeObject<INode>(dragObject)) { items = dragObject.nodes; - } else if (isNode(dragObject) || isNodeSchema(dragObject)) { + } else if (isNode<INode>(dragObject) || isNodeSchema(dragObject)) { items = [dragObject]; } else { console.warn('the dragObject is not in the correct type, dragObject:', dragObject); @@ -760,7 +783,7 @@ export class DocumentModel implements IDocumentModel { /* istanbul ignore next */ acceptRootNodeVisitor( visitorName = 'default', - visitorFn: (node: RootNode) => any, + visitorFn: (node: IRootNode) => any, ) { let visitorResult = {}; if (!visitorName) { @@ -768,8 +791,10 @@ export class DocumentModel implements IDocumentModel { console.warn('Invalid or empty RootNodeVisitor name.'); } try { - visitorResult = visitorFn.call(this, this.rootNode); - this.rootNodeVisitorMap[visitorName] = visitorResult; + if (this.rootNode) { + visitorResult = visitorFn.call(this, this.rootNode); + this.rootNodeVisitorMap[visitorName] = visitorResult; + } } catch (e) { console.error('RootNodeVisitor is not valid.'); console.error(e); @@ -864,7 +889,7 @@ export class DocumentModel implements IDocumentModel { console.warn('onRefresh method is deprecated'); } - onReady(fn: Function) { + onReady(fn: (...args: any[]) => void) { this.designer.editor.eventBus.on('document-open', fn); return () => { this.designer.editor.eventBus.off('document-open', fn); @@ -876,7 +901,7 @@ export class DocumentModel implements IDocumentModel { } } -export function isDocumentModel(obj: any): obj is DocumentModel { +export function isDocumentModel(obj: any): obj is IDocumentModel { return obj && obj.rootNode; } diff --git a/packages/designer/src/document/document-view.tsx b/packages/designer/src/document/document-view.tsx index a9641069a7..c6dbe76a81 100644 --- a/packages/designer/src/document/document-view.tsx +++ b/packages/designer/src/document/document-view.tsx @@ -1,11 +1,11 @@ import { Component } from 'react'; import classNames from 'classnames'; import { observer } from '@alilc/lowcode-editor-core'; -import { DocumentModel } from './document-model'; +import { DocumentModel, IDocumentModel } from './document-model'; import { BuiltinSimulatorHostView } from '../builtin-simulator'; @observer -export class DocumentView extends Component<{ document: DocumentModel }> { +export class DocumentView extends Component<{ document: IDocumentModel }> { render() { const { document } = this.props; const { simulatorProps } = document; @@ -26,7 +26,7 @@ export class DocumentView extends Component<{ document: DocumentModel }> { } } -class DocumentInfoView extends Component<{ document: DocumentModel }> { +class DocumentInfoView extends Component<{ document: IDocumentModel }> { render() { return null; } diff --git a/packages/designer/src/document/history.ts b/packages/designer/src/document/history.ts index 5de6ca78a9..d190a9a9cb 100644 --- a/packages/designer/src/document/history.ts +++ b/packages/designer/src/document/history.ts @@ -1,5 +1,5 @@ import { reaction, untracked, globalContext, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; -import { IPublicTypeNodeSchema, IPublicModelHistory } from '@alilc/lowcode-types'; +import { IPublicTypeNodeSchema, IPublicModelHistory, IPublicTypeDisposable } from '@alilc/lowcode-types'; import { Logger } from '@alilc/lowcode-utils'; const logger = new Logger({ level: 'warn', bizName: 'history' }); @@ -10,7 +10,7 @@ export interface Serialization<K = IPublicTypeNodeSchema, T = string> { } export interface IHistory extends IPublicModelHistory { - + onStateChange(func: () => any): IPublicTypeDisposable; } export class History<T = IPublicTypeNodeSchema> implements IHistory { @@ -189,11 +189,11 @@ export class History<T = IPublicTypeNodeSchema> implements IHistory { * @param func * @returns */ - onChangeState(func: () => any): () => void { + onChangeState(func: () => any): IPublicTypeDisposable { return this.onStateChange(func); } - onStateChange(func: () => any): () => void { + onStateChange(func: () => any): IPublicTypeDisposable { this.emitter.on('statechange', func); return () => { this.emitter.removeListener('statechange', func); @@ -205,7 +205,7 @@ export class History<T = IPublicTypeNodeSchema> implements IHistory { * @param func * @returns */ - onChangeCursor(func: () => any): () => void { + onChangeCursor(func: () => any): IPublicTypeDisposable { return this.onCursor(func); } diff --git a/packages/designer/src/document/node/exclusive-group.ts b/packages/designer/src/document/node/exclusive-group.ts index 8cf9930950..d8c14cedb5 100644 --- a/packages/designer/src/document/node/exclusive-group.ts +++ b/packages/designer/src/document/node/exclusive-group.ts @@ -7,11 +7,17 @@ import { intl } from '../../locale'; export interface IExclusiveGroup extends IPublicModelExclusiveGroup<INode> { readonly name: string; + get index(): number | undefined; + remove(node: INode): void; add(node: INode): void; isVisible(node: INode): boolean; + + get length(): number; + + get visibleNode(): INode; } // modals assoc x-hide value, initial: check is Modal, yes will put it in modals, cross levels diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index 51e921a935..1b6df58660 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -20,6 +20,8 @@ export interface INodeChildren extends Omit<IPublicModelNodeChildren<INode>, get length(): number; + children: INode[]; + unlinkChild(node: INode): void; /** @@ -65,7 +67,7 @@ export interface INodeChildren extends Omit<IPublicModelNodeChildren<INode>, /** overriding methods end */ } export class NodeChildren implements INodeChildren { - @obx.shallow private children: INode[]; + @obx.shallow children: INode[]; private emitter: IEventBus = createModuleEventBus('NodeChildren'); diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 77f5bddd40..691c228447 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -37,9 +37,9 @@ export interface NodeStatus { inPlaceEditing: boolean; } -export interface INode extends Omit<IBaseModelNode< +export interface IBaseNode<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> extends Omit<IBaseModelNode< IDocumentModel, - INode, + IBaseNode, INodeChildren, IComponentMeta, ISettingTopEntry, @@ -77,6 +77,10 @@ export interface INode extends Omit<IBaseModelNode< get isPurging(): boolean; + getId(): string; + + getParent(): INode | null; + /** * 内部方法,请勿使用 * @param useMutator 是否触发联动逻辑 @@ -147,6 +151,8 @@ export interface INode extends Omit<IBaseModelNode< setVisible(flag: boolean): void; getVisible(): boolean; + + getChildren(): INodeChildren | null; } /** @@ -1352,16 +1358,17 @@ export interface LeafNode extends Node { export type IPublicTypePropChangeOptions = Omit<GlobalEvent.Node.Prop.ChangeOptions, 'node'>; -export type SlotNode = Node<IPublicTypeSlotSchema>; -export type PageNode = Node<IPublicTypePageSchema>; -export type ComponentNode = Node<IPublicTypeComponentSchema>; -export type RootNode = PageNode | ComponentNode; +export type ISlotNode = IBaseNode<IPublicTypeSlotSchema>; +export type IPageNode = IBaseNode<IPublicTypePageSchema>; +export type IComponentNode = IBaseNode<IPublicTypeComponentSchema>; +export type IRootNode = IPageNode | IComponentNode; +export type INode = IPageNode | ISlotNode | IComponentNode | IRootNode; -export function isRootNode(node: INode): node is INode { +export function isRootNode(node: INode): node is IRootNode { return node && node.isRootNode; } -export function isLowCodeComponent(node: INode): node is INode { +export function isLowCodeComponent(node: INode): node is IComponentNode { return node.componentMeta?.getMetadata().devMode === 'lowCode'; } @@ -1446,7 +1453,7 @@ export function insertChild( at?: number | null, copy?: boolean, ): INode | null { - let node: INode | null | RootNode | undefined; + let node: INode | null | IRootNode | undefined; let nodeSchema: IPublicTypeNodeSchema; if (isNode<INode>(thing) && (copy || thing.isSlot())) { nodeSchema = thing.export(IPublicEnumTransformStage.Clone); diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index bb6797d456..a679c28c85 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -1,9 +1,9 @@ import { untracked, computed, obx, engineConfig, action, makeObservable, mobx, runInAction } from '@alilc/lowcode-editor-core'; import { IPublicTypeCompositeValue, GlobalEvent, IPublicTypeJSSlot, IPublicTypeSlotSchema, IPublicEnumTransformStage, IPublicModelProp } from '@alilc/lowcode-types'; -import { uniqueId, isPlainObject, hasOwnProperty, compatStage, isJSExpression, isJSSlot } from '@alilc/lowcode-utils'; +import { uniqueId, isPlainObject, hasOwnProperty, compatStage, isJSExpression, isJSSlot, isNodeSchema } from '@alilc/lowcode-utils'; import { valueToSource } from './value-to-source'; import { IProps, IPropParent } from './props'; -import { SlotNode, INode } from '../node'; +import { ISlotNode, INode } from '../node'; // import { TransformStage } from '../transform-stage'; const { set: mobxSet, isObservableArray } = mobx; @@ -30,6 +30,12 @@ export interface IProp extends Omit<IPublicModelProp< unset(): void; get value(): IPublicTypeCompositeValue | UNSET; + + compare(other: IProp | null): number; + + isUnset(): boolean; + + key: string | number | undefined; } export type ValueTypes = 'unset' | 'literal' | 'map' | 'list' | 'expression' | 'slot'; @@ -402,7 +408,7 @@ export class Prop implements IProp, IPropParent { this._type = 'slot'; let slotSchema: IPublicTypeSlotSchema; // 当 data.value 的结构为 { componentName: 'Slot' } 时,复用部分 slotSchema 数据 - if ((isPlainObject(data.value) && data.value?.componentName === 'Slot')) { + if ((isPlainObject(data.value) && isNodeSchema(data.value) && data.value?.componentName === 'Slot')) { const value = data.value as IPublicTypeSlotSchema; slotSchema = { componentName: 'Slot', @@ -427,7 +433,7 @@ export class Prop implements IProp, IPropParent { this._slotNode.import(slotSchema); } else { const { owner } = this.props; - this._slotNode = owner.document.createNode<SlotNode>(slotSchema); + this._slotNode = owner.document.createNode<ISlotNode>(slotSchema); if (this._slotNode) { owner.addSlot(this._slotNode); this._slotNode.internalSetSlotFor(this); diff --git a/packages/designer/src/document/selection.ts b/packages/designer/src/document/selection.ts index 2456de7594..93ec04ffe9 100644 --- a/packages/designer/src/document/selection.ts +++ b/packages/designer/src/document/selection.ts @@ -4,7 +4,7 @@ import { DocumentModel } from './document-model'; import { IPublicModelSelection } from '@alilc/lowcode-types'; export interface ISelection extends Omit<IPublicModelSelection<INode>, 'node'> { - + containsNode(node: INode, excludeRoot: boolean): boolean; } export class Selection implements ISelection { diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 6516d67aa7..55ac584fbc 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -12,7 +12,9 @@ import { import { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils'; import { ISimulatorHost } from '../simulator'; -export interface IProject extends Omit< IPublicApiProject, +export interface IProject extends Omit< IPublicApiProject< + IDocumentModel +>, 'simulatorHost' | 'importSchema' | 'exportSchema' | @@ -49,7 +51,7 @@ export interface IProject extends Omit< IPublicApiProject, load(schema?: IPublicTypeProjectSchema, autoOpen?: boolean | string): void; getSchema( - stage: IPublicEnumTransformStage, + stage?: IPublicEnumTransformStage, ): IPublicTypeProjectSchema; getDocument(id: string): IDocumentModel | null; @@ -134,10 +136,10 @@ export class Project implements IProject { } private getComponentsMap(): IPublicTypeComponentsMap { - return this.documents.reduce(( + return this.documents.reduce<IPublicTypeComponentsMap>(( componentsMap: IPublicTypeComponentsMap, - curDoc: DocumentModel, - ) => { + curDoc: IDocumentModel, + ): IPublicTypeComponentsMap => { const curComponentsMap = curDoc.getComponentsMap(); if (Array.isArray(curComponentsMap)) { curComponentsMap.forEach((item) => { @@ -176,7 +178,7 @@ export class Project implements IProject { componentsMap: this.getComponentsMap(), componentsTree: this.documents .filter((doc) => !doc.isBlank()) - .map((doc) => doc.export(stage)), + .map((doc) => doc.export(stage) || {} as IPublicTypeRootSchema), i18n: this.i18n, }; } @@ -188,7 +190,7 @@ export class Project implements IProject { setSchema(schema?: IPublicTypeProjectSchema) { // FIXME: 这里的行为和 getSchema 并不对等,感觉不太对 const doc = this.documents.find((doc) => doc.active); - doc && doc.import(schema?.componentsTree[0]); + doc && schema?.componentsTree[0] && doc.import(schema?.componentsTree[0]); this.simulator?.rerender(); } @@ -244,7 +246,7 @@ export class Project implements IProject { } } - removeDocument(doc: IPublicModelDocumentModel) { + removeDocument(doc: IDocumentModel) { const index = this.documents.indexOf(doc); if (index < 0) { return; diff --git a/packages/designer/src/simulator.ts b/packages/designer/src/simulator.ts index 32b9233c90..99586fb815 100644 --- a/packages/designer/src/simulator.ts +++ b/packages/designer/src/simulator.ts @@ -1,5 +1,5 @@ import { ComponentType } from 'react'; -import { IPublicTypeComponentMetadata, IPublicTypeNodeSchema, IPublicTypeScrollable, IPublicTypeComponentInstance, IPublicModelSensor, IPublicTypeNodeInstance } from '@alilc/lowcode-types'; +import { IPublicTypeComponentMetadata, IPublicTypeNodeSchema, IPublicTypeScrollable, IPublicTypeComponentInstance, IPublicModelSensor, IPublicTypeNodeInstance, IPublicTypePackage } from '@alilc/lowcode-types'; import { Point, ScrollTarget, ILocateEvent } from './designer'; import { BuiltinSimulatorRenderer } from './builtin-simulator/renderer'; import { INode } from './document'; @@ -78,7 +78,7 @@ export interface DropContainer { /** * 模拟器控制进程协议 */ -export interface ISimulatorHost<P = object> extends IPublicModelSensor { +export interface ISimulatorHost<P = object> extends IPublicModelSensor<INode> { readonly isSimulator: true; /** @@ -177,6 +177,8 @@ export interface ISimulatorHost<P = object> extends IPublicModelSensor { * 销毁 */ purge(): void; + + setupComponents(library: IPublicTypePackage[]): Promise<void>; } export function isSimulatorHost(obj: any): obj is ISimulatorHost { diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index 0b470557b3..89557e5e8a 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -1,16 +1,16 @@ import { Component, MouseEvent, Fragment } from 'react'; import { shallowIntl, observer, obx, engineConfig, runInAction, globalContext } from '@alilc/lowcode-editor-core'; -import { createContent, isJSSlot, isSetterConfig, isSettingField } from '@alilc/lowcode-utils'; -import { Skeleton } from '@alilc/lowcode-editor-skeleton'; +import { createContent, isJSSlot, isSetterConfig } from '@alilc/lowcode-utils'; +import { Skeleton, Stage } from '@alilc/lowcode-editor-skeleton'; import { IPublicTypeCustomView } from '@alilc/lowcode-types'; -import { SettingField, SettingTopEntry, ISettingEntry, ComponentMeta } from '@alilc/lowcode-designer'; +import { SettingField, SettingTopEntry, ISettingEntry, IComponentMeta, ISettingField, isSettingField } from '@alilc/lowcode-designer'; import { createField } from '../field'; import PopupService, { PopupPipe } from '../popup'; import { SkeletonContext } from '../../context'; import { intl } from '../../locale'; import { Setters } from '@alilc/lowcode-shell'; -function isStandardComponent(componentMeta: ComponentMeta | null) { +function isStandardComponent(componentMeta: IComponentMeta | null) { if (!componentMeta) return false; const { prototype } = componentMeta; return prototype == null; @@ -31,8 +31,9 @@ function isInitialValueNotEmpty(initialValue: any) { return (initialValue !== undefined && initialValue !== null); } -type SettingFieldViewProps = { field: SettingField }; +type SettingFieldViewProps = { field: ISettingField }; type SettingFieldViewState = { fromOnChange: boolean; value: any }; + @observer class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldViewState> { static contextType = SkeletonContext; @@ -55,7 +56,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView let stageName; if (display === 'entry') { runInAction(() => { - stageName = `${field.getNode().id}_${field.name.toString()}`; + stageName = `${field.getNode().id}_${field.name?.toString()}`; // 清除原 stage,不然 content 引用的一直是老的 field,导致数据无法得到更新 stages.container.remove(stageName); stages.add({ @@ -252,7 +253,9 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView }, removeProp: () => { - field.parent.clearPropValue(field.name); + if (field.name) { + field.parent.clearPropValue(field.name); + } }, }), extraProps.forceInline ? 'plain' : extraProps.display, @@ -280,7 +283,7 @@ class SettingGroupView extends Component<SettingGroupViewProps> { let stageName; if (display === 'entry') { runInAction(() => { - stageName = `${field.getNode().id}_${field.name.toString()}`; + stageName = `${field.getNode().id}_${field.name?.toString()}`; // 清除原 stage,不然 content 引用的一直是老的 field,导致数据无法得到更新 stages.container.remove(stageName); stages.add({ @@ -324,7 +327,7 @@ class SettingGroupView extends Component<SettingGroupViewProps> { } } -export function createSettingFieldView(item: SettingField | IPublicTypeCustomView, field: ISettingEntry, index?: number) { +export function createSettingFieldView(item: ISettingField | IPublicTypeCustomView, field: ISettingEntry, index?: number) { if (isSettingField(item)) { if (item.isGroup) { return <SettingGroupView field={item} key={item.id} />; diff --git a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx index c12d966be2..0bbef4bf26 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -1,17 +1,22 @@ import React, { Component } from 'react'; import { Tab, Breadcrumb } from '@alifd/next'; import { Title, observer, Editor, obx, globalContext, engineConfig, makeObservable } from '@alilc/lowcode-editor-core'; -import { Node, SettingField } from '@alilc/lowcode-designer'; +import { Node, SettingField, isSettingField, INode } from '@alilc/lowcode-designer'; import classNames from 'classnames'; import { SettingsMain } from './main'; import { SettingsPane } from './settings-pane'; import { StageBox } from '../stage-box'; import { SkeletonContext } from '../../context'; import { intl } from '../../locale'; -import { createIcon, isSettingField } from '@alilc/lowcode-utils'; +import { createIcon } from '@alilc/lowcode-utils'; + +interface ISettingsPrimaryPaneProps { + engineEditor: Editor; + config: any; +} @observer -export class SettingsPrimaryPane extends Component<{ engineEditor: Editor; config: any }, { shouldIgnoreRoot: boolean }> { +export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, { shouldIgnoreRoot: boolean }> { state = { shouldIgnoreRoot: false, }; @@ -19,7 +24,7 @@ export class SettingsPrimaryPane extends Component<{ engineEditor: Editor; confi @obx.ref private _activeKey?: any; - constructor(props) { + constructor(props: ISettingsPrimaryPaneProps) { super(props); makeObservable(this); } @@ -72,8 +77,8 @@ export class SettingsPrimaryPane extends Component<{ engineEditor: Editor; confi const editor = this.props.engineEditor; const designer = editor.get('designer'); const current = designer?.currentSelection?.getNodes()?.[0]; - let node: Node | null = settings.first; - const { focusNode } = node.document; + let node: INode | null = settings.first; + const focusNode = node.document?.focusNode; const items = []; let l = 3; @@ -83,7 +88,7 @@ export class SettingsPrimaryPane extends Component<{ engineEditor: Editor; confi if (shouldIgnoreRoot && node.isRoot()) { break; } - if (node.contains(focusNode)) { + if (focusNode && node.contains(focusNode)) { l = 0; } const props = diff --git a/packages/editor-skeleton/src/types.ts b/packages/editor-skeleton/src/types.ts index b3e5a04089..a51369f153 100644 --- a/packages/editor-skeleton/src/types.ts +++ b/packages/editor-skeleton/src/types.ts @@ -15,7 +15,7 @@ export interface WidgetConfig extends IPublicTypeWidgetBaseConfig { props?: { align?: 'left' | 'right' | 'bottom' | 'center' | 'top'; onInit?: (widget: IWidget) => void; - title?: IPublicTypeTitleContent; + title?: IPublicTypeTitleContent | null; }; content?: string | ReactElement | ComponentType<any>; // children } diff --git a/packages/types/src/shell/api/project.ts b/packages/types/src/shell/api/project.ts index edafabb48b..ead415e544 100644 --- a/packages/types/src/shell/api/project.ts +++ b/packages/types/src/shell/api/project.ts @@ -3,20 +3,22 @@ import { IPublicEnumTransformStage } from '../enum'; import { IPublicApiSimulatorHost } from './'; import { IPublicModelDocumentModel } from '../model'; -export interface IPublicApiProject { +export interface IPublicApiProject< + DocumentModel = IPublicModelDocumentModel +> { /** * 获取当前的 document * get current document */ - get currentDocument(): IPublicModelDocumentModel | null; + get currentDocument(): DocumentModel | null; /** * 获取当前 project 下所有 documents * get all documents of this project * @returns */ - get documents(): IPublicModelDocumentModel[]; + get documents(): DocumentModel[]; /** * 获取模拟器的 host @@ -30,7 +32,7 @@ export interface IPublicApiProject { * @param doc * @returns */ - openDocument(doc?: string | IPublicTypeRootSchema | undefined): IPublicModelDocumentModel | null; + openDocument(doc?: string | IPublicTypeRootSchema | undefined): DocumentModel | null; /** * 创建一个 document @@ -38,14 +40,14 @@ export interface IPublicApiProject { * @param data * @returns */ - createDocument(data?: IPublicTypeRootSchema): IPublicModelDocumentModel | null; + createDocument(data?: IPublicTypeRootSchema): DocumentModel | null; /** * 删除一个 document * remove a document * @param doc */ - removeDocument(doc: IPublicModelDocumentModel): void; + removeDocument(doc: DocumentModel): void; /** * 根据 fileName 获取 document @@ -53,7 +55,7 @@ export interface IPublicApiProject { * @param fileName * @returns */ - getDocumentByFileName(fileName: string): IPublicModelDocumentModel | null; + getDocumentByFileName(fileName: string): DocumentModel | null; /** * 根据 id 获取 document @@ -61,7 +63,7 @@ export interface IPublicApiProject { * @param id * @returns */ - getDocumentById(id: string): IPublicModelDocumentModel | null; + getDocumentById(id: string): DocumentModel | null; /** * 导出 project @@ -82,7 +84,7 @@ export interface IPublicApiProject { * get current document * @returns */ - getCurrentDocument(): IPublicModelDocumentModel | null; + getCurrentDocument(): DocumentModel | null; /** * 增加一个属性的管道处理函数 @@ -107,7 +109,7 @@ export interface IPublicApiProject { * 当前 project 内的 document 变更事件 * set callback for event onDocumentChanged */ - onChangeDocument(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable; + onChangeDocument(fn: (doc: DocumentModel) => void): IPublicTypeDisposable; /** * 当前 project 的模拟器 ready 事件 diff --git a/packages/types/src/shell/model/dragon.ts b/packages/types/src/shell/model/dragon.ts index 602284e633..67ddb82c74 100644 --- a/packages/types/src/shell/model/dragon.ts +++ b/packages/types/src/shell/model/dragon.ts @@ -2,7 +2,9 @@ import { IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type'; import { IPublicModelDragObject, IPublicModelLocateEvent, IPublicModelNode } from './'; -export interface IPublicModelDragon { +export interface IPublicModelDragon< + Node = IPublicModelNode +> { /** * 是否正在拖动 @@ -51,7 +53,7 @@ export interface IPublicModelDragon { * @param dragObject 拖拽对象 * @param boostEvent 拖拽初始时事件 */ - boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode): void; + boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node): void; /** * 添加投放感应区 diff --git a/packages/types/src/shell/model/index.ts b/packages/types/src/shell/model/index.ts index 23b6a6431c..097e18065a 100644 --- a/packages/types/src/shell/model/index.ts +++ b/packages/types/src/shell/model/index.ts @@ -29,3 +29,5 @@ export * from './plugin-instance'; export * from './sensor'; export * from './resource'; export * from './clipboard'; +export * from './setting-entry'; +export * from './setting-field'; diff --git a/packages/types/src/shell/model/node.ts b/packages/types/src/shell/model/node.ts index ba924d6d59..1cbf63e13f 100644 --- a/packages/types/src/shell/model/node.ts +++ b/packages/types/src/shell/model/node.ts @@ -297,8 +297,9 @@ export interface IBaseModelNode< * 获取指定 path 的属性模型实例 * get prop by path * @param path 属性路径,支持 a / a.b / a.0 等格式 + * @param createIfNone 如果不存在,是否新建,默认为 true */ - getProp(path: string, createIfNone: boolean): Prop | null; + getProp(path: string, createIfNone?: boolean): Prop | null; /** * 获取指定 path 的属性模型实例值 diff --git a/packages/types/src/shell/model/sensor.ts b/packages/types/src/shell/model/sensor.ts index 405cd7866f..b563cddb14 100644 --- a/packages/types/src/shell/model/sensor.ts +++ b/packages/types/src/shell/model/sensor.ts @@ -3,12 +3,15 @@ import { IPublicModelLocateEvent, IPublicModelDropLocation, IPublicTypeComponentInstance, + IPublicModelNode, } from '..'; /** * 拖拽敏感板 */ -export interface IPublicModelSensor { +export interface IPublicModelSensor< + Node = IPublicModelNode +> { /** * 是否可响应,比如面板被隐藏,可设置该值 false @@ -38,5 +41,5 @@ export interface IPublicModelSensor { /** * 获取节点实例 */ - getNodeInstanceFromElement?: (e: Element | null) => IPublicTypeNodeInstance<IPublicTypeComponentInstance> | null; + getNodeInstanceFromElement?: (e: Element | null) => IPublicTypeNodeInstance<IPublicTypeComponentInstance, Node> | null; } diff --git a/packages/types/src/shell/model/setting-entry.ts b/packages/types/src/shell/model/setting-entry.ts new file mode 100644 index 0000000000..ec5b423189 --- /dev/null +++ b/packages/types/src/shell/model/setting-entry.ts @@ -0,0 +1,20 @@ +import { IPublicModelComponentMeta } from "./component-meta"; +import { IPublicModelNode } from "./node"; +import { IBaseModelSettingTarget } from "./setting-target"; + +export interface IBaseModelSettingEntry< + Node, + ComponentMeta, + SettingEntry +> extends IBaseModelSettingTarget< + SettingEntry +> { + readonly nodes: Node[]; + readonly componentMeta: ComponentMeta | null; +} + +export interface IPublicModelSettingEntry extends IBaseModelSettingEntry< + IPublicModelNode, + IPublicModelComponentMeta, + IPublicModelSettingEntry +> {} \ No newline at end of file diff --git a/packages/types/src/shell/model/setting-field.ts b/packages/types/src/shell/model/setting-field.ts new file mode 100644 index 0000000000..5efa4c6467 --- /dev/null +++ b/packages/types/src/shell/model/setting-field.ts @@ -0,0 +1,5 @@ +import { IPublicModelSettingEntry } from "./setting-entry"; + +export interface IPublicModelSettingField extends IPublicModelSettingEntry { + +} \ No newline at end of file diff --git a/packages/types/src/shell/model/setting-target.ts b/packages/types/src/shell/model/setting-target.ts index e41cf6ea6d..78bd924e15 100644 --- a/packages/types/src/shell/model/setting-target.ts +++ b/packages/types/src/shell/model/setting-target.ts @@ -1,7 +1,9 @@ import { IPublicApiSetters } from '../api'; import { IPublicModelEditor } from './'; -export interface IPublicModelSettingTarget { +export interface IBaseModelSettingTarget< + SettingTarget +> { /** * 同样类型的节点 @@ -33,12 +35,12 @@ export interface IPublicModelSettingTarget { /** * 顶端 */ - readonly top: IPublicModelSettingTarget; + readonly top: SettingTarget; /** * 父级 */ - readonly parent: IPublicModelSettingTarget; + readonly parent: SettingTarget; /** * 获取当前值 @@ -53,12 +55,12 @@ export interface IPublicModelSettingTarget { /** * 取得子项 */ - get: (propName: string | number) => IPublicModelSettingTarget | null; + get: (propName: string | number) => SettingTarget | null; /** * 取得子项 */ - getProps?: () => IPublicModelSettingTarget; + getProps?: () => SettingTarget; /** * 获取子项属性值 @@ -91,3 +93,9 @@ export interface IPublicModelSettingTarget { */ getNode: () => any; } + +export interface IPublicModelSettingTarget extends IBaseModelSettingTarget< + IPublicModelSettingTarget +> { + +} diff --git a/packages/types/src/shell/type/dynamic-setter.ts b/packages/types/src/shell/type/dynamic-setter.ts index c10d41c471..5883bb2bb9 100644 --- a/packages/types/src/shell/type/dynamic-setter.ts +++ b/packages/types/src/shell/type/dynamic-setter.ts @@ -1,5 +1,4 @@ -import { IPublicModelSettingTarget } from '../model/setting-target'; -import { IPublicTypeCustomView } from '..'; +import { IPublicModelSettingPropEntry, IPublicTypeCustomView } from '..'; import { IPublicTypeSetterConfig } from './setter-config'; -export type IPublicTypeDynamicSetter = (target: IPublicModelSettingTarget) => string | IPublicTypeSetterConfig | IPublicTypeCustomView; +export type IPublicTypeDynamicSetter = (target: IPublicModelSettingPropEntry) => (string | IPublicTypeSetterConfig | IPublicTypeCustomView); diff --git a/packages/types/src/shell/type/location.ts b/packages/types/src/shell/type/location.ts index ac04687e01..c9e2df67fd 100644 --- a/packages/types/src/shell/type/location.ts +++ b/packages/types/src/shell/type/location.ts @@ -46,8 +46,10 @@ export interface IPublicTypeLocationPropDetail { // eslint-disable-next-line max-len export type IPublicTypeLocationDetail = IPublicTypeLocationChildrenDetail | IPublicTypeLocationPropDetail | { type: string; [key: string]: any }; -export interface IPublicTypeLocationData { - target: IPublicModelNode; // shadowNode | ConditionFlow | ElementNode | RootNode +export interface IPublicTypeLocationData< + Node = IPublicModelNode +> { + target: Node; // shadowNode | ConditionFlow | ElementNode | RootNode detail: IPublicTypeLocationDetail; source: string; event: IPublicModelLocateEvent; diff --git a/packages/types/src/shell/type/metadata.ts b/packages/types/src/shell/type/metadata.ts index 39022d48fe..5659916b84 100644 --- a/packages/types/src/shell/type/metadata.ts +++ b/packages/types/src/shell/type/metadata.ts @@ -184,9 +184,9 @@ export interface ConfigureSupport { */ export interface IPublicTypeCallbacks { // hooks - onMouseDownHook?: (e: MouseEvent, currentNode: IPublicModelNode) => any; - onDblClickHook?: (e: MouseEvent, currentNode: IPublicModelNode) => any; - onClickHook?: (e: MouseEvent, currentNode: IPublicModelNode) => any; + onMouseDownHook?: (e: MouseEvent, currentNode: IPublicModelNode | null) => any; + onDblClickHook?: (e: MouseEvent, currentNode: IPublicModelNode | null) => any; + onClickHook?: (e: MouseEvent, currentNode: IPublicModelNode | null) => any; // onLocateHook?: (e: any, currentNode: any) => any; // onAcceptHook?: (currentNode: any, locationData: any) => any; onMoveHook?: (currentNode: IPublicModelNode) => boolean; diff --git a/packages/types/src/shell/type/node-instance.ts b/packages/types/src/shell/type/node-instance.ts index e1d9789c8e..fab8e672ba 100644 --- a/packages/types/src/shell/type/node-instance.ts +++ b/packages/types/src/shell/type/node-instance.ts @@ -1,8 +1,11 @@ import { IPublicTypeComponentInstance, IPublicModelNode } from '..'; -export interface IPublicTypeNodeInstance<T = IPublicTypeComponentInstance> { +export interface IPublicTypeNodeInstance< + T = IPublicTypeComponentInstance, + Node = IPublicModelNode +> { docId: string; nodeId: string; instance: T; - node?: IPublicModelNode | null; + node?: Node | null; } diff --git a/packages/types/src/shell/type/title-content.ts b/packages/types/src/shell/type/title-content.ts index b345ce854c..b17a476a5c 100644 --- a/packages/types/src/shell/type/title-content.ts +++ b/packages/types/src/shell/type/title-content.ts @@ -1,5 +1,5 @@ -import { ReactElement } from 'react'; +import { ReactElement, ReactNode } from 'react'; import { IPublicTypeI18nData, IPublicTypeTitleConfig } from './'; // eslint-disable-next-line max-len -export type IPublicTypeTitleContent = string | IPublicTypeI18nData | ReactElement | IPublicTypeTitleConfig; \ No newline at end of file +export type IPublicTypeTitleContent = string | IPublicTypeI18nData | ReactElement | ReactNode | IPublicTypeTitleConfig; \ No newline at end of file diff --git a/packages/utils/src/check-types/is-i18n-data.ts b/packages/utils/src/check-types/is-i18n-data.ts index d54ce8d918..f4a7b6f7aa 100644 --- a/packages/utils/src/check-types/is-i18n-data.ts +++ b/packages/utils/src/check-types/is-i18n-data.ts @@ -1,6 +1,8 @@ // type checks -export function isI18nData(obj: any): boolean { +import { IPublicTypeI18nData } from "@alilc/lowcode-types"; + +export function isI18nData(obj: any): obj is IPublicTypeI18nData { return obj && obj.type === 'i18n'; } diff --git a/packages/utils/src/check-types/is-location-children-detail.ts b/packages/utils/src/check-types/is-location-children-detail.ts index d20ccc38c3..c6d2819d30 100644 --- a/packages/utils/src/check-types/is-location-children-detail.ts +++ b/packages/utils/src/check-types/is-location-children-detail.ts @@ -1,5 +1,5 @@ -import { IPublicTypeLocationDetailType } from '@alilc/lowcode-types'; +import { IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType } from '@alilc/lowcode-types'; -export function isLocationChildrenDetail(obj: any): boolean { +export function isLocationChildrenDetail(obj: any): obj is IPublicTypeLocationChildrenDetail { return obj && obj.type === IPublicTypeLocationDetailType.Children; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-procode-component-type.ts b/packages/utils/src/check-types/is-procode-component-type.ts index 5e58ed1758..5c768dd943 100644 --- a/packages/utils/src/check-types/is-procode-component-type.ts +++ b/packages/utils/src/check-types/is-procode-component-type.ts @@ -1,6 +1,6 @@ -import { IPublicTypeComponentMap } from '@alilc/lowcode-types'; +import { IPublicTypeComponentMap, IPublicTypeProCodeComponent } from '@alilc/lowcode-types'; -export function isProCodeComponentType(desc: IPublicTypeComponentMap): boolean { +export function isProCodeComponentType(desc: IPublicTypeComponentMap): desc is IPublicTypeProCodeComponent { return 'package' in desc; } diff --git a/packages/utils/src/check-types/is-setting-field.ts b/packages/utils/src/check-types/is-setting-field.ts index 3db1d887f7..67a183a959 100644 --- a/packages/utils/src/check-types/is-setting-field.ts +++ b/packages/utils/src/check-types/is-setting-field.ts @@ -1,3 +1,5 @@ -export function isSettingField(obj: any): boolean { +import { IPublicModelSettingField } from "@alilc/lowcode-types"; + +export function isSettingField(obj: any): obj is IPublicModelSettingField { return obj && obj.isSettingField; } diff --git a/packages/utils/src/check-types/is-title-config.ts b/packages/utils/src/check-types/is-title-config.ts index 23ec49833e..460da99790 100644 --- a/packages/utils/src/check-types/is-title-config.ts +++ b/packages/utils/src/check-types/is-title-config.ts @@ -1,7 +1,7 @@ +import { IPublicTypeTitleConfig } from '@alilc/lowcode-types'; import { isI18nData } from './is-i18n-data'; import { isPlainObject } from '../is-plain-object'; - -export function isTitleConfig(obj: any): boolean { +export function isTitleConfig(obj: any): obj is IPublicTypeTitleConfig { return isPlainObject(obj) && !isI18nData(obj); } diff --git a/packages/utils/src/node-helper.ts b/packages/utils/src/node-helper.ts index 66a514364e..55d42be4e6 100644 --- a/packages/utils/src/node-helper.ts +++ b/packages/utils/src/node-helper.ts @@ -1,10 +1,10 @@ // 仅使用类型 import { IPublicModelNode } from '@alilc/lowcode-types'; -export const getClosestNode = ( - node: IPublicModelNode, - until: (n: IPublicModelNode) => boolean, - ): IPublicModelNode | undefined => { +export const getClosestNode = <Node extends IPublicModelNode = IPublicModelNode>( + node: Node, + until: (n: Node) => boolean, + ): Node | undefined => { if (!node) { return undefined; } @@ -22,7 +22,7 @@ export const getClosestNode = ( * @param {unknown} e 点击事件 * @returns {boolean} 是否可点击,true表示可点击 */ -export const canClickNode = (node: IPublicModelNode, e: unknown): boolean => { +export function canClickNode<Node extends IPublicModelNode = IPublicModelNode>(node: Node, e: unknown): boolean { const onClickHook = node.componentMeta?.advanced?.callbacks?.onClickHook; const canClick = typeof onClickHook === 'function' ? onClickHook(e as MouseEvent, node) : true; return canClick; From 4d4a8a6d6f94bfcfe9af0409a3a54b22a89f2d26 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 14 Mar 2023 18:56:46 +0800 Subject: [PATCH 046/469] feat: fix designer:entry ts errors --- docs/docs/specs/material-spec.md | 10 +- packages/designer/src/component-meta.ts | 11 +- packages/designer/src/designer/designer.ts | 2 +- .../designer/src/designer/setting/index.ts | 3 +- .../designer/setting/setting-entry-type.ts | 45 ++++ .../src/designer/setting/setting-entry.ts | 26 --- .../src/designer/setting/setting-field.ts | 50 ++++- .../designer/setting/setting-prop-entry.ts | 61 ++++-- .../src/designer/setting/setting-top-entry.ts | 52 +++-- packages/designer/src/document/node/node.ts | 24 ++- .../designer/setting/setting-field.test.ts | 2 +- .../src/components/field/index.ts | 2 +- .../src/components/settings/settings-pane.tsx | 18 +- .../src/transducers/addon-combine.ts | 6 +- .../engine/src/modules/shell-model-factory.ts | 11 +- packages/engine/src/modules/symbols.ts | 4 +- packages/shell/src/index.ts | 5 +- packages/shell/src/model/index.ts | 2 +- packages/shell/src/model/props.ts | 2 +- ...setting-prop-entry.ts => setting-field.ts} | 107 +++++----- packages/shell/src/model/setting-top-entry.ts | 20 +- packages/shell/src/symbols.ts | 2 +- packages/types/src/shell-model-factory.ts | 5 +- packages/types/src/shell/model/index.ts | 1 - packages/types/src/shell/model/props.ts | 4 +- .../types/src/shell/model/setting-entry.ts | 20 -- .../types/src/shell/model/setting-field.ts | 197 +++++++++++++++++- .../src/shell/model/setting-prop-entry.ts | 188 +---------------- .../types/src/shell/model/setting-target.ts | 105 +--------- .../src/shell/model/setting-top-entry.ts | 17 +- packages/types/src/shell/type/advanced.ts | 4 +- .../types/src/shell/type/dynamic-props.ts | 4 +- .../types/src/shell/type/field-extra-props.ts | 12 +- packages/types/src/shell/type/metadata.ts | 6 +- .../types/src/shell/type/setter-config.ts | 7 +- 35 files changed, 533 insertions(+), 502 deletions(-) create mode 100644 packages/designer/src/designer/setting/setting-entry-type.ts delete mode 100644 packages/designer/src/designer/setting/setting-entry.ts rename packages/shell/src/model/{setting-prop-entry.ts => setting-field.ts} (56%) delete mode 100644 packages/types/src/shell/model/setting-entry.ts diff --git a/docs/docs/specs/material-spec.md b/docs/docs/specs/material-spec.md index 3bee847c09..8b79284304 100644 --- a/docs/docs/specs/material-spec.md +++ b/docs/docs/specs/material-spec.md @@ -833,11 +833,11 @@ props 数组下对象字段描述: | name | 属性名 | String | type = 'field' 生效 | | defaultValue | 默认值 | Any(视字段类型而定) | type = 'field' 生效 | | supportVariable | 是否支持配置变量 | Boolean | type = 'field' 生效 | -| condition | 配置当前 prop 是否展示 | (target: SettingTarget) => boolean; | - | +| condition | 配置当前 prop 是否展示 | (target: IPublicModelSettingField) => boolean; | - | | setter | 单个控件 (setter) 描述,搭建基础协议组件的描述对象,支持 JSExpression / JSFunction / JSSlot | `String\|Object\|Function` | type = 'field' 生效 | | extraProps | 其他配置属性(不做流通要求) | Object | 其他配置 | -| extraProps.getValue | setter 渲染时被调用,setter 会根据该函数的返回值设置 setter 当前值 | Function | (target: SettingTarget, value: any) => any; | -| extraProps.setValue | setter 内容修改时调用,开发者可在该函数内部修改节点 schema 或者进行其他操作 | Function | (target: SettingTarget, value: any) => void; | +| extraProps.getValue | setter 渲染时被调用,setter 会根据该函数的返回值设置 setter 当前值 | Function | (target: IPublicModelSettingField, value: any) => any; | +| extraProps.setValue | setter 内容修改时调用,开发者可在该函数内部修改节点 schema 或者进行其他操作 | Function | (target: IPublicModelSettingField, value: any) => void; | 根据属性值类型 propType,确定对应控件类型 (setter) 。 @@ -922,7 +922,7 @@ props 数组下对象字段描述: | 字段 | 用途 | 类型 | 备注 | | ------------------------------- | --------------------------------------------------------------------------------------------------- | ------- | --- | -|initialChildren | 组件拖入“设计器”时根据此配置自动生成 children 节点 schema |NodeData[]/Function NodeData[] | ((target: SettingTarget) => NodeData[]);| +|initialChildren | 组件拖入“设计器”时根据此配置自动生成 children 节点 schema |NodeData[]/Function NodeData[] | ((target: IPublicModelSettingField) => NodeData[]);| |getResizingHandlers| 用于配置设计器中组件 resize 操作工具的样式和内容 | Function| (currentNode: any) => Array<{ type: 'N' | 'W' | 'S' | 'E' | 'NW' | 'NE' | 'SE' | 'SW'; content?: ReactElement; propTarget?: string; appearOn?: 'mouse-enter' | 'mouse-hover' | 'selected' | 'always'; }> / ReactElement[]; |callbacks| 配置 callbacks 可捕获引擎抛出的一些事件,例如 onNodeAdd、onResize 等 | Callback| - |callbacks.onNodeAdd| 在容器中拖入组件时触发的事件回调 | Function| (e: MouseEvent, currentNode: any) => any @@ -1098,7 +1098,7 @@ export interface Advanced { /** * 拖入容器时,自动带入 children 列表 */ - initialChildren?: NodeData[] | ((target: SettingTarget) => NodeData[]); + initialChildren?: NodeData[] | ((target: IPublicModelSettingField) => NodeData[]); /** * @todo 待补充文档 */ diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 80f99c05bc..4b0a613cb4 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -8,10 +8,11 @@ import { IPublicTypeTransformedComponentMetadata, IPublicTypeNestingFilter, IPublicTypeI18nData, - IPublicTypePluginConfig, IPublicTypeFieldConfig, IPublicModelComponentMeta, IPublicTypeAdvanced, + IPublicTypeDisposable, + IPublicTypeLiveTextEditingConfig, } from '@alilc/lowcode-types'; import { deprecate, isRegExp, isTitleConfig, isNode } from '@alilc/lowcode-utils'; import { computed, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core'; @@ -59,9 +60,11 @@ export function buildFilter(rule?: string | string[] | RegExp | IPublicTypeNesti export interface IComponentMeta extends IPublicModelComponentMeta<INode> { prototype?: any; + get rootSelector(): string | undefined; + setMetadata(metadata: IPublicTypeComponentMetadata): void; - get rootSelector(): string | undefined; + onMetadataChange(fn: (args: any) => void): IPublicTypeDisposable; } export class ComponentMeta implements IComponentMeta { @@ -120,7 +123,7 @@ export class ComponentMeta implements IComponentMeta { return config?.combined || config?.props || []; } - private _liveTextEditing?: IPublicTypePluginConfig[]; + private _liveTextEditing?: IPublicTypeLiveTextEditingConfig[]; get liveTextEditing() { return this._liveTextEditing; @@ -357,7 +360,7 @@ export class ComponentMeta implements IComponentMeta { return true; } - onMetadataChange(fn: (args: any) => void): () => void { + onMetadataChange(fn: (args: any) => void): IPublicTypeDisposable { this.emitter.on('metadata_change', fn); return () => { this.emitter.removeListener('metadata_change', fn); diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index c26d9fb4b3..a1d05a8dd7 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -140,7 +140,7 @@ export class Designer implements IDesigner { @obx.ref private _simulatorComponent?: ComponentType<any>; - @obx.ref private _simulatorProps?: object | ((project: Project) => object); + @obx.ref private _simulatorProps?: Record<string, any> | ((project: Project) => object); @obx.ref private _suspensed = false; diff --git a/packages/designer/src/designer/setting/index.ts b/packages/designer/src/designer/setting/index.ts index a8319e5b27..6cfa914e62 100644 --- a/packages/designer/src/designer/setting/index.ts +++ b/packages/designer/src/designer/setting/index.ts @@ -1,3 +1,4 @@ export * from './setting-field'; export * from './setting-top-entry'; -export * from './setting-entry'; +export * from './setting-entry-type'; +export * from './setting-prop-entry'; diff --git a/packages/designer/src/designer/setting/setting-entry-type.ts b/packages/designer/src/designer/setting/setting-entry-type.ts new file mode 100644 index 0000000000..1aee9016e5 --- /dev/null +++ b/packages/designer/src/designer/setting/setting-entry-type.ts @@ -0,0 +1,45 @@ +import { IPublicApiSetters, IPublicModelEditor } from '@alilc/lowcode-types'; +import { IDesigner } from '../designer'; +import { INode } from '../../document'; +import { ISettingField } from './setting-field'; + +export interface ISettingEntry { + readonly designer: IDesigner | undefined; + + readonly id: string; + + /** + * 同样类型的节点 + */ + readonly isSameComponent: boolean; + + /** + * 一个 + */ + readonly isSingle: boolean; + + /** + * 多个 + */ + readonly isMultiple: boolean; + + /** + * 编辑器引用 + */ + readonly editor: IPublicModelEditor; + + readonly setters: IPublicApiSetters; + + /** + * 取得子项 + */ + get: (propName: string | number) => ISettingField | null; + + readonly nodes: INode[]; + + // @todo 补充 node 定义 + /** + * 获取 node 中的第一项 + */ + getNode: () => any; +} diff --git a/packages/designer/src/designer/setting/setting-entry.ts b/packages/designer/src/designer/setting/setting-entry.ts deleted file mode 100644 index 9b0d4846a3..0000000000 --- a/packages/designer/src/designer/setting/setting-entry.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { IBaseModelSettingEntry, IPublicModelSettingPropEntry, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; -import { IComponentMeta } from '../../component-meta'; -import { IDesigner } from '../designer'; -import { INode } from '../../document'; - -export interface ISettingEntry extends IBaseModelSettingEntry< - INode, - IComponentMeta, - ISettingEntry -> { - readonly designer: IDesigner; - - readonly isGroup: boolean; - - readonly id: string; - - get name(): string | number | undefined; - - internalToShellPropEntry(): IPublicModelSettingPropEntry; - - valueChange(options: IPublicTypeSetValueOptions): void; - - get valueState(): number; - - clearValue(): void; -} diff --git a/packages/designer/src/designer/setting/setting-field.ts b/packages/designer/src/designer/setting/setting-field.ts index da374f9bb6..36a30eb1cb 100644 --- a/packages/designer/src/designer/setting/setting-field.ts +++ b/packages/designer/src/designer/setting/setting-field.ts @@ -7,14 +7,18 @@ import { IPublicTypeFieldConfig, IPublicTypeCustomView, IPublicTypeSetValueOptions, + IPublicTypeDisposable, + IPublicModelSettingField, + IBaseModelSettingField, } from '@alilc/lowcode-types'; import { Transducer } from './utils'; -import { SettingPropEntry } from './setting-prop-entry'; -import { ISettingEntry } from './setting-entry'; +import { ISettingPropEntry, SettingPropEntry } from './setting-prop-entry'; import { computed, obx, makeObservable, action, untracked, intl } from '@alilc/lowcode-editor-core'; import { cloneDeep, isCustomView, isDynamicSetter } from '@alilc/lowcode-utils'; +import { ISettingTopEntry } from './setting-top-entry'; +import { IComponentMeta, INode } from '@alilc/lowcode-designer'; -function getSettingFieldCollectorKey(parent: ISettingEntry, config: IPublicTypeFieldConfig) { +function getSettingFieldCollectorKey(parent: ISettingTopEntry | ISettingField, config: IPublicTypeFieldConfig) { let cur = parent; const path = [config.name]; while (cur !== parent.top) { @@ -26,11 +30,18 @@ function getSettingFieldCollectorKey(parent: ISettingEntry, config: IPublicTypeF return path.join('.'); } -export interface ISettingField extends Omit<ISettingEntry, 'setValue'> { +export interface ISettingField extends ISettingPropEntry, Omit<IBaseModelSettingField< +ISettingTopEntry, +ISettingField, +IComponentMeta, +INode +>, 'setValue' | 'key' | 'node'> { get items(): Array<ISettingField | IPublicTypeCustomView>; get title(): string | ReactNode | undefined; + readonly isSettingField: true; + purge(): void; extraProps: IPublicTypeFieldExtraProps; @@ -41,6 +52,10 @@ export interface ISettingField extends Omit<ISettingEntry, 'setValue'> { readonly isRequired: boolean; + readonly isGroup: boolean; + + get valueState(): number; + setExpanded(value: boolean): void; setValue( @@ -49,6 +64,16 @@ export interface ISettingField extends Omit<ISettingEntry, 'setValue'> { force?: boolean, extraOptions?: IPublicTypeSetValueOptions, ): void; + + clearValue(): void; + + valueChange(options: IPublicTypeSetValueOptions): void; + + createField(config: IPublicTypeFieldConfig): ISettingField; + + onEffect(action: () => void): IPublicTypeDisposable; + + internalToShell(): IPublicModelSettingField; } export class SettingField extends SettingPropEntry implements ISettingField { @@ -62,7 +87,7 @@ export class SettingField extends SettingPropEntry implements ISettingField { private hotValue: any; - parent: ISettingEntry; + parent: ISettingTopEntry | ISettingField; extraProps: IPublicTypeFieldExtraProps; @@ -82,7 +107,7 @@ export class SettingField extends SettingPropEntry implements ISettingField { private _items: Array<ISettingField | IPublicTypeCustomView> = []; constructor( - parent: ISettingEntry, + parent: ISettingTopEntry | ISettingField, config: IPublicTypeFieldConfig, private settingFieldCollector?: (name: string | number, field: ISettingField) => void, ) { @@ -118,8 +143,8 @@ export class SettingField extends SettingPropEntry implements ISettingField { } if (isDynamicSetter(this._setter)) { return untracked(() => { - const shellThis = this.internalToShellPropEntry(); - return (this._setter as IPublicTypeDynamicSetter)?.call(shellThis, shellThis); + const shellThis = this.internalToShell(); + return (this._setter as IPublicTypeDynamicSetter)?.call(shellThis, shellThis!); }); } return this._setter; @@ -266,8 +291,13 @@ export class SettingField extends SettingPropEntry implements ISettingField { this.valueChange(options); } - onEffect(action: () => void): () => void { - return this.designer.autorun(action, true); + onEffect(action: () => void): IPublicTypeDisposable { + return this.designer!.autorun(action, true); + } + + + internalToShell() { + return this.designer!.shellModelFactory.createSettingField(this); } } diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts index 392301b7da..e2f1be615c 100644 --- a/packages/designer/src/designer/setting/setting-prop-entry.ts +++ b/packages/designer/src/designer/setting/setting-prop-entry.ts @@ -1,13 +1,44 @@ import { obx, computed, makeObservable, runInAction, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; -import { GlobalEvent, IPublicApiSetters, IPublicModelEditor, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; -import { uniqueId, isJSExpression, isSettingField } from '@alilc/lowcode-utils'; -import { ISettingEntry } from './setting-entry'; +import { GlobalEvent, IPublicApiSetters, IPublicModelEditor, IPublicModelSettingField, IPublicTypeFieldExtraProps, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; +import { uniqueId, isJSExpression } from '@alilc/lowcode-utils'; +import { ISettingEntry } from './setting-entry-type'; import { INode } from '../../document'; import { IComponentMeta } from '../../component-meta'; import { IDesigner } from '../designer'; -import { ISettingField } from './setting-field'; +import { ISettingTopEntry } from './setting-top-entry'; +import { ISettingField, isSettingField } from './setting-field'; -export class SettingPropEntry implements ISettingEntry { +export interface ISettingPropEntry extends ISettingEntry { + get props(): ISettingTopEntry; + + readonly isGroup: boolean; + + get name(): string | number | undefined; + + valueChange(options: IPublicTypeSetValueOptions): void; + + getKey(): string | number | undefined; + + setKey(key: string | number): void; + + getDefaultValue(): any; + + setUseVariable(flag: boolean): void; + + getProps(): ISettingTopEntry; + + isUseVariable(): boolean; + + getMockOrValue(): any; + + remove(): void; + + setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: IPublicTypeSetValueOptions): void; + + internalToShell(): IPublicModelSettingField; +} + +export class SettingPropEntry implements ISettingPropEntry { // === static properties === readonly editor: IPublicModelEditor; @@ -23,9 +54,9 @@ export class SettingPropEntry implements ISettingEntry { readonly componentMeta: IComponentMeta | null; - readonly designer: IDesigner; + readonly designer: IDesigner | undefined; - readonly top: ISettingEntry; + readonly top: ISettingTopEntry; readonly isGroup: boolean; @@ -50,9 +81,9 @@ export class SettingPropEntry implements ISettingEntry { return path; } - extraProps: any = {}; + extraProps: IPublicTypeFieldExtraProps = {}; - constructor(readonly parent: ISettingEntry | ISettingField, name: string | number | undefined, type?: 'field' | 'group') { + constructor(readonly parent: ISettingTopEntry | ISettingField, name: string | number | undefined, type?: 'field' | 'group') { makeObservable(this); if (type == null) { const c = typeof name === 'string' ? name.slice(0, 1) : ''; @@ -126,7 +157,7 @@ export class SettingPropEntry implements ISettingEntry { if (this.type !== 'field') { const { getValue } = this.extraProps; return getValue - ? getValue(this.internalToShellPropEntry(), undefined) === undefined + ? getValue(this.internalToShell()!, undefined) === undefined ? 0 : 1 : 0; @@ -165,7 +196,7 @@ export class SettingPropEntry implements ISettingEntry { } const { getValue } = this.extraProps; try { - return getValue ? getValue(this.internalToShellPropEntry(), val) : val; + return getValue ? getValue(this.internalToShell()!, val) : val; } catch (e) { console.warn(e); return val; @@ -184,7 +215,7 @@ export class SettingPropEntry implements ISettingEntry { const { setValue } = this.extraProps; if (setValue && !extraOptions?.disableMutator) { try { - setValue(this.internalToShellPropEntry(), val); + setValue(this.internalToShell()!, val); } catch (e) { /* istanbul ignore next */ console.warn(e); @@ -207,7 +238,7 @@ export class SettingPropEntry implements ISettingEntry { const { setValue } = this.extraProps; if (setValue) { try { - setValue(this.internalToShellPropEntry(), undefined); + setValue(this.internalToShell()!, undefined); } catch (e) { /* istanbul ignore next */ console.warn(e); @@ -363,7 +394,7 @@ export class SettingPropEntry implements ISettingEntry { return v; } - internalToShellPropEntry() { - return this.designer.shellModelFactory.createSettingPropEntry(this); + internalToShell(): IPublicModelSettingField { + return this.designer!.shellModelFactory.createSettingField(this);; } } diff --git a/packages/designer/src/designer/setting/setting-top-entry.ts b/packages/designer/src/designer/setting/setting-top-entry.ts index 04f00afc31..62efd5f539 100644 --- a/packages/designer/src/designer/setting/setting-top-entry.ts +++ b/packages/designer/src/designer/setting/setting-top-entry.ts @@ -1,11 +1,10 @@ -import { IPublicTypeCustomView, IPublicModelEditor } from '@alilc/lowcode-types'; +import { IPublicTypeCustomView, IPublicModelEditor, IPublicModelSettingTopEntry } from '@alilc/lowcode-types'; import { isCustomView } from '@alilc/lowcode-utils'; import { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; -import { ISettingEntry } from './setting-entry'; -import { SettingField } from './setting-field'; -import { SettingPropEntry } from './setting-prop-entry'; +import { ISettingEntry } from './setting-entry-type'; +import { ISettingField, SettingField } from './setting-field'; import { INode } from '../../document'; -import { ComponentMeta } from '../../component-meta'; +import { IComponentMeta } from '../../component-meta'; import { IDesigner } from '../designer'; import { Setters } from '@alilc/lowcode-shell'; @@ -16,8 +15,25 @@ function generateSessionId(nodes: INode[]) { .join(','); } -export interface ISettingTopEntry extends ISettingEntry { +export interface ISettingTopEntry extends ISettingEntry, IPublicModelSettingTopEntry< + INode, + ISettingField +> { purge(): void; + + items: Array<ISettingField | IPublicTypeCustomView>; + + readonly top: ISettingTopEntry; + + readonly parent: ISettingTopEntry; + + readonly path: never[]; + + componentMeta: IComponentMeta | null; + + getExtraPropValue(propName: string): void; + + setExtraPropValue(propName: string, value: any): void; } export class SettingTopEntry implements ISettingTopEntry { @@ -25,11 +41,11 @@ export class SettingTopEntry implements ISettingTopEntry { private _items: Array<SettingField | IPublicTypeCustomView> = []; - private _componentMeta: ComponentMeta | null = null; + private _componentMeta: IComponentMeta | null = null; private _isSame = true; - private _settingFieldMap: { [prop: string]: SettingField } = {}; + private _settingFieldMap: { [prop: string]: ISettingField } = {}; readonly path = []; @@ -122,8 +138,8 @@ export class SettingTopEntry implements ISettingTopEntry { private setupItems() { if (this.componentMeta) { - const settingFieldMap: { [prop: string]: SettingField } = {}; - const settingFieldCollector = (name: string | number, field: SettingField) => { + const settingFieldMap: { [prop: string]: ISettingField } = {}; + const settingFieldCollector = (name: string | number, field: ISettingField) => { settingFieldMap[name] = field; }; this._items = this.componentMeta.configure.map((item) => { @@ -160,34 +176,34 @@ export class SettingTopEntry implements ISettingTopEntry { /** * 获取子项 */ - get(propName: string | number): SettingPropEntry | null { + get(propName: string | number): ISettingField | null { if (!propName) return null; - return this._settingFieldMap[propName] || (new SettingPropEntry(this, propName)); + return this._settingFieldMap[propName] || (new SettingField(this, { name: propName })); } /** * 设置子级属性值 */ - setPropValue(propName: string, value: any) { + setPropValue(propName: string | number, value: any) { this.nodes.forEach((node) => { - node.setPropValue(propName, value); + node.setPropValue(propName.toString(), value); }); } /** * 清除已设置值 */ - clearPropValue(propName: string) { + clearPropValue(propName: string | number) { this.nodes.forEach((node) => { - node.clearPropValue(propName); + node.clearPropValue(propName.toString()); }); } /** * 获取子级属性值 */ - getPropValue(propName: string): any { - return this.first.getProp(propName, true)?.getValue(); + getPropValue(propName: string | number): any { + return this.first.getProp(propName.toString(), true)?.getValue(); } /** diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 691c228447..d8b371ddf4 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -153,6 +153,12 @@ export interface IBaseNode<Schema extends IPublicTypeNodeSchema = IPublicTypeNod getVisible(): boolean; getChildren(): INodeChildren | null; + + clearPropValue(path: string): void; + + setProps(props?: IPublicTypePropsMap | IPublicTypePropsList | Props | null): void; + + mergeProps(props: IPublicTypePropsMap): void; } /** @@ -203,7 +209,7 @@ export interface IBaseNode<Schema extends IPublicTypeNodeSchema = IPublicTypeNod * isLocked * hidden */ -export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> implements INode { +export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> implements IBaseNode { private emitter: IEventBus; /** @@ -427,18 +433,24 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> }); } - private initialChildren(children: any): IPublicTypeNodeData[] { + private initialChildren(children: IPublicTypeNodeData | IPublicTypeNodeData[] | undefined): IPublicTypeNodeData[] { // FIXME! this is dirty code if (children == null) { const { initialChildren } = this.componentMeta.advanced; if (initialChildren) { if (typeof initialChildren === 'function') { - return initialChildren(this as any) || []; + return initialChildren(this.internalToShellNode()!) || []; } return initialChildren; } } - return children || []; + if (Array.isArray(children)) { + return children; + } else if (children) { + return [children]; + } else { + return []; + } } isContainer(): boolean { @@ -900,12 +912,12 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> (subNode: INode) => { subNode.remove(true, true); }, - (iterable, idx) => (iterable as NodeChildren).get(idx), + (iterable, idx) => (iterable as INodeChildren).get(idx), ); } if (this.isParental()) { this.props.import(props, extras); - (this._children as NodeChildren).import(children, checkId); + this._children?.import(children, checkId); } else { this.props .get('children', true)! diff --git a/packages/designer/tests/designer/setting/setting-field.test.ts b/packages/designer/tests/designer/setting/setting-field.test.ts index c0cdf17b55..2a5ef4c230 100644 --- a/packages/designer/tests/designer/setting/setting-field.test.ts +++ b/packages/designer/tests/designer/setting/setting-field.test.ts @@ -104,7 +104,7 @@ describe('setting-field 测试', () => { // group 类型的 field const groupField = settingEntry.get('groupkgzzeo41') as SettingField; - expect(groupField.items).toBeUndefined(); + expect(groupField.items).toEqual([]); // 有子节点的 field const objField = settingEntry.get('obj') as SettingField; diff --git a/packages/editor-skeleton/src/components/field/index.ts b/packages/editor-skeleton/src/components/field/index.ts index 1212d3095f..defe151cf7 100644 --- a/packages/editor-skeleton/src/components/field/index.ts +++ b/packages/editor-skeleton/src/components/field/index.ts @@ -14,7 +14,7 @@ export interface FieldProps { [extra: string]: any; } -export function createField(props: FieldProps, children: ReactNode, type?: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry') { +export function createField(props: FieldProps, children: ReactNode, type?: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry'): ReactNode { if (type === 'popup') { return createElement(PopupField, props, children); } diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index 89557e5e8a..6e256be5cc 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -3,7 +3,7 @@ import { shallowIntl, observer, obx, engineConfig, runInAction, globalContext } import { createContent, isJSSlot, isSetterConfig } from '@alilc/lowcode-utils'; import { Skeleton, Stage } from '@alilc/lowcode-editor-skeleton'; import { IPublicTypeCustomView } from '@alilc/lowcode-types'; -import { SettingField, SettingTopEntry, ISettingEntry, IComponentMeta, ISettingField, isSettingField } from '@alilc/lowcode-designer'; +import { ISettingEntry, IComponentMeta, ISettingField, isSettingField, ISettingTopEntry } from '@alilc/lowcode-designer'; import { createField } from '../field'; import PopupService, { PopupPipe } from '../popup'; import { SkeletonContext } from '../../context'; @@ -80,7 +80,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView const { extraProps } = this.field; const { condition } = extraProps; try { - return typeof condition === 'function' ? condition(this.field.internalToShellPropEntry()) !== false : true; + return typeof condition === 'function' ? condition(this.field.internalToShell()) !== false : true; } catch (error) { console.error('exception when condition (hidden) is excuted', error); } @@ -111,7 +111,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView if (setter.props) { setterProps = setter.props; if (typeof setterProps === 'function') { - setterProps = setterProps(this.field.internalToShellPropEntry()); + setterProps = setterProps(this.field.internalToShell()); } } if (setter.initialValue != null) { @@ -177,7 +177,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView } // 当前 field 没有 value 值时,将 initialValue 写入 field // 之所以用 initialValue,而不是 defaultValue 是为了保持跟 props.onInitial 的逻辑一致 - const _initialValue = typeof initialValue === 'function' ? initialValue(this.field.internalToShellPropEntry()) : initialValue; + const _initialValue = typeof initialValue === 'function' ? initialValue(this.field.internalToShell()) : initialValue; this.field.setValue(_initialValue); } @@ -225,9 +225,9 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView forceInline: extraProps.forceInline, key: field.id, // === injection - prop: field.internalToShellPropEntry(), // for compatible vision + prop: field.internalToShell(), // for compatible vision selected: field.top?.getNode()?.internalToShellNode(), - field: field.internalToShellPropEntry(), + field: field.internalToShell(), // === IO value, // reaction point initialValue, @@ -244,7 +244,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView if (initialValue == null) { return; } - const value = typeof initialValue === 'function' ? initialValue(field.internalToShellPropEntry()) : initialValue; + const value = typeof initialValue === 'function' ? initialValue(field.internalToShell()) : initialValue; this.setState({ // eslint-disable-next-line react/no-unused-state value, @@ -303,7 +303,7 @@ class SettingGroupView extends Component<SettingGroupViewProps> { const { field } = this.props; const { extraProps } = field; const { condition, display } = extraProps; - const visible = field.isSingle && typeof condition === 'function' ? condition(field.internalToShellPropEntry()) !== false : true; + const visible = field.isSingle && typeof condition === 'function' ? condition(field.internalToShell()) !== false : true; if (!visible) { return null; @@ -340,7 +340,7 @@ export function createSettingFieldView(item: ISettingField | IPublicTypeCustomVi } export type SettingsPaneProps = { - target: SettingTopEntry | SettingField; + target: ISettingTopEntry | ISettingField; usePopup?: boolean; }; diff --git a/packages/editor-skeleton/src/transducers/addon-combine.ts b/packages/editor-skeleton/src/transducers/addon-combine.ts index 855dbe5697..c2bc2dd4c5 100644 --- a/packages/editor-skeleton/src/transducers/addon-combine.ts +++ b/packages/editor-skeleton/src/transducers/addon-combine.ts @@ -1,7 +1,7 @@ import { IPublicTypeTransformedComponentMetadata, IPublicTypeFieldConfig, - IPublicModelSettingTarget, + IPublicModelSettingField, } from '@alilc/lowcode-types'; import { IconSlot } from '../icons/slot'; import { getConvertedExtraKey } from '@alilc/lowcode-designer'; @@ -214,11 +214,11 @@ export default function ( definition: eventsDefinition, }, }, - getValue(field: IPublicModelSettingTarget, val?: any[]) { + getValue(field: IPublicModelSettingField, val?: any[]) { return val; }, - setValue(field: IPublicModelSettingTarget, eventData) { + setValue(field: IPublicModelSettingField, eventData) { const { eventDataList, eventList } = eventData; Array.isArray(eventList) && eventList.map((item) => { diff --git a/packages/engine/src/modules/shell-model-factory.ts b/packages/engine/src/modules/shell-model-factory.ts index bd3f795eb6..4271d126a3 100644 --- a/packages/engine/src/modules/shell-model-factory.ts +++ b/packages/engine/src/modules/shell-model-factory.ts @@ -1,18 +1,19 @@ import { INode, - SettingField as InnerSettingField, + ISettingField, } from '@alilc/lowcode-designer'; -import { IShellModelFactory, IPublicModelNode, IPublicModelSettingPropEntry } from '@alilc/lowcode-types'; +import { IShellModelFactory, IPublicModelNode } from '@alilc/lowcode-types'; +import { IPublicModelSettingField } from '../../../types/src/shell/model/setting-field'; import { Node, - SettingPropEntry, + SettingField, } from '@alilc/lowcode-shell'; class ShellModelFactory implements IShellModelFactory { createNode(node: INode | null | undefined): IPublicModelNode | null { return Node.create(node); } - createSettingPropEntry(prop: InnerSettingField): IPublicModelSettingPropEntry { - return SettingPropEntry.create(prop); + createSettingField(prop: ISettingField): IPublicModelSettingField { + return SettingField.create(prop); } } export const shellModelFactory = new ShellModelFactory(); \ No newline at end of file diff --git a/packages/engine/src/modules/symbols.ts b/packages/engine/src/modules/symbols.ts index 8ac1d95a86..7faccff513 100644 --- a/packages/engine/src/modules/symbols.ts +++ b/packages/engine/src/modules/symbols.ts @@ -6,7 +6,7 @@ import { designerSymbol, skeletonSymbol, editorSymbol, - settingPropEntrySymbol, + settingFieldSymbol, settingTopEntrySymbol, designerCabinSymbol, propSymbol, @@ -21,7 +21,7 @@ export default { skeletonSymbol, editorSymbol, designerSymbol, - settingPropEntrySymbol, + settingPropEntrySymbol: settingFieldSymbol, settingTopEntrySymbol, designerCabinSymbol, propSymbol, diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index aed56fb957..30eb32adaf 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -7,10 +7,10 @@ import { Prop, Selection, Dragon, - SettingPropEntry, SettingTopEntry, Clipboard, Config, + SettingField, } from './model'; import { Project, @@ -51,7 +51,7 @@ export { Setters, Hotkey, Skeleton, - SettingPropEntry, + SettingField as SettingPropEntry, SettingTopEntry, Dragon, Common, @@ -63,4 +63,5 @@ export { Clipboard, SimulatorHost, Config, + SettingField, }; diff --git a/packages/shell/src/model/index.ts b/packages/shell/src/model/index.ts index 8e18c36bb6..e747021b79 100644 --- a/packages/shell/src/model/index.ts +++ b/packages/shell/src/model/index.ts @@ -12,8 +12,8 @@ export * from './node'; export * from './prop'; export * from './props'; export * from './selection'; -export * from './setting-prop-entry'; export * from './setting-top-entry'; +export * from './setting-field'; export * from './resource'; export * from './active-tracker'; export * from './plugin-instance'; diff --git a/packages/shell/src/model/props.ts b/packages/shell/src/model/props.ts index 98d0ef1436..86a9a2142b 100644 --- a/packages/shell/src/model/props.ts +++ b/packages/shell/src/model/props.ts @@ -28,7 +28,7 @@ export class Props implements IPublicModelProps { /** * 返回当前 props 的路径 */ - get path(): any[] { + get path(): string[] { return this[propsSymbol].path; } diff --git a/packages/shell/src/model/setting-prop-entry.ts b/packages/shell/src/model/setting-field.ts similarity index 56% rename from packages/shell/src/model/setting-prop-entry.ts rename to packages/shell/src/model/setting-field.ts index 94d39a5226..8cb6341849 100644 --- a/packages/shell/src/model/setting-prop-entry.ts +++ b/packages/shell/src/model/setting-field.ts @@ -1,144 +1,149 @@ -import { SettingField, ISettingEntry } from '@alilc/lowcode-designer'; +import { ISettingField, isSettingField } from '@alilc/lowcode-designer'; import { IPublicTypeCompositeValue, IPublicTypeFieldConfig, IPublicTypeCustomView, - IPublicModelSettingPropEntry, IPublicTypeSetterType, IPublicTypeFieldExtraProps, IPublicModelSettingTopEntry, IPublicModelNode, IPublicModelComponentMeta, IPublicTypeSetValueOptions, + IPublicModelSettingField, + IPublicTypeDisposable, } from '@alilc/lowcode-types'; -import { settingPropEntrySymbol } from '../symbols'; +import { settingFieldSymbol } from '../symbols'; import { Node as ShellNode } from './node'; -import { SettingTopEntry as ShellSettingTopEntry } from './setting-top-entry'; +import { SettingTopEntry, SettingTopEntry as ShellSettingTopEntry } from './setting-top-entry'; import { ComponentMeta as ShellComponentMeta } from './component-meta'; import { isCustomView } from '@alilc/lowcode-utils'; -export class SettingPropEntry implements IPublicModelSettingPropEntry { - private readonly [settingPropEntrySymbol]: SettingField; +export class SettingField implements IPublicModelSettingField { + private readonly [settingFieldSymbol]: ISettingField; - constructor(prop: SettingField) { - this[settingPropEntrySymbol] = prop; + constructor(prop: ISettingField) { + this[settingFieldSymbol] = prop; } - static create(prop: SettingField): IPublicModelSettingPropEntry { - return new SettingPropEntry(prop); + static create(prop: ISettingField): IPublicModelSettingField { + return new SettingField(prop); } /** * 获取设置属性的 isGroup */ get isGroup(): boolean { - return this[settingPropEntrySymbol].isGroup; + return this[settingFieldSymbol].isGroup; } /** * 获取设置属性的 id */ get id(): string { - return this[settingPropEntrySymbol].id; + return this[settingFieldSymbol].id; } /** * 获取设置属性的 name */ - get name(): string | number { - return this[settingPropEntrySymbol].name; + get name(): string | number | undefined { + return this[settingFieldSymbol].name; } /** * 获取设置属性的 key */ - get key(): string | number { - return this[settingPropEntrySymbol].getKey(); + get key(): string | number | undefined { + return this[settingFieldSymbol].getKey(); } /** * 获取设置属性的 path */ get path(): any[] { - return this[settingPropEntrySymbol].path; + return this[settingFieldSymbol].path; } /** * 获取设置属性的 title */ get title(): any { - return this[settingPropEntrySymbol].title; + return this[settingFieldSymbol].title; } /** * 获取设置属性的 setter */ get setter(): IPublicTypeSetterType | null { - return this[settingPropEntrySymbol].setter; + return this[settingFieldSymbol].setter; } /** * 获取设置属性的 expanded */ get expanded(): boolean { - return this[settingPropEntrySymbol].expanded; + return this[settingFieldSymbol].expanded; } /** * 获取设置属性的 extraProps */ get extraProps(): IPublicTypeFieldExtraProps { - return this[settingPropEntrySymbol].extraProps; + return this[settingFieldSymbol].extraProps; } get props(): IPublicModelSettingTopEntry { - return ShellSettingTopEntry.create(this[settingPropEntrySymbol].props); + return ShellSettingTopEntry.create(this[settingFieldSymbol].props); } /** * 获取设置属性对应的节点实例 */ get node(): IPublicModelNode | null { - return ShellNode.create(this[settingPropEntrySymbol].getNode()); + return ShellNode.create(this[settingFieldSymbol].getNode()); } /** * 获取设置属性的父设置属性 */ - get parent(): IPublicModelSettingPropEntry { - return SettingPropEntry.create(this[settingPropEntrySymbol].parent as any); + get parent(): IPublicModelSettingField | IPublicModelSettingTopEntry { + if (isSettingField(this[settingFieldSymbol].parent)) { + return SettingField.create(this[settingFieldSymbol].parent); + } + + return SettingTopEntry.create(this[settingFieldSymbol].parent); } /** * 获取顶级设置属性 */ get top(): IPublicModelSettingTopEntry { - return ShellSettingTopEntry.create(this[settingPropEntrySymbol].top); + return ShellSettingTopEntry.create(this[settingFieldSymbol].top); } /** * 是否是 SettingField 实例 */ get isSettingField(): boolean { - return this[settingPropEntrySymbol].isSettingField; + return this[settingFieldSymbol].isSettingField; } /** * componentMeta */ get componentMeta(): IPublicModelComponentMeta | null { - return ShellComponentMeta.create(this[settingPropEntrySymbol].componentMeta); + return ShellComponentMeta.create(this[settingFieldSymbol].componentMeta); } /** * 获取设置属性的 items */ - get items(): Array<IPublicModelSettingPropEntry | IPublicTypeCustomView> { - return this[settingPropEntrySymbol].items?.map((item) => { + get items(): Array<IPublicModelSettingField | IPublicTypeCustomView> { + return this[settingFieldSymbol].items?.map((item) => { if (isCustomView(item)) { return item; } - return item.internalToShellPropEntry(); + return item.internalToShell(); }); } @@ -147,7 +152,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @param key */ setKey(key: string | number): void { - this[settingPropEntrySymbol].setKey(key); + this[settingFieldSymbol].setKey(key); } /** @@ -169,7 +174,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @param val 值 */ setValue(val: IPublicTypeCompositeValue, extraOptions?: IPublicTypeSetValueOptions): void { - this[settingPropEntrySymbol].setValue(val, false, false, extraOptions); + this[settingFieldSymbol].setValue(val, false, false, extraOptions); } /** @@ -178,7 +183,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @param value 值 */ setPropValue(propName: string | number, value: any): void { - this[settingPropEntrySymbol].setPropValue(propName, value); + this[settingFieldSymbol].setPropValue(propName, value); } /** @@ -186,7 +191,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @param propName */ clearPropValue(propName: string | number): void { - this[settingPropEntrySymbol].clearPropValue(propName); + this[settingFieldSymbol].clearPropValue(propName); } /** @@ -194,7 +199,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @returns */ getDefaultValue(): any { - return this[settingPropEntrySymbol].getDefaultValue(); + return this[settingFieldSymbol].getDefaultValue(); } /** @@ -202,7 +207,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @returns */ getValue(): any { - return this[settingPropEntrySymbol].getValue(); + return this[settingFieldSymbol].getValue(); } /** @@ -211,21 +216,21 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @returns */ getPropValue(propName: string | number): any { - return this[settingPropEntrySymbol].getPropValue(propName); + return this[settingFieldSymbol].getPropValue(propName); } /** * 获取顶层附属属性值 */ getExtraPropValue(propName: string): any { - return this[settingPropEntrySymbol].getExtraPropValue(propName); + return this[settingFieldSymbol].getExtraPropValue(propName); } /** * 设置顶层附属属性值 */ setExtraPropValue(propName: string, value: any): void { - this[settingPropEntrySymbol].setExtraPropValue(propName, value); + this[settingFieldSymbol].setExtraPropValue(propName, value); } /** @@ -233,7 +238,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @returns */ getProps(): IPublicModelSettingTopEntry { - return ShellSettingTopEntry.create(this[settingPropEntrySymbol].getProps() as ISettingEntry); + return ShellSettingTopEntry.create(this[settingFieldSymbol].getProps()); } /** @@ -241,7 +246,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @returns */ isUseVariable(): boolean { - return this[settingPropEntrySymbol].isUseVariable(); + return this[settingFieldSymbol].isUseVariable(); } /** @@ -249,7 +254,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @param flag */ setUseVariable(flag: boolean): void { - this[settingPropEntrySymbol].setUseVariable(flag); + this[settingFieldSymbol].setUseVariable(flag); } /** @@ -257,8 +262,8 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @param config * @returns */ - createField(config: IPublicTypeFieldConfig): IPublicModelSettingPropEntry { - return SettingPropEntry.create(this[settingPropEntrySymbol].createField(config)); + createField(config: IPublicTypeFieldConfig): IPublicModelSettingField { + return SettingField.create(this[settingFieldSymbol].createField(config)); } /** @@ -266,21 +271,21 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @returns */ getMockOrValue(): any { - return this[settingPropEntrySymbol].getMockOrValue(); + return this[settingFieldSymbol].getMockOrValue(); } /** * 销毁当前 field 实例 */ purge(): void { - this[settingPropEntrySymbol].purge(); + this[settingFieldSymbol].purge(); } /** * 移除当前 field 实例 */ remove(): void { - this[settingPropEntrySymbol].remove(); + this[settingFieldSymbol].remove(); } /** @@ -288,15 +293,15 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @param action * @returns */ - onEffect(action: () => void): () => void { - return this[settingPropEntrySymbol].onEffect(action); + onEffect(action: () => void): IPublicTypeDisposable { + return this[settingFieldSymbol].onEffect(action); } /** * 返回 shell 模型,兼容某些场景下 field 已经是 shell field 了 * @returns */ - internalToShellPropEntry() { + internalToShellField() { return this; } } diff --git a/packages/shell/src/model/setting-top-entry.ts b/packages/shell/src/model/setting-top-entry.ts index 7947baffa6..8afed43a50 100644 --- a/packages/shell/src/model/setting-top-entry.ts +++ b/packages/shell/src/model/setting-top-entry.ts @@ -1,17 +1,17 @@ -import { ISettingEntry } from '@alilc/lowcode-designer'; +import { ISettingTopEntry } from '@alilc/lowcode-designer'; import { settingTopEntrySymbol } from '../symbols'; import { Node as ShellNode } from './node'; -import { SettingPropEntry as ShellSettingPropEntry } from './setting-prop-entry'; -import { IPublicModelSettingTopEntry, IPublicModelNode, IPublicModelSettingPropEntry } from '@alilc/lowcode-types'; +import { IPublicModelSettingTopEntry, IPublicModelNode, IPublicModelSettingField } from '@alilc/lowcode-types'; +import { SettingField } from './setting-field'; export class SettingTopEntry implements IPublicModelSettingTopEntry { - private readonly [settingTopEntrySymbol]: ISettingEntry; + private readonly [settingTopEntrySymbol]: ISettingTopEntry; - constructor(prop: ISettingEntry) { + constructor(prop: ISettingTopEntry) { this[settingTopEntrySymbol] = prop; } - static create(prop: ISettingEntry): IPublicModelSettingTopEntry { + static create(prop: ISettingTopEntry): IPublicModelSettingTopEntry { return new SettingTopEntry(prop); } @@ -27,8 +27,8 @@ export class SettingTopEntry implements IPublicModelSettingTopEntry { * @param propName * @returns */ - get(propName: string | number): IPublicModelSettingPropEntry { - return ShellSettingPropEntry.create(this[settingTopEntrySymbol].get(propName) as any); + get(propName: string | number): IPublicModelSettingField { + return SettingField.create(this[settingTopEntrySymbol].get(propName)!); } /** @@ -55,4 +55,8 @@ export class SettingTopEntry implements IPublicModelSettingTopEntry { setPropValue(propName: string | number, value: any): void { this[settingTopEntrySymbol].setPropValue(propName, value); } + + clearPropValue(propName: string | number) { + this[settingTopEntrySymbol].clearPropValue(propName); + } } \ No newline at end of file diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index 83d831747b..4ba6ff2369 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -10,7 +10,7 @@ export const nodeSymbol = Symbol('node'); export const modalNodesManagerSymbol = Symbol('modalNodesManager'); export const nodeChildrenSymbol = Symbol('nodeChildren'); export const propSymbol = Symbol('prop'); -export const settingPropEntrySymbol = Symbol('settingPropEntry'); +export const settingFieldSymbol = Symbol('settingField'); export const settingTopEntrySymbol = Symbol('settingTopEntry'); export const propsSymbol = Symbol('props'); export const detectingSymbol = Symbol('detecting'); diff --git a/packages/types/src/shell-model-factory.ts b/packages/types/src/shell-model-factory.ts index a7a57648f1..b6044ced9e 100644 --- a/packages/types/src/shell-model-factory.ts +++ b/packages/types/src/shell-model-factory.ts @@ -1,8 +1,9 @@ -import { IPublicModelSettingPropEntry, IPublicModelNode } from './shell'; +import { IPublicModelNode, IPublicModelSettingField } from './shell'; export interface IShellModelFactory { // TODO: 需要给 innerNode 提供一个 interface 并用在这里 createNode(node: any | null | undefined): IPublicModelNode | null; // TODO: 需要给 InnerSettingField 提供一个 interface 并用在这里 - createSettingPropEntry(prop: any): IPublicModelSettingPropEntry; + + createSettingField(prop: any): IPublicModelSettingField; } diff --git a/packages/types/src/shell/model/index.ts b/packages/types/src/shell/model/index.ts index 097e18065a..b62fb76b95 100644 --- a/packages/types/src/shell/model/index.ts +++ b/packages/types/src/shell/model/index.ts @@ -29,5 +29,4 @@ export * from './plugin-instance'; export * from './sensor'; export * from './resource'; export * from './clipboard'; -export * from './setting-entry'; export * from './setting-field'; diff --git a/packages/types/src/shell/model/props.ts b/packages/types/src/shell/model/props.ts index 3c390a8cf6..f3ef2e4519 100644 --- a/packages/types/src/shell/model/props.ts +++ b/packages/types/src/shell/model/props.ts @@ -1,5 +1,5 @@ import { IPublicTypeCompositeValue } from '../type'; -import { IPublicModelNode } from './'; +import { IPublicModelNode, IPublicModelProp } from './'; export interface IBaseModelProps< Prop @@ -86,4 +86,4 @@ export interface IBaseModelProps< } -export type IPublicModelProps = IBaseModelProps<IPublicModelProps>; \ No newline at end of file +export interface IPublicModelProps extends IBaseModelProps<IPublicModelProp> {}; \ No newline at end of file diff --git a/packages/types/src/shell/model/setting-entry.ts b/packages/types/src/shell/model/setting-entry.ts deleted file mode 100644 index ec5b423189..0000000000 --- a/packages/types/src/shell/model/setting-entry.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { IPublicModelComponentMeta } from "./component-meta"; -import { IPublicModelNode } from "./node"; -import { IBaseModelSettingTarget } from "./setting-target"; - -export interface IBaseModelSettingEntry< - Node, - ComponentMeta, - SettingEntry -> extends IBaseModelSettingTarget< - SettingEntry -> { - readonly nodes: Node[]; - readonly componentMeta: ComponentMeta | null; -} - -export interface IPublicModelSettingEntry extends IBaseModelSettingEntry< - IPublicModelNode, - IPublicModelComponentMeta, - IPublicModelSettingEntry -> {} \ No newline at end of file diff --git a/packages/types/src/shell/model/setting-field.ts b/packages/types/src/shell/model/setting-field.ts index 5efa4c6467..a2dd4fd28a 100644 --- a/packages/types/src/shell/model/setting-field.ts +++ b/packages/types/src/shell/model/setting-field.ts @@ -1,5 +1,198 @@ -import { IPublicModelSettingEntry } from "./setting-entry"; +import { IPublicTypeCustomView, IPublicTypeCompositeValue, IPublicTypeSetterType, IPublicTypeSetValueOptions, IPublicTypeFieldConfig, IPublicTypeFieldExtraProps, IPublicTypeDisposable } from '../type'; +import { IPublicModelNode, IPublicModelComponentMeta, IPublicModelSettingTopEntry } from './'; -export interface IPublicModelSettingField extends IPublicModelSettingEntry { +export interface IBaseModelSettingField< + SettingTopEntry, + SettingField, + ComponentMeta, + Node +> { + + /** + * 获取设置属性的 isGroup + */ + get isGroup(): boolean; + + /** + * 获取设置属性的 id + */ + get id(): string; + + /** + * 获取设置属性的 name + */ + get name(): string | number | undefined; + + /** + * 获取设置属性的 key + */ + get key(): string | number | undefined; + + /** + * 获取设置属性的 path + */ + get path(): any[]; + + /** + * 获取设置属性的 title + */ + get title(): any; + + /** + * 获取设置属性的 setter + */ + get setter(): IPublicTypeSetterType | null; + + /** + * 获取设置属性的 expanded + */ + get expanded(): boolean; + + /** + * 获取设置属性的 extraProps + */ + get extraProps(): IPublicTypeFieldExtraProps; + + get props(): SettingTopEntry; + + /** + * 获取设置属性对应的节点实例 + */ + get node(): Node | null; + + /** + * 获取设置属性的父设置属性 + */ + readonly parent: SettingTopEntry | SettingField; + + /** + * 获取顶级设置属性 + */ + get top(): SettingTopEntry; + + /** + * 是否是 SettingField 实例 + */ + get isSettingField(): boolean; + + /** + * componentMeta + */ + get componentMeta(): ComponentMeta | null; + + /** + * 获取设置属性的 items + */ + get items(): Array<SettingField | IPublicTypeCustomView>; + + /** + * 设置 key 值 + * @param key + */ + setKey(key: string | number): void; + + /** + * 设置值 + * @param val 值 + */ + setValue(val: IPublicTypeCompositeValue, extraOptions?: IPublicTypeSetValueOptions): void; + + /** + * 设置子级属性值 + * @param propName 子属性名 + * @param value 值 + */ + setPropValue(propName: string | number, value: any): void; + + /** + * 清空指定属性值 + * @param propName + */ + clearPropValue(propName: string | number): void; + + /** + * 获取配置的默认值 + * @returns + */ + getDefaultValue(): any; + + /** + * 获取值 + * @returns + */ + getValue(): any; + + /** + * 获取子级属性值 + * @param propName 子属性名 + * @returns + */ + getPropValue(propName: string | number): any; + + /** + * 获取顶层附属属性值 + */ + getExtraPropValue(propName: string): any; + + /** + * 设置顶层附属属性值 + */ + setExtraPropValue(propName: string, value: any): void; + + /** + * 获取设置属性集 + * @returns + */ + getProps(): SettingTopEntry; + + /** + * 是否绑定了变量 + * @returns + */ + isUseVariable(): boolean; + + /** + * 设置绑定变量 + * @param flag + */ + setUseVariable(flag: boolean): void; + + /** + * 创建一个设置 field 实例 + * @param config + * @returns + */ + createField(config: IPublicTypeFieldConfig): SettingField; + + /** + * 获取值,当为变量时,返回 mock + * @returns + */ + getMockOrValue(): any; + + /** + * 销毁当前 field 实例 + */ + purge(): void; + + /** + * 移除当前 field 实例 + */ + remove(): void; + + /** + * 设置 autorun + * @param action + * @returns + */ + onEffect(action: () => void): IPublicTypeDisposable; +} + +export interface IPublicModelSettingField extends IBaseModelSettingField< + IPublicModelSettingTopEntry, + IPublicModelSettingField, + IPublicModelComponentMeta, + IPublicModelNode +> { } \ No newline at end of file diff --git a/packages/types/src/shell/model/setting-prop-entry.ts b/packages/types/src/shell/model/setting-prop-entry.ts index f392cda338..b40eab8bff 100644 --- a/packages/types/src/shell/model/setting-prop-entry.ts +++ b/packages/types/src/shell/model/setting-prop-entry.ts @@ -1,184 +1,6 @@ -import { IPublicTypeCustomView, IPublicTypeCompositeValue, IPublicTypeSetterType, IPublicTypeSetValueOptions, IPublicTypeFieldConfig, IPublicTypeFieldExtraProps } from '../type'; -import { IPublicModelNode, IPublicModelComponentMeta, IPublicModelSettingTopEntry } from './'; +import { IPublicModelSettingField } from './'; -export interface IPublicModelSettingPropEntry { - - /** - * 获取设置属性的 isGroup - */ - get isGroup(): boolean; - - /** - * 获取设置属性的 id - */ - get id(): string; - - /** - * 获取设置属性的 name - */ - get name(): string | number; - - /** - * 获取设置属性的 key - */ - get key(): string | number; - - /** - * 获取设置属性的 path - */ - get path(): any[]; - - /** - * 获取设置属性的 title - */ - get title(): any; - - /** - * 获取设置属性的 setter - */ - get setter(): IPublicTypeSetterType | null; - - /** - * 获取设置属性的 expanded - */ - get expanded(): boolean; - - /** - * 获取设置属性的 extraProps - */ - get extraProps(): IPublicTypeFieldExtraProps; - - get props(): IPublicModelSettingTopEntry; - - /** - * 获取设置属性对应的节点实例 - */ - get node(): IPublicModelNode | null; - - /** - * 获取设置属性的父设置属性 - */ - get parent(): IPublicModelSettingPropEntry; - - /** - * 获取顶级设置属性 - */ - get top(): IPublicModelSettingTopEntry; - - /** - * 是否是 SettingField 实例 - */ - get isSettingField(): boolean; - - /** - * componentMeta - */ - get componentMeta(): IPublicModelComponentMeta | null; - - /** - * 获取设置属性的 items - */ - get items(): Array<IPublicModelSettingPropEntry | IPublicTypeCustomView>; - - /** - * 设置 key 值 - * @param key - */ - setKey(key: string | number): void; - - /** - * 设置值 - * @param val 值 - */ - setValue(val: IPublicTypeCompositeValue, extraOptions?: IPublicTypeSetValueOptions): void; - - /** - * 设置子级属性值 - * @param propName 子属性名 - * @param value 值 - */ - setPropValue(propName: string | number, value: any): void; - - /** - * 清空指定属性值 - * @param propName - */ - clearPropValue(propName: string | number): void; - - /** - * 获取配置的默认值 - * @returns - */ - getDefaultValue(): any; - - /** - * 获取值 - * @returns - */ - getValue(): any; - - /** - * 获取子级属性值 - * @param propName 子属性名 - * @returns - */ - getPropValue(propName: string | number): any; - - /** - * 获取顶层附属属性值 - */ - getExtraPropValue(propName: string): any; - - /** - * 设置顶层附属属性值 - */ - setExtraPropValue(propName: string, value: any): void; - - /** - * 获取设置属性集 - * @returns - */ - getProps(): IPublicModelSettingTopEntry; - - /** - * 是否绑定了变量 - * @returns - */ - isUseVariable(): boolean; - - /** - * 设置绑定变量 - * @param flag - */ - setUseVariable(flag: boolean): void; - - /** - * 创建一个设置 field 实例 - * @param config - * @returns - */ - createField(config: IPublicTypeFieldConfig): IPublicModelSettingPropEntry; - - /** - * 获取值,当为变量时,返回 mock - * @returns - */ - getMockOrValue(): any; - - /** - * 销毁当前 field 实例 - */ - purge(): void; - - /** - * 移除当前 field 实例 - */ - remove(): void; - - /** - * 设置 autorun - * @param action - * @returns - */ - onEffect(action: () => void): () => void; -} +/** + * @deprecated please use IPublicModelSettingField + */ +export type IPublicModelSettingPropEntry = IPublicModelSettingField diff --git a/packages/types/src/shell/model/setting-target.ts b/packages/types/src/shell/model/setting-target.ts index 78bd924e15..6df1e36e99 100644 --- a/packages/types/src/shell/model/setting-target.ts +++ b/packages/types/src/shell/model/setting-target.ts @@ -1,101 +1,6 @@ -import { IPublicApiSetters } from '../api'; -import { IPublicModelEditor } from './'; +import { IPublicModelSettingField } from './'; -export interface IBaseModelSettingTarget< - SettingTarget -> { - - /** - * 同样类型的节点 - */ - readonly isSameComponent: boolean; - - /** - * 一个 - */ - readonly isSingle: boolean; - - /** - * 多个 - */ - readonly isMultiple: boolean; - - /** - * 编辑器引用 - */ - readonly editor: IPublicModelEditor; - - readonly setters: IPublicApiSetters; - - /** - * 访问路径 - */ - readonly path: Array<string| number>; - - /** - * 顶端 - */ - readonly top: SettingTarget; - - /** - * 父级 - */ - readonly parent: SettingTarget; - - /** - * 获取当前值 - */ - getValue: () => any; - - /** - * 设置当前值 - */ - setValue: (value: any) => void; - - /** - * 取得子项 - */ - get: (propName: string | number) => SettingTarget | null; - - /** - * 取得子项 - */ - getProps?: () => SettingTarget; - - /** - * 获取子项属性值 - */ - getPropValue: (propName: string | number) => any; - - /** - * 设置子项属性值 - */ - setPropValue: (propName: string | number, value: any) => void; - - /** - * 清除已设置值 - */ - clearPropValue: (propName: string | number) => void; - - /** - * 获取顶层附属属性值 - */ - getExtraPropValue: (propName: string) => any; - - /** - * 设置顶层附属属性值 - */ - setExtraPropValue: (propName: string, value: any) => void; - - // @todo 补充 node 定义 - /** - * 获取 node 中的第一项 - */ - getNode: () => any; -} - -export interface IPublicModelSettingTarget extends IBaseModelSettingTarget< - IPublicModelSettingTarget -> { - -} +/** + * @deprecated please use IPublicModelSettingField + */ +export type IPublicModelSettingTarget = IPublicModelSettingField; diff --git a/packages/types/src/shell/model/setting-top-entry.ts b/packages/types/src/shell/model/setting-top-entry.ts index b609d24f38..1c3d6c2f15 100644 --- a/packages/types/src/shell/model/setting-top-entry.ts +++ b/packages/types/src/shell/model/setting-top-entry.ts @@ -1,18 +1,21 @@ -import { IPublicModelNode, IPublicModelSettingPropEntry } from './'; +import { IPublicModelNode, IPublicModelSettingField } from './'; -export interface IPublicModelSettingTopEntry { +export interface IPublicModelSettingTopEntry< + Node = IPublicModelNode, + SettingField = IPublicModelSettingField +> { /** * 返回所属的节点实例 */ - get node(): IPublicModelNode | null; + get node(): Node | null; /** * 获取子级属性对象 * @param propName * @returns */ - get(propName: string | number): IPublicModelSettingPropEntry; + get(propName: string | number): SettingField | null; /** * 获取指定 propName 的值 @@ -27,4 +30,10 @@ export interface IPublicModelSettingTopEntry { * @param value */ setPropValue(propName: string | number, value: any): void; + + /** + * 清除指定 propName 的值 + * @param propName + */ + clearPropValue(propName: string | number): void; } diff --git a/packages/types/src/shell/type/advanced.ts b/packages/types/src/shell/type/advanced.ts index f4c750535c..8a6db85b67 100644 --- a/packages/types/src/shell/type/advanced.ts +++ b/packages/types/src/shell/type/advanced.ts @@ -1,6 +1,6 @@ import { ComponentType, ReactElement } from 'react'; import { IPublicTypeNodeData, IPublicTypeSnippet, IPublicTypeInitialItem, IPublicTypeFilterItem, IPublicTypeAutorunItem, IPublicTypeCallbacks, IPublicTypeLiveTextEditingConfig } from './'; -import { IPublicModelSettingTarget } from '../model'; +import { IPublicModelNode, IPublicModelSettingField } from '../model'; /** * 高级特性配置 @@ -17,7 +17,7 @@ export interface IPublicTypeAdvanced { /** * 拖入容器时,自动带入 children 列表 */ - initialChildren?: IPublicTypeNodeData[] | ((target: IPublicModelSettingTarget) => IPublicTypeNodeData[]); + initialChildren?: IPublicTypeNodeData[] | ((target: IPublicModelNode) => IPublicTypeNodeData[]); /** * 样式 及 位置,handle 上必须有明确的标识以便事件路由判断,或者主动设置事件独占模式 diff --git a/packages/types/src/shell/type/dynamic-props.ts b/packages/types/src/shell/type/dynamic-props.ts index 5db033d70b..1d87a65671 100644 --- a/packages/types/src/shell/type/dynamic-props.ts +++ b/packages/types/src/shell/type/dynamic-props.ts @@ -1,3 +1,3 @@ -import { IPublicModelSettingTarget } from '../model/setting-target'; +import { IPublicModelSettingField } from '../model'; -export type IPublicTypeDynamicProps = (target: IPublicModelSettingTarget) => Record<string, unknown>; +export type IPublicTypeDynamicProps = (target: IPublicModelSettingField) => Record<string, unknown>; diff --git a/packages/types/src/shell/type/field-extra-props.ts b/packages/types/src/shell/type/field-extra-props.ts index 79466389e0..4827571dd8 100644 --- a/packages/types/src/shell/type/field-extra-props.ts +++ b/packages/types/src/shell/type/field-extra-props.ts @@ -1,4 +1,4 @@ -import { IPublicModelSettingPropEntry, IPublicModelSettingTarget } from '../model'; +import { IPublicModelSettingField } from '../model'; import { IPublicTypeLiveTextEditingConfig } from './'; /** @@ -19,28 +19,28 @@ export interface IPublicTypeFieldExtraProps { /** * get value for field */ - getValue?: (target: IPublicModelSettingPropEntry, fieldValue: any) => any; + getValue?: (target: IPublicModelSettingField, fieldValue: any) => any; /** * set value for field */ - setValue?: (target: IPublicModelSettingPropEntry, value: any) => void; + setValue?: (target: IPublicModelSettingField, value: any) => void; /** * the field conditional show, is not set always true * @default undefined */ - condition?: (target: IPublicModelSettingPropEntry) => boolean; + condition?: (target: IPublicModelSettingField) => boolean; /** * autorun when something change */ - autorun?: (target: IPublicModelSettingTarget) => void; + autorun?: (target: IPublicModelSettingField) => void; /** * is this field is a virtual field that not save to schema */ - virtual?: (target: IPublicModelSettingTarget) => boolean; + virtual?: (target: IPublicModelSettingField) => boolean; /** * default collapsed when display accordion diff --git a/packages/types/src/shell/type/metadata.ts b/packages/types/src/shell/type/metadata.ts index 5659916b84..7f972622be 100644 --- a/packages/types/src/shell/type/metadata.ts +++ b/packages/types/src/shell/type/metadata.ts @@ -1,5 +1,5 @@ import { IPublicTypePropType, IPublicTypeComponentAction } from './'; -import { IPublicModelNode, IPublicModelProp, IPublicModelSettingTarget } from '../model'; +import { IPublicModelNode, IPublicModelProp, IPublicModelSettingField } from '../model'; /** * 嵌套控制函数 @@ -93,11 +93,11 @@ export interface IPublicTypeComponentConfigure { export interface IPublicTypeInitialItem { name: string; - initial: (target: IPublicModelSettingTarget, currentValue: any) => any; + initial: (target: IPublicModelSettingField, currentValue: any) => any; } export interface IPublicTypeFilterItem { name: string; - filter: (target: IPublicModelSettingTarget | null, currentValue: any) => any; + filter: (target: IPublicModelSettingField | null, currentValue: any) => any; } export interface IPublicTypeAutorunItem { name: string; diff --git a/packages/types/src/shell/type/setter-config.ts b/packages/types/src/shell/type/setter-config.ts index ac8a05aa3d..c0f93679ee 100644 --- a/packages/types/src/shell/type/setter-config.ts +++ b/packages/types/src/shell/type/setter-config.ts @@ -1,5 +1,4 @@ -import { IPublicModelSettingTarget } from '../model/setting-target'; -import { IPublicTypeCustomView, IPublicTypeCompositeValue, IPublicTypeTitleContent } from '..'; +import { IPublicTypeCustomView, IPublicTypeCompositeValue, IPublicTypeTitleContent, IPublicModelSettingField } from '..'; import { IPublicTypeDynamicProps } from './dynamic-props'; /** @@ -37,7 +36,7 @@ export interface IPublicTypeSetterConfig { * * @todo initialValue 可能要和 defaultValue 二选一 */ - initialValue?: any | ((target: IPublicModelSettingTarget) => any); + initialValue?: any | ((target: IPublicModelSettingField) => any); defaultValue?: any; @@ -51,7 +50,7 @@ export interface IPublicTypeSetterConfig { /** * 给 MixedSetter 用于判断优先选中哪个 */ - condition?: (target: IPublicModelSettingTarget) => boolean; + condition?: (target: IPublicModelSettingField) => boolean; /** * 给 MixedSetter,切换值时声明类型 From 95a1137b466b73d7dabe9a453e2016bd0c51322c Mon Sep 17 00:00:00 2001 From: beautiful-boyyy <66351806+beautiful-boyyy@users.noreply.github.com> Date: Wed, 15 Mar 2023 15:14:24 +0800 Subject: [PATCH 047/469] fix: fix tooltip being covered by other elements (#1717) * docs: fix incorrect content for emit method in event api * fix: Fix tooltip being covered by other elements --- packages/editor-core/src/widgets/tip/tip-container.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/editor-core/src/widgets/tip/tip-container.tsx b/packages/editor-core/src/widgets/tip/tip-container.tsx index 81750bd6a4..ae494d5409 100644 --- a/packages/editor-core/src/widgets/tip/tip-container.tsx +++ b/packages/editor-core/src/widgets/tip/tip-container.tsx @@ -3,12 +3,10 @@ import { TipItem } from './tip-item'; import { tipHandler } from './tip-handler'; export class TipContainer extends Component { + private dispose?: () => void; shouldComponentUpdate() { return false; } - - private dispose?: () => void; - componentDidMount() { const over = (e: MouseEvent) => tipHandler.setTarget(e.target as any); const down = () => tipHandler.hideImmediately(); @@ -27,10 +25,11 @@ export class TipContainer extends Component { } render() { - return ( + return window.ReactDOM.createPortal( <div className="lc-tips-container"> <TipItem /> - </div> + </div>, + document.querySelector('body')!, ); } } From eeb6719a1ff1defff3b91a2f1455d0b7daaa252d Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 15 Mar 2023 16:17:18 +0800 Subject: [PATCH 048/469] feat: optimize outline tree performance and ts definition --- packages/designer/src/project/project.ts | 5 ++-- .../src/controllers/pane-controller.ts | 2 +- .../plugin-outline-pane/src/views/filter.tsx | 4 +-- .../plugin-outline-pane/src/views/pane.tsx | 4 +-- .../src/views/tree-branches.tsx | 23 ++++++++++------ .../src/views/tree-node.tsx | 8 +++--- .../src/views/tree-title.tsx | 15 +++++------ .../plugin-outline-pane/src/views/tree.tsx | 27 +++++++++++-------- packages/types/src/shell/api/common.ts | 10 ++++--- packages/types/src/shell/api/project.ts | 6 +++-- 10 files changed, 60 insertions(+), 44 deletions(-) diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 55ac584fbc..51db678ad0 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -5,14 +5,13 @@ import { IPublicTypeProjectSchema, IPublicTypeRootSchema, IPublicTypeComponentsMap, - IPublicApiProject, - IPublicModelDocumentModel, IPublicEnumTransformStage, + IBaseApiProject, } from '@alilc/lowcode-types'; import { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils'; import { ISimulatorHost } from '../simulator'; -export interface IProject extends Omit< IPublicApiProject< +export interface IProject extends Omit< IBaseApiProject< IDocumentModel >, 'simulatorHost' | diff --git a/packages/plugin-outline-pane/src/controllers/pane-controller.ts b/packages/plugin-outline-pane/src/controllers/pane-controller.ts index d3187687af..a02844ad1b 100644 --- a/packages/plugin-outline-pane/src/controllers/pane-controller.ts +++ b/packages/plugin-outline-pane/src/controllers/pane-controller.ts @@ -444,7 +444,7 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTy event: e, detail: { type: IPublicTypeLocationDetailType.Children, - index: index + 1, + index: (index || 0) + 1, valid: document?.checkNesting(node.parent!, dragObject as any), near: { node, pos: 'after' }, focus: checkRecursion(focusNode, dragObject) ? { type: 'node', node: focusNode } : undefined, diff --git a/packages/plugin-outline-pane/src/views/filter.tsx b/packages/plugin-outline-pane/src/views/filter.tsx index d4fa792aea..166a5c8e2f 100644 --- a/packages/plugin-outline-pane/src/views/filter.tsx +++ b/packages/plugin-outline-pane/src/views/filter.tsx @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React, { PureComponent } from 'react'; import './style.less'; import { IconFilter } from '../icons/filter'; import { Search, Checkbox, Balloon, Divider } from '@alifd/next'; @@ -7,7 +7,7 @@ import { Tree } from '../controllers/tree'; import { matchTreeNode, FILTER_OPTIONS } from './filter-tree'; import { IPublicModelPluginContext } from '@alilc/lowcode-types'; -export default class Filter extends Component<{ +export default class Filter extends PureComponent<{ tree: Tree; pluginContext: IPublicModelPluginContext; }, { diff --git a/packages/plugin-outline-pane/src/views/pane.tsx b/packages/plugin-outline-pane/src/views/pane.tsx index 4cee54a511..adaada7862 100644 --- a/packages/plugin-outline-pane/src/views/pane.tsx +++ b/packages/plugin-outline-pane/src/views/pane.tsx @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React, { PureComponent } from 'react'; import { PaneController } from '../controllers/pane-controller'; import TreeView from './tree'; import './style.less'; @@ -6,7 +6,7 @@ import { IPublicModelPluginContext } from '@alilc/lowcode-types'; import Filter from './filter'; import { TreeMaster } from '../controllers/tree-master'; -export class Pane extends Component<{ +export class Pane extends PureComponent<{ config: any; pluginContext: IPublicModelPluginContext; treeMaster: TreeMaster; diff --git a/packages/plugin-outline-pane/src/views/tree-branches.tsx b/packages/plugin-outline-pane/src/views/tree-branches.tsx index d9b0f83a87..abbc5a840c 100644 --- a/packages/plugin-outline-pane/src/views/tree-branches.tsx +++ b/packages/plugin-outline-pane/src/views/tree-branches.tsx @@ -1,10 +1,10 @@ -import { Component } from 'react'; +import { PureComponent } from 'react'; import classNames from 'classnames'; import TreeNode from '../controllers/tree-node'; import TreeNodeView from './tree-node'; -import { IPublicModelPluginContext, IPublicModelExclusiveGroup, IPublicTypeDisposable } from '@alilc/lowcode-types'; +import { IPublicModelPluginContext, IPublicModelExclusiveGroup, IPublicTypeDisposable, IPublicTypeLocationChildrenDetail } from '@alilc/lowcode-types'; -export default class TreeBranches extends Component<{ +export default class TreeBranches extends PureComponent<{ treeNode: TreeNode; isModal?: boolean; pluginContext: IPublicModelPluginContext; @@ -62,12 +62,19 @@ export default class TreeBranches extends Component<{ } } -class TreeNodeChildren extends Component<{ + +interface ITreeNodeChildrenState { + filterWorking: boolean; + matchSelf: boolean; + keywords: string | null; + dropDetail: IPublicTypeLocationChildrenDetail | undefined | null; +} +class TreeNodeChildren extends PureComponent<{ treeNode: TreeNode; isModal?: boolean; pluginContext: IPublicModelPluginContext; - }> { - state = { + }, ITreeNodeChildrenState> { + state: ITreeNodeChildrenState = { filterWorking: false, matchSelf: false, keywords: null, @@ -144,7 +151,7 @@ class TreeNodeChildren extends Component<{ /> ); treeNode.children?.forEach((child, index) => { - const childIsModal = child.node.componentMeta.isModal || false; + const childIsModal = child.node.componentMeta?.isModal || false; if (isModal != childIsModal) { return; } @@ -180,7 +187,7 @@ class TreeNodeChildren extends Component<{ } } -class TreeNodeSlots extends Component<{ +class TreeNodeSlots extends PureComponent<{ treeNode: TreeNode; pluginContext: IPublicModelPluginContext; }> { diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx index 213418fb90..1531eaf635 100644 --- a/packages/plugin-outline-pane/src/views/tree-node.tsx +++ b/packages/plugin-outline-pane/src/views/tree-node.tsx @@ -1,4 +1,4 @@ -import { Component } from 'react'; +import { PureComponent } from 'react'; import classNames from 'classnames'; import TreeNode from '../controllers/tree-node'; import TreeTitle from './tree-title'; @@ -6,7 +6,7 @@ import TreeBranches from './tree-branches'; import { IconEyeClose } from '../icons/eye-close'; import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicModelDocumentModel, IPublicTypeDisposable } from '@alilc/lowcode-types'; -class ModalTreeNodeView extends Component<{ +class ModalTreeNodeView extends PureComponent<{ treeNode: TreeNode; pluginContext: IPublicModelPluginContext; }> { @@ -59,11 +59,11 @@ class ModalTreeNodeView extends Component<{ } } -export default class TreeNodeView extends Component<{ +export default class TreeNodeView extends PureComponent<{ treeNode: TreeNode; isModal?: boolean; pluginContext: IPublicModelPluginContext; - isRootNode: boolean; + isRootNode?: boolean; }> { state = { expanded: false, diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 51d0fcf805..6e1b14a466 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -1,5 +1,4 @@ -/* eslint-disable max-len */ -import { Component, KeyboardEvent, FocusEvent, Fragment } from 'react'; +import { KeyboardEvent, FocusEvent, Fragment, PureComponent } from 'react'; import classNames from 'classnames'; import { createIcon } from '@alilc/lowcode-utils'; import { IPublicModelPluginContext, IPublicApiEvent } from '@alilc/lowcode-types'; @@ -17,7 +16,7 @@ function emitOutlineEvent(event: IPublicApiEvent, type: string, treeNode: TreeNo }); } -export default class TreeTitle extends Component<{ +export default class TreeTitle extends PureComponent<{ treeNode: TreeNode; isModal?: boolean; expanded: boolean; @@ -36,7 +35,7 @@ export default class TreeTitle extends Component<{ private lastInput?: HTMLInputElement; - private enableEdit = (e) => { + private enableEdit = (e: MouseEvent) => { e.preventDefault(); this.setState({ editing: true, @@ -205,7 +204,7 @@ export default class TreeTitle extends Component<{ } } -class RenameBtn extends Component<{ +class RenameBtn extends PureComponent<{ treeNode: TreeNode; pluginContext: IPublicModelPluginContext; onClick: (e: any) => void; @@ -225,7 +224,7 @@ class RenameBtn extends Component<{ } } -class LockBtn extends Component<{ +class LockBtn extends PureComponent<{ treeNode: TreeNode; pluginContext: IPublicModelPluginContext; locked: boolean; @@ -249,7 +248,7 @@ class LockBtn extends Component<{ } } -class HideBtn extends Component<{ +class HideBtn extends PureComponent<{ treeNode: TreeNode; hidden: boolean; pluginContext: IPublicModelPluginContext; @@ -276,7 +275,7 @@ class HideBtn extends Component<{ } } -class ExpandBtn extends Component<{ +class ExpandBtn extends PureComponent<{ treeNode: TreeNode; pluginContext: IPublicModelPluginContext; expanded: boolean; diff --git a/packages/plugin-outline-pane/src/views/tree.tsx b/packages/plugin-outline-pane/src/views/tree.tsx index 4eb1dbfeed..930c65cce9 100644 --- a/packages/plugin-outline-pane/src/views/tree.tsx +++ b/packages/plugin-outline-pane/src/views/tree.tsx @@ -1,8 +1,9 @@ -import { Component, MouseEvent as ReactMouseEvent } from 'react'; +import { MouseEvent as ReactMouseEvent, PureComponent } from 'react'; import { isFormEvent, canClickNode, isShaken } from '@alilc/lowcode-utils'; import { Tree } from '../controllers/tree'; import TreeNodeView from './tree-node'; import { IPublicEnumDragObjectType, IPublicModelPluginContext, IPublicModelNode } from '@alilc/lowcode-types'; +import TreeNode from '../controllers/tree-node'; function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string { let target: Element | null = e.target as Element; @@ -17,7 +18,7 @@ function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string return (target as HTMLDivElement).dataset.id || null; } -export default class TreeView extends Component<{ +export default class TreeView extends PureComponent<{ tree: Tree; pluginContext: IPublicModelPluginContext; }> { @@ -60,12 +61,12 @@ export default class TreeView extends Component<{ const { id } = node; const isMulti = e.metaKey || e.ctrlKey || e.shiftKey; canvas.activeTracker?.track(node); - if (isMulti && !node.contains(focusNode) && selection.has(id)) { + if (isMulti && focusNode && !node.contains(focusNode) && selection?.has(id)) { if (!isFormEvent(e.nativeEvent)) { selection.remove(id); } } else { - selection.select(id); + selection?.select(id); const selectedNode = selection?.getNodes()?.[0]; const npm = selectedNode?.componentMeta?.npm; const selected = @@ -134,21 +135,23 @@ export default class TreeView extends Component<{ const isMulti = e.metaKey || e.ctrlKey || e.shiftKey; const isLeftButton = e.button === 0; - if (isLeftButton && !node.contains(focusNode)) { + if (isLeftButton && focusNode && !node.contains(focusNode)) { let nodes: IPublicModelNode[] = [node]; this.ignoreUpSelected = false; if (isMulti) { // multi select mode, directily add - if (!selection.has(node.id)) { + if (!selection?.has(node.id)) { canvas.activeTracker?.track(node); - selection.add(node.id); + selection?.add(node.id); this.ignoreUpSelected = true; } // todo: remove rootNodes id - selection.remove(focusNode.id); + selection?.remove(focusNode.id); // 获得顶层 nodes - nodes = selection.getTopNodes(); - } else if (selection.has(node.id)) { + if (selection) { + nodes = selection.getTopNodes(); + } + } else if (selection?.has(node.id)) { nodes = selection.getTopNodes(); } this.boostEvent = e.nativeEvent; @@ -169,7 +172,9 @@ export default class TreeView extends Component<{ doc?.detecting.leave(); }; - state = { + state: { + root: TreeNode | null + } = { root: null, }; diff --git a/packages/types/src/shell/api/common.ts b/packages/types/src/shell/api/common.ts index ceb85067f2..d00a2468b3 100644 --- a/packages/types/src/shell/api/common.ts +++ b/packages/types/src/shell/api/common.ts @@ -1,6 +1,6 @@ import { Component, ReactNode } from 'react'; -import { IPublicTypeNodeSchema } from '../type'; +import { IPublicTypeNodeSchema, IPublicTypeTitleContent } from '../type'; import { IPublicEnumTransitionType } from '../enum'; export interface IPublicApiCommonUtils { @@ -82,12 +82,16 @@ export interface IPublicApiCommonEditorCabin { * Title 组件 * @experimental unstable API, pay extra caution when trying to use this */ - get Tip(): Component; + get Tip(): React.FC<{}>; /** * Tip 组件 * @experimental unstable API, pay extra caution when trying to use this */ - get Title(): Component; + get Title(): React.FC<{ + title: IPublicTypeTitleContent | undefined; + match?: boolean; + keywords?: string | null; + }>; } export interface IPublicApiCommonDesignerCabin { diff --git a/packages/types/src/shell/api/project.ts b/packages/types/src/shell/api/project.ts index ead415e544..baea41b948 100644 --- a/packages/types/src/shell/api/project.ts +++ b/packages/types/src/shell/api/project.ts @@ -3,8 +3,8 @@ import { IPublicEnumTransformStage } from '../enum'; import { IPublicApiSimulatorHost } from './'; import { IPublicModelDocumentModel } from '../model'; -export interface IPublicApiProject< - DocumentModel = IPublicModelDocumentModel +export interface IBaseApiProject< + DocumentModel > { /** @@ -133,3 +133,5 @@ export interface IPublicApiProject< */ setI18n(value: object): void; } + +export interface IPublicApiProject extends IBaseApiProject<IPublicModelDocumentModel> {} \ No newline at end of file From 9597b1c3768699c7de90359156e713b2bf474a31 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 15 Mar 2023 10:44:16 +0800 Subject: [PATCH 049/469] feat: material spec add ignoreDefaultValue field to component property description --- docs/docs/specs/material-spec.md | 1 + .../src/components/settings/settings-pane.tsx | 13 +++++++++++++ packages/types/src/shell/type/field-extra-props.ts | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/docs/docs/specs/material-spec.md b/docs/docs/specs/material-spec.md index 8b79284304..c766c68347 100644 --- a/docs/docs/specs/material-spec.md +++ b/docs/docs/specs/material-spec.md @@ -834,6 +834,7 @@ props 数组下对象字段描述: | defaultValue | 默认值 | Any(视字段类型而定) | type = 'field' 生效 | | supportVariable | 是否支持配置变量 | Boolean | type = 'field' 生效 | | condition | 配置当前 prop 是否展示 | (target: IPublicModelSettingField) => boolean; | - | +| ignoreDefaultValue | 配置当前 prop 是否忽略默认值处理逻辑,如果返回值是 true 引擎不会处理默认值 | (target: IPublicModelSettingField) => boolean; | - | | setter | 单个控件 (setter) 描述,搭建基础协议组件的描述对象,支持 JSExpression / JSFunction / JSSlot | `String\|Object\|Function` | type = 'field' 生效 | | extraProps | 其他配置属性(不做流通要求) | Object | 其他配置 | | extraProps.getValue | setter 渲染时被调用,setter 会根据该函数的返回值设置 setter 当前值 | Function | (target: IPublicModelSettingField, value: any) => any; | diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index 6e256be5cc..5390092413 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -88,6 +88,18 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView return true; } + get ignoreDefaultValue(): boolean { + const { extraProps } = this.field; + const { ignoreDefaultValue } = extraProps; + try { + return typeof ignoreDefaultValue === 'function' ? ignoreDefaultValue(this.field.internalToShell()) : false; + } catch (error) { + console.error('exception when ignoreDefaultValue is excuted', error); + } + + return false; + } + get setterInfo(): { setterProps: any; initialValue: any; @@ -171,6 +183,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView const { initialValue } = this.setterInfo; if (this.state?.fromOnChange || !isInitialValueNotEmpty(initialValue) || + this.ignoreDefaultValue || this.value !== undefined ) { return; diff --git a/packages/types/src/shell/type/field-extra-props.ts b/packages/types/src/shell/type/field-extra-props.ts index 4827571dd8..bfaff1a468 100644 --- a/packages/types/src/shell/type/field-extra-props.ts +++ b/packages/types/src/shell/type/field-extra-props.ts @@ -32,6 +32,12 @@ export interface IPublicTypeFieldExtraProps { */ condition?: (target: IPublicModelSettingField) => boolean; + /** + * 配置当前 prop 是否忽略默认值处理逻辑,如果返回值是 true 引擎不会处理默认值 + * @returns boolean + */ + ignoreDefaultValue?: (target: IPublicModelSettingField) => boolean; + /** * autorun when something change */ From 0181a8ad335a899f200f8eda68b956e07d9c35e6 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 10 Mar 2023 11:43:14 +0800 Subject: [PATCH 050/469] chore(release): publish 1.1.3 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 10 +++++----- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 67 insertions(+), 67 deletions(-) diff --git a/lerna.json b/lerna.json index 8ca861e34c..b1ce00bbf5 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.2", + "version": "1.1.3", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 663e5d91c4..ec63d191c5 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.2", + "version": "1.1.3", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index a3e799761a..87022ad09b 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.1.2", + "version": "1.1.3", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 3477ba1d5c..d799bb68ba 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.1.2", + "version": "1.1.3", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -18,10 +18,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 6edbe7ac02..768b80ffd4 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.2", + "version": "1.1.3", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-editor-skeleton": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-editor-skeleton": "1.1.3", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.2", - "@alilc/lowcode-plugin-outline-pane": "1.1.2", - "@alilc/lowcode-shell": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", - "@alilc/lowcode-workspace": "1.1.2", + "@alilc/lowcode-plugin-designer": "1.1.3", + "@alilc/lowcode-plugin-outline-pane": "1.1.3", + "@alilc/lowcode-shell": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-workspace": "1.1.3", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 92f19ca676..71ea2b4c0b 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.2", + "version": "1.1.3", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index fd0a246a68..ca426b6ebc 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.1.2", + "version": "1.1.3", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 5a9147a8d2..ff05813c4f 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.1.2", + "version": "1.1.3", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,10 +13,10 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index d6270e1f82..50209be4ed 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.1.2", + "version": "1.1.3", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-renderer-core": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 2ff493c2eb..e5b08717da 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.1.2", + "version": "1.1.3", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-rax-renderer": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-rax-renderer": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 7ac9336479..b897eea682 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.1.2", + "version": "1.1.3", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.1.2" + "@alilc/lowcode-renderer-core": "1.1.3" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 7c5868f3cd..49c991f2ac 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.1.2", + "version": "1.1.3", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-react-renderer": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-react-renderer": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index deb30be11e..aa1c7d2046 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.1.2", + "version": "1.1.3", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index a475a05bf3..7608df5f5d 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.2", + "version": "1.1.3", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,12 +15,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-editor-skeleton": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", - "@alilc/lowcode-workspace": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-editor-skeleton": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-workspace": "1.1.3", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index d36e7fb210..351c0311d2 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.2", + "version": "1.1.3", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 7ed3787a75..4f391d23c4 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.2", + "version": "1.1.3", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.2", + "@alilc/lowcode-types": "1.1.3", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 4bd99eaf9a..ef80c7d671 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.2", + "version": "1.1.3", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-editor-skeleton": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-editor-skeleton": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 64e70930534f57e95bd29c6e3d9c7035b271b14a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Thu, 2 Mar 2023 10:38:31 +0800 Subject: [PATCH 051/469] feat: add file name as the third argument which passed to module post processor --- .eslintrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 09d3792a9b..6c072c3262 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -54,4 +54,4 @@ module.exports = { ], 'no-unused-vars': ['error', { "destructuredArrayIgnorePattern": "^_" }] }, -}; \ No newline at end of file +}; From ffaf58b5b56138b537ac54ca02b0e8e70724d56e Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 16 Mar 2023 11:11:51 +0800 Subject: [PATCH 052/469] refactor: rename internalToShell to internalToShellField --- .../designer/src/designer/setting/setting-field.ts | 6 +++--- .../src/designer/setting/setting-prop-entry.ts | 12 ++++++------ .../src/components/settings/settings-pane.tsx | 14 +++++++------- packages/shell/src/model/setting-field.ts | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/designer/src/designer/setting/setting-field.ts b/packages/designer/src/designer/setting/setting-field.ts index 36a30eb1cb..7e91f02ce0 100644 --- a/packages/designer/src/designer/setting/setting-field.ts +++ b/packages/designer/src/designer/setting/setting-field.ts @@ -73,7 +73,7 @@ INode onEffect(action: () => void): IPublicTypeDisposable; - internalToShell(): IPublicModelSettingField; + internalToShellField(): IPublicModelSettingField; } export class SettingField extends SettingPropEntry implements ISettingField { @@ -143,7 +143,7 @@ export class SettingField extends SettingPropEntry implements ISettingField { } if (isDynamicSetter(this._setter)) { return untracked(() => { - const shellThis = this.internalToShell(); + const shellThis = this.internalToShellField(); return (this._setter as IPublicTypeDynamicSetter)?.call(shellThis, shellThis!); }); } @@ -296,7 +296,7 @@ export class SettingField extends SettingPropEntry implements ISettingField { } - internalToShell() { + internalToShellField() { return this.designer!.shellModelFactory.createSettingField(this); } } diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts index e2f1be615c..c061c4c8eb 100644 --- a/packages/designer/src/designer/setting/setting-prop-entry.ts +++ b/packages/designer/src/designer/setting/setting-prop-entry.ts @@ -35,7 +35,7 @@ export interface ISettingPropEntry extends ISettingEntry { setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: IPublicTypeSetValueOptions): void; - internalToShell(): IPublicModelSettingField; + internalToShellField(): IPublicModelSettingField; } export class SettingPropEntry implements ISettingPropEntry { @@ -157,7 +157,7 @@ export class SettingPropEntry implements ISettingPropEntry { if (this.type !== 'field') { const { getValue } = this.extraProps; return getValue - ? getValue(this.internalToShell()!, undefined) === undefined + ? getValue(this.internalToShellField()!, undefined) === undefined ? 0 : 1 : 0; @@ -196,7 +196,7 @@ export class SettingPropEntry implements ISettingPropEntry { } const { getValue } = this.extraProps; try { - return getValue ? getValue(this.internalToShell()!, val) : val; + return getValue ? getValue(this.internalToShellField()!, val) : val; } catch (e) { console.warn(e); return val; @@ -215,7 +215,7 @@ export class SettingPropEntry implements ISettingPropEntry { const { setValue } = this.extraProps; if (setValue && !extraOptions?.disableMutator) { try { - setValue(this.internalToShell()!, val); + setValue(this.internalToShellField()!, val); } catch (e) { /* istanbul ignore next */ console.warn(e); @@ -238,7 +238,7 @@ export class SettingPropEntry implements ISettingPropEntry { const { setValue } = this.extraProps; if (setValue) { try { - setValue(this.internalToShell()!, undefined); + setValue(this.internalToShellField()!, undefined); } catch (e) { /* istanbul ignore next */ console.warn(e); @@ -394,7 +394,7 @@ export class SettingPropEntry implements ISettingPropEntry { return v; } - internalToShell(): IPublicModelSettingField { + internalToShellField(): IPublicModelSettingField { return this.designer!.shellModelFactory.createSettingField(this);; } } diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index 5390092413..0a70c36c97 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -80,7 +80,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView const { extraProps } = this.field; const { condition } = extraProps; try { - return typeof condition === 'function' ? condition(this.field.internalToShell()) !== false : true; + return typeof condition === 'function' ? condition(this.field.internalToShellField()) !== false : true; } catch (error) { console.error('exception when condition (hidden) is excuted', error); } @@ -123,7 +123,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView if (setter.props) { setterProps = setter.props; if (typeof setterProps === 'function') { - setterProps = setterProps(this.field.internalToShell()); + setterProps = setterProps(this.field.internalToShellField()); } } if (setter.initialValue != null) { @@ -190,7 +190,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView } // 当前 field 没有 value 值时,将 initialValue 写入 field // 之所以用 initialValue,而不是 defaultValue 是为了保持跟 props.onInitial 的逻辑一致 - const _initialValue = typeof initialValue === 'function' ? initialValue(this.field.internalToShell()) : initialValue; + const _initialValue = typeof initialValue === 'function' ? initialValue(this.field.internalToShellField()) : initialValue; this.field.setValue(_initialValue); } @@ -238,9 +238,9 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView forceInline: extraProps.forceInline, key: field.id, // === injection - prop: field.internalToShell(), // for compatible vision + prop: field.internalToShellField(), // for compatible vision selected: field.top?.getNode()?.internalToShellNode(), - field: field.internalToShell(), + field: field.internalToShellField(), // === IO value, // reaction point initialValue, @@ -257,7 +257,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView if (initialValue == null) { return; } - const value = typeof initialValue === 'function' ? initialValue(field.internalToShell()) : initialValue; + const value = typeof initialValue === 'function' ? initialValue(field.internalToShellField()) : initialValue; this.setState({ // eslint-disable-next-line react/no-unused-state value, @@ -316,7 +316,7 @@ class SettingGroupView extends Component<SettingGroupViewProps> { const { field } = this.props; const { extraProps } = field; const { condition, display } = extraProps; - const visible = field.isSingle && typeof condition === 'function' ? condition(field.internalToShell()) !== false : true; + const visible = field.isSingle && typeof condition === 'function' ? condition(field.internalToShellField()) !== false : true; if (!visible) { return null; diff --git a/packages/shell/src/model/setting-field.ts b/packages/shell/src/model/setting-field.ts index 8cb6341849..ffc97ccc8f 100644 --- a/packages/shell/src/model/setting-field.ts +++ b/packages/shell/src/model/setting-field.ts @@ -143,7 +143,7 @@ export class SettingField implements IPublicModelSettingField { if (isCustomView(item)) { return item; } - return item.internalToShell(); + return item.internalToShellField(); }); } From 598f9e90fe5275bef1a0d81600a3b128d4abc351 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 16 Mar 2023 11:19:56 +0800 Subject: [PATCH 053/469] chore(docs): publish docs 1.0.21 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index c72e1804ef..e2ffbd0359 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.20", + "version": "1.0.21", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From ba6bdda6a236ba499ce143dff296714a78a28361 Mon Sep 17 00:00:00 2001 From: BARM <ccz_work@189.cn> Date: Wed, 15 Mar 2023 16:44:51 +0800 Subject: [PATCH 054/469] update pluginWidget.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dock的使用需要在props里面定义icon属性和onClick事件 --- docs/docs/guide/expand/editor/pluginWidget.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/docs/docs/guide/expand/editor/pluginWidget.md b/docs/docs/guide/expand/editor/pluginWidget.md index 7efaffcf03..06125575f6 100644 --- a/docs/docs/guide/expand/editor/pluginWidget.md +++ b/docs/docs/guide/expand/editor/pluginWidget.md @@ -172,19 +172,16 @@ skeleton.add({ area: 'leftArea', type: 'Dock', name: 'opener', - content: Opener, // Widget 组件实例 - contentProps: { // Widget 插件 props - xxx: '1', - }, props: { + icon: Icon, // Icon 组件实例 align: 'bottom', - }, - onClick: function () { - // 打开外部链接 - window.open('https://lowcode-engine.cn'); - // 显示 widget - skeleton.showWidget('xxx'); - }, + onClick: function () { + // 打开外部链接 + window.open('https://lowcode-engine.cn'); + // 显示 widget + skeleton.showWidget('xxx'); + } + } }); ``` From fb3aea4f27ba99a14183c37ee7961d55fa9149e7 Mon Sep 17 00:00:00 2001 From: Qi <Cossey11111@163.com> Date: Thu, 16 Mar 2023 15:18:06 +0800 Subject: [PATCH 055/469] fix: fiberkey compatibility --- packages/react-simulator-renderer/src/renderer.ts | 4 ++-- .../src/utils/react-find-dom-nodes.ts | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index 7661500280..1832ca99d5 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -4,7 +4,7 @@ import { host } from './host'; import SimulatorRendererView from './renderer-view'; import { computed, observable as obx, untracked, makeObservable, configure } from 'mobx'; import { getClientRects } from './utils/get-client-rects'; -import { reactFindDOMNodes, FIBER_KEY } from './utils/react-find-dom-nodes'; +import { reactFindDOMNodes, getReactInternalFiber } from './utils/react-find-dom-nodes'; import { Asset, isElement, @@ -565,7 +565,7 @@ function getClosestNodeInstance( if (isElement(el)) { el = cacheReactKey(el); } else { - return getNodeInstance(el[FIBER_KEY], specId); + return getNodeInstance(getReactInternalFiber(el), specId); } } while (el) { diff --git a/packages/react-simulator-renderer/src/utils/react-find-dom-nodes.ts b/packages/react-simulator-renderer/src/utils/react-find-dom-nodes.ts index eb1fb41d50..d7af90346f 100644 --- a/packages/react-simulator-renderer/src/utils/react-find-dom-nodes.ts +++ b/packages/react-simulator-renderer/src/utils/react-find-dom-nodes.ts @@ -3,7 +3,9 @@ import { findDOMNode } from 'react-dom'; import { isElement } from '@alilc/lowcode-utils'; import { isDOMNode } from './is-dom-node'; -export const FIBER_KEY = '_reactInternalFiber'; +export const getReactInternalFiber = (el: any) => { + return el._reactInternals || el._reactInternalFiber; +}; function elementsFromFiber(fiber: any, elements: Array<Element | Text>) { if (fiber) { @@ -28,7 +30,7 @@ export function reactFindDOMNodes(elem: ReactInstance | null): Array<Element | T return [elem]; } const elements: Array<Element | Text> = []; - const fiberNode = (elem as any)[FIBER_KEY]; + const fiberNode = getReactInternalFiber(elem); elementsFromFiber(fiberNode?.child, elements); if (elements.length > 0) return elements; try { From f6537f536f965ebffb2af50c99d1147f7276373d Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 17 Mar 2023 15:02:14 +0800 Subject: [PATCH 056/469] feat: lowCode components support project schema --- .../src/builtin-simulator/renderer.ts | 4 +- .../rax-simulator-renderer/src/renderer.ts | 68 +++++++++++++------ .../react-simulator-renderer/src/renderer.ts | 35 ++++++---- packages/types/src/shell/type/package.ts | 4 +- .../types/src/shell/type/project-schema.ts | 4 +- packages/utils/src/build-components.ts | 18 +++-- packages/utils/src/check-types/index.ts | 5 +- .../src/check-types/is-component-schema.ts | 8 +++ .../check-types/is-lowcode-component-type.ts | 4 +- .../check-types/is-lowcode-project-schema.ts | 6 ++ .../src/check-types/is-project-schema.ts | 4 +- 11 files changed, 111 insertions(+), 49 deletions(-) create mode 100644 packages/utils/src/check-types/is-component-schema.ts create mode 100644 packages/utils/src/check-types/is-lowcode-project-schema.ts diff --git a/packages/designer/src/builtin-simulator/renderer.ts b/packages/designer/src/builtin-simulator/renderer.ts index 43a1532229..bd94f24f65 100644 --- a/packages/designer/src/builtin-simulator/renderer.ts +++ b/packages/designer/src/builtin-simulator/renderer.ts @@ -1,12 +1,12 @@ import { Component } from '../simulator'; -import { IPublicTypeNodeSchema, IPublicTypeComponentInstance, IPublicTypeNodeInstance, Asset } from '@alilc/lowcode-types'; +import { IPublicTypeComponentInstance, IPublicTypeNodeInstance, Asset, IPublicTypeComponentSchema, IPublicTypeProjectSchema, IPublicTypeLowCodeComponent } from '@alilc/lowcode-types'; export interface BuiltinSimulatorRenderer { readonly isSimulatorRenderer: true; autoRepaintNode?: boolean; components: Record<string, Component>; rerender: () => void; - createComponent(schema: IPublicTypeNodeSchema): Component | null; + createComponent(schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>): Component | null; getComponent(componentName: string): Component; getClosestNodeInstance( from: IPublicTypeComponentInstance, diff --git a/packages/rax-simulator-renderer/src/renderer.ts b/packages/rax-simulator-renderer/src/renderer.ts index 2dca4506ea..64ec2d2c69 100644 --- a/packages/rax-simulator-renderer/src/renderer.ts +++ b/packages/rax-simulator-renderer/src/renderer.ts @@ -1,6 +1,6 @@ -import { BuiltinSimulatorRenderer, Component, DocumentModel, Node } from '@alilc/lowcode-designer'; -import { IPublicTypeComponentSchema, IPublicTypeNodeSchema, IPublicTypeNpmInfo, IPublicEnumTransformStage, IPublicTypeNodeInstance } from '@alilc/lowcode-types'; -import { Asset, compatibleLegaoSchema, cursor, isElement, isESModule, isPlainObject, isReactComponent, setNativeSelection } from '@alilc/lowcode-utils'; +import { BuiltinSimulatorRenderer, Component, IBaseNode, IDocumentModel } from '@alilc/lowcode-designer'; +import { IPublicTypeComponentSchema, IPublicTypeNodeSchema, IPublicTypeNpmInfo, IPublicEnumTransformStage, IPublicTypeNodeInstance, IPublicTypeProjectSchema } from '@alilc/lowcode-types'; +import { Asset, compatibleLegaoSchema, cursor, isElement, isESModule, isLowcodeProjectSchema, isComponentSchema, isPlainObject, isReactComponent, setNativeSelection } from '@alilc/lowcode-utils'; import LowCodeRenderer from '@alilc/lowcode-rax-renderer'; import { computed, observable as obx, makeObservable, configure } from 'mobx'; import DriverUniversal from 'driver-universal'; @@ -47,15 +47,23 @@ const builtinComponents = { function buildComponents( libraryMap: LibraryMap, componentsMap: { [componentName: string]: IPublicTypeNpmInfo | ComponentType<any> | IPublicTypeComponentSchema }, - createComponent: (schema: IPublicTypeComponentSchema) => Component | null, + createComponent: (schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>) => Component | null, ) { const components: any = { ...builtinComponents, }; Object.keys(componentsMap).forEach((componentName) => { let component = componentsMap[componentName]; - if (component && (component as IPublicTypeComponentSchema).componentName === 'Component') { - components[componentName] = createComponent(component as IPublicTypeComponentSchema); + if (component && (isLowcodeProjectSchema(component) || isComponentSchema(component))) { + if (isComponentSchema(component)) { + components[componentName] = createComponent({ + version: '', + componentsMap: [], + componentsTree: [component], + }); + } else { + components[componentName] = createComponent(component); + } } else if (isReactComponent(component)) { components[componentName] = component; } else { @@ -110,7 +118,7 @@ export class DocumentInstance { return this.document.export(IPublicEnumTransformStage.Render); } - constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) { + constructor(readonly container: SimulatorRendererContainer, readonly document: IDocumentModel) { makeObservable(this); } @@ -221,7 +229,7 @@ export class DocumentInstance { return this.instancesMap.get(id) || null; } - getNode(id: string): Node<IPublicTypeNodeSchema> | null { + getNode(id: string): IBaseNode<IPublicTypeNodeSchema> | null { return this.document.getNode(id); } } @@ -256,6 +264,8 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { // sync designMode this._designMode = host.designMode; + this._locale = host.locale; + // sync requestHandlersMap this._requestHandlersMap = host.requestHandlersMap; @@ -343,11 +353,11 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { // TODO: remove this.createComponent this._components = buildComponents(this._libraryMap, this._componentsMap, this.createComponent.bind(this)); } - @obx.ref private _components: any = {}; - @computed get components(): object { + @obx.ref private _components: Record<string, React.FC | React.ComponentClass> | null = {}; + @computed get components(): Record<string, React.FC | React.ComponentClass> { // 根据 device 选择不同组件,进行响应式 // 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl - return this._components; + return this._components || {}; } // context from: utils、constants、history、location、match @obx.ref private _appContext = {}; @@ -362,6 +372,10 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { @computed get device() { return this._device; } + @obx.ref private _locale: string | undefined = undefined; + @computed get locale() { + return this._locale; + } @obx.ref private _requestHandlersMap = null; @computed get requestHandlersMap(): any { return this._requestHandlersMap; @@ -378,12 +392,15 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { return loader.load(asset); } + async loadAsyncLibrary(asyncLibraryMap: Record<string, any>) { + } + getComponent(componentName: string) { const paths = componentName.split('.'); const subs: string[] = []; while (true) { - const component = this._components[componentName]; + const component = this._components?.[componentName]; if (component) { return getSubComponent(component, subs); } @@ -416,7 +433,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { // if (instance && SYMBOL_VNID in instance) { // const docId = (instance.props as any).schema.docId; return { - docId: instance.props._leaf.document.id, + docId: instance.props._leaf.document?.id || '', nodeId: instance.props._leaf.getId(), instance, node: instance.props._leaf, @@ -497,17 +514,26 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { this.currentDocumentInstance?.refresh(); } - createComponent(schema: IPublicTypeNodeSchema): Component | null { - const _schema: any = { - ...compatibleLegaoSchema(schema), + stopAutoRepaintNode() { + } + + enableAutoRepaintNode() { + } + + createComponent(schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>): Component | null { + const _schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema> = { + ...schema, + componentsTree: schema.componentsTree.map(compatibleLegaoSchema), }; - if (schema.componentName === 'Component' && (schema as IPublicTypeComponentSchema).css) { + const componentsTreeSchema = _schema.componentsTree[0]; + + if (componentsTreeSchema.componentName === 'Component' && componentsTreeSchema.css) { const doc = window.document; const s = doc.createElement('style'); s.setAttribute('type', 'text/css'); - s.setAttribute('id', `Component-${schema.id || ''}`); - s.appendChild(doc.createTextNode((schema as IPublicTypeComponentSchema).css || '')); + s.setAttribute('id', `Component-${componentsTreeSchema.id || ''}`); + s.appendChild(doc.createTextNode(componentsTreeSchema.css || '')); doc.getElementsByTagName('head')[0].appendChild(s); } @@ -520,9 +546,11 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { // @ts-ignore return createElement(LowCodeRenderer, { ...extraProps, - schema: _schema, + schema: componentsTreeSchema, components, designMode: '', + locale: renderer.locale, + messages: _schema.i18n || {}, device: renderer.device, appHelper: renderer.context, rendererName: 'LowCodeRenderer', diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index 1832ca99d5..dbb24a5bb5 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -17,9 +17,9 @@ import { AssetLoader, getProjectUtils, } from '@alilc/lowcode-utils'; -import { IPublicTypeComponentSchema, IPublicEnumTransformStage, IPublicTypeNodeSchema, IPublicTypeNodeInstance } from '@alilc/lowcode-types'; +import { IPublicTypeComponentSchema, IPublicEnumTransformStage, IPublicTypeNodeInstance, IPublicTypeProjectSchema } from '@alilc/lowcode-types'; // just use types -import { BuiltinSimulatorRenderer, Component, DocumentModel, Node } from '@alilc/lowcode-designer'; +import { BuiltinSimulatorRenderer, Component, IDocumentModel, INode } from '@alilc/lowcode-designer'; import LowCodeRenderer from '@alilc/lowcode-react-renderer'; import { createMemoryHistory, MemoryHistory } from 'history'; import Slot from './builtin-components/slot'; @@ -94,7 +94,7 @@ export class DocumentInstance { return this.document.id; } - constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) { + constructor(readonly container: SimulatorRendererContainer, readonly document: IDocumentModel) { makeObservable(this); } @@ -173,7 +173,7 @@ export class DocumentInstance { mountContext() { } - getNode(id: string): Node | null { + getNode(id: string): INode | null { return this.document.getNode(id); } @@ -207,12 +207,12 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { private _libraryMap: { [key: string]: string } = {}; - private _components: any = {}; + private _components: Record<string, React.FC | React.ComponentClass> | null = {}; - get components(): object { + get components(): Record<string, React.FC | React.ComponentClass> { // 根据 device 选择不同组件,进行响应式 // 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl - return this._components; + return this._components || {}; } // context from: utils、constants、history、location、match @obx.ref private _appContext: any = {}; @@ -388,7 +388,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { const subs: string[] = []; while (true) { - const component = this._components[componentName]; + const component = this._components?.[componentName]; if (component) { return getSubComponent(component, subs); } @@ -430,17 +430,20 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { cursor.release(); } - createComponent(schema: IPublicTypeNodeSchema): Component | null { - const _schema: any = { - ...compatibleLegaoSchema(schema), + createComponent(schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>): Component | null { + const _schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema> = { + ...schema, + componentsTree: schema.componentsTree.map(compatibleLegaoSchema), }; - if (schema.componentName === 'Component' && (schema as IPublicTypeComponentSchema).css) { + const componentsTreeSchema = _schema.componentsTree[0]; + + if (componentsTreeSchema.componentName === 'Component' && componentsTreeSchema.css) { const doc = window.document; const s = doc.createElement('style'); s.setAttribute('type', 'text/css'); - s.setAttribute('id', `Component-${schema.id || ''}`); - s.appendChild(doc.createTextNode((schema as IPublicTypeComponentSchema).css || '')); + s.setAttribute('id', `Component-${componentsTreeSchema.id || ''}`); + s.appendChild(doc.createTextNode(componentsTreeSchema.css || '')); doc.getElementsByTagName('head')[0].appendChild(s); } @@ -452,9 +455,11 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { return createElement(LowCodeRenderer, { ...extraProps, // 防止覆盖下面内置属性 // 使用 _schema 为了使低代码组件在页面设计中使用变量,同 react 组件使用效果一致 - schema: _schema, + schema: componentsTreeSchema, components: renderer.components, designMode: '', + locale: renderer.locale, + messages: _schema.i18n || {}, device: renderer.device, appHelper: renderer.context, rendererName: 'LowCodeRenderer', diff --git a/packages/types/src/shell/type/package.ts b/packages/types/src/shell/type/package.ts index 6df8fdd0b1..b33fa3f94a 100644 --- a/packages/types/src/shell/type/package.ts +++ b/packages/types/src/shell/type/package.ts @@ -1,5 +1,5 @@ import { EitherOr } from '../../utils'; -import { IPublicTypeComponentSchema } from './'; +import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from './'; /** * 定义组件大包及 external 资源的信息 @@ -51,5 +51,5 @@ export type IPublicTypePackage = EitherOr<{ /** * 低代码组件 schema 内容 */ - schema?: IPublicTypeComponentSchema; + schema?: IPublicTypeProjectSchema<IPublicTypeComponentSchema>; }, 'package', 'id'>; diff --git a/packages/types/src/shell/type/project-schema.ts b/packages/types/src/shell/type/project-schema.ts index 6472085318..66a5aaa8a2 100644 --- a/packages/types/src/shell/type/project-schema.ts +++ b/packages/types/src/shell/type/project-schema.ts @@ -19,7 +19,7 @@ export type IPublicTypeUtilsMap = IPublicTypeUtilItem[]; * 应用描述 */ -export interface IPublicTypeProjectSchema { +export interface IPublicTypeProjectSchema<T = IPublicTypeRootSchema> { id?: string; /** * 当前应用协议版本号 @@ -34,7 +34,7 @@ export interface IPublicTypeProjectSchema { * 低代码业务组件树描述 * 是长度固定为 1 的数组,即数组内仅包含根容器的描述(低代码业务组件容器类型) */ - componentsTree: IPublicTypeRootSchema[]; + componentsTree: T[]; /** * 国际化语料 */ diff --git a/packages/utils/src/build-components.ts b/packages/utils/src/build-components.ts index af4c64699f..e3b1797df7 100644 --- a/packages/utils/src/build-components.ts +++ b/packages/utils/src/build-components.ts @@ -1,8 +1,10 @@ import { ComponentType, forwardRef, createElement, FunctionComponent } from 'react'; -import { IPublicTypeNpmInfo, IPublicTypeComponentSchema } from '@alilc/lowcode-types'; +import { IPublicTypeNpmInfo, IPublicTypeComponentSchema, IPublicTypeProjectSchema } from '@alilc/lowcode-types'; import { isESModule } from './is-es-module'; import { isReactComponent, acceptsRef, wrapReactClass } from './is-react'; import { isObject } from './is-object'; +import { isLowcodeProjectSchema } from './check-types'; +import { isComponentSchema } from './check-types/is-component-schema'; type Component = ComponentType<any> | object; interface LibraryMap { @@ -95,12 +97,20 @@ function isMixinComponent(components: any) { export function buildComponents(libraryMap: LibraryMap, componentsMap: { [componentName: string]: IPublicTypeNpmInfo | ComponentType<any> | IPublicTypeComponentSchema }, - createComponent: (schema: IPublicTypeComponentSchema) => Component | null) { + createComponent: (schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>) => Component | null) { const components: any = {}; Object.keys(componentsMap).forEach((componentName) => { let component = componentsMap[componentName]; - if (component && (component as IPublicTypeComponentSchema).componentName === 'Component') { - components[componentName] = createComponent(component as IPublicTypeComponentSchema); + if (component && (isLowcodeProjectSchema(component) || isComponentSchema(component))) { + if (isComponentSchema(component)) { + components[componentName] = createComponent({ + version: '', + componentsMap: [], + componentsTree: [component], + }); + } else { + components[componentName] = createComponent(component); + } } else if (isReactComponent(component)) { if (!acceptsRef(component)) { component = wrapReactClass(component as FunctionComponent); diff --git a/packages/utils/src/check-types/index.ts b/packages/utils/src/check-types/index.ts index 1e38350217..3155926ef2 100644 --- a/packages/utils/src/check-types/index.ts +++ b/packages/utils/src/check-types/index.ts @@ -20,4 +20,7 @@ export * from './is-drag-any-object'; export * from './is-location-children-detail'; export * from './is-node'; export * from './is-location-data'; -export * from './is-setting-field'; \ No newline at end of file +export * from './is-setting-field'; +export * from './is-lowcode-component-type'; +export * from './is-lowcode-project-schema'; +export * from './is-component-schema'; \ No newline at end of file diff --git a/packages/utils/src/check-types/is-component-schema.ts b/packages/utils/src/check-types/is-component-schema.ts new file mode 100644 index 0000000000..508d153b93 --- /dev/null +++ b/packages/utils/src/check-types/is-component-schema.ts @@ -0,0 +1,8 @@ +import { IPublicTypeComponentSchema } from "@alilc/lowcode-types"; + +export function isComponentSchema(schema: any): schema is IPublicTypeComponentSchema { + if (typeof schema === 'object') { + return schema.componentName === 'Component'; + } + return false +} diff --git a/packages/utils/src/check-types/is-lowcode-component-type.ts b/packages/utils/src/check-types/is-lowcode-component-type.ts index 22ab539b4d..ce19c23e87 100644 --- a/packages/utils/src/check-types/is-lowcode-component-type.ts +++ b/packages/utils/src/check-types/is-lowcode-component-type.ts @@ -1,7 +1,7 @@ import { isProCodeComponentType } from './is-procode-component-type'; -import { IPublicTypeComponentMap } from '@alilc/lowcode-types'; +import { IPublicTypeComponentMap, IPublicTypeLowCodeComponent } from '@alilc/lowcode-types'; -export function isLowCodeComponentType(desc: IPublicTypeComponentMap): boolean { +export function isLowCodeComponentType(desc: IPublicTypeComponentMap): desc is IPublicTypeLowCodeComponent { return !isProCodeComponentType(desc); } diff --git a/packages/utils/src/check-types/is-lowcode-project-schema.ts b/packages/utils/src/check-types/is-lowcode-project-schema.ts new file mode 100644 index 0000000000..0fffaea2fc --- /dev/null +++ b/packages/utils/src/check-types/is-lowcode-project-schema.ts @@ -0,0 +1,6 @@ +import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from "@alilc/lowcode-types"; +import { isComponentSchema } from "./is-component-schema"; + +export function isLowcodeProjectSchema(data: any): data is IPublicTypeProjectSchema<IPublicTypeComponentSchema> { + return data && data.componentsTree && data.componentsTree.length && isComponentSchema(data.componentsTree[0]); +} diff --git a/packages/utils/src/check-types/is-project-schema.ts b/packages/utils/src/check-types/is-project-schema.ts index aa1961072e..b228d481e0 100644 --- a/packages/utils/src/check-types/is-project-schema.ts +++ b/packages/utils/src/check-types/is-project-schema.ts @@ -1,3 +1,5 @@ -export function isProjectSchema(data: any): boolean { +import { IPublicTypeProjectSchema } from "@alilc/lowcode-types"; + +export function isProjectSchema(data: any): data is IPublicTypeProjectSchema { return data && data.componentsTree; } From 12a22de1698efc4bdde80de5e5e65d20bc62c8f7 Mon Sep 17 00:00:00 2001 From: zzzhrookie <zzh7498624@163.com> Date: Mon, 20 Mar 2023 09:24:08 +0800 Subject: [PATCH 057/469] =?UTF-8?q?fix:=20document-model=20=E6=96=87?= =?UTF-8?q?=E6=A1=A3=20isDetectingNode=20=E6=96=87=E6=A1=88=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/api/model/document-model.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/api/model/document-model.md b/docs/docs/api/model/document-model.md index 4da765d309..b609f00504 100644 --- a/docs/docs/api/model/document-model.md +++ b/docs/docs/api/model/document-model.md @@ -220,7 +220,7 @@ checkNesting( **@since v1.0.16** ### isDetectingNode -检查拖拽放置的目标节点是否可以放置该拖拽对象 +判断是否当前节点处于被探测状态 ```typescript /** From 6d4ca29466640164082274ea791ae2055136c3f9 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 20 Mar 2023 14:48:59 +0800 Subject: [PATCH 058/469] fix: fix workspace api ts defined --- .eslintrc.js | 2 +- .../bem-tools/border-selecting.tsx | 14 ++-- .../designer/src/builtin-simulator/host.ts | 65 +++++++------- .../builtin-simulator/node-selector/index.tsx | 30 ++++--- packages/designer/src/designer/designer.ts | 22 +++-- packages/designer/src/designer/dragon.ts | 14 ++-- .../designer/src/designer/offset-observer.ts | 14 ++-- .../designer/src/document/document-model.ts | 8 +- packages/designer/src/plugin/plugin-types.ts | 4 +- packages/designer/src/project/project.ts | 8 ++ packages/designer/src/simulator.ts | 7 +- packages/editor-core/src/hotkey.ts | 4 +- .../src/widgets/tip/tip-container.tsx | 5 +- packages/shell/src/api/plugins.ts | 8 +- packages/shell/src/api/workspace.ts | 6 +- packages/shell/src/model/resource.ts | 6 +- packages/shell/src/model/window.ts | 6 +- packages/types/src/shell/api/workspace.ts | 7 +- packages/types/src/shell/model/drag-object.ts | 9 +- packages/types/src/shell/model/resource.ts | 10 ++- packages/types/src/shell/model/window.ts | 6 +- .../src/shell/type/action-content-object.ts | 6 +- packages/types/src/shell/type/location.ts | 6 +- packages/types/src/shell/type/metadata.ts | 1 + .../types/src/shell/type/resource-list.ts | 9 +- .../check-types/is-action-content-object.ts | 3 +- .../utils/src/check-types/is-location-data.ts | 3 +- packages/utils/src/css-helper.ts | 48 +++++------ packages/utils/src/is-react.ts | 3 +- packages/utils/src/node-helper.ts | 9 +- .../workspace/src/context/base-context.ts | 84 +++++++++++++------ .../workspace/src/context/view-context.ts | 8 +- packages/workspace/src/index.ts | 4 +- packages/workspace/src/resource-type.ts | 10 ++- packages/workspace/src/resource.ts | 36 ++++++-- packages/workspace/src/window.ts | 15 +++- packages/workspace/src/workspace.ts | 67 +++++++++------ 37 files changed, 348 insertions(+), 219 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 6c072c3262..4d573688f5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -52,6 +52,6 @@ module.exports = { 'error', { default: ['signature', 'field', 'constructor', 'method'] } ], - 'no-unused-vars': ['error', { "destructuredArrayIgnorePattern": "^_" }] + '@typescript-eslint/no-unused-vars': ['error'] }, }; diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx index da3c73ae59..75b4a34881 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx @@ -13,9 +13,9 @@ import { observer, computed, Tip, globalContext } from '@alilc/lowcode-editor-co import { createIcon, isReactComponent, isActionContentObject } from '@alilc/lowcode-utils'; import { IPublicTypeActionContentObject } from '@alilc/lowcode-types'; import { BuiltinSimulatorHost } from '../host'; -import { OffsetObserver } from '../../designer'; -import { Node } from '../../document'; +import { INode, OffsetObserver } from '../../designer'; import NodeSelector from '../node-selector'; +import { ISimulatorHost } from '../../simulator'; @observer export class BorderSelectingInstance extends Component<{ @@ -116,8 +116,8 @@ class Toolbar extends Component<{ observed: OffsetObserver }> { } } -function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActionContentObject, key: string, node: Node) { - if (isValidElement(content)) { +function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActionContentObject, key: string, node: INode) { + if (isValidElement<{ key: string; node: INode }>(content)) { return cloneElement(content, { key, node }); } if (isReactComponent(content)) { @@ -130,7 +130,7 @@ function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActio key={key} className="lc-borders-action" onClick={() => { - action && action(node); + action && action(node.internalToShellNode()!); const workspace = globalContext.get('workspace'); const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); const npm = node?.componentMeta?.npm; @@ -153,8 +153,8 @@ function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActio } @observer -export class BorderSelectingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> { - get host(): BuiltinSimulatorHost { +export class BorderSelectingForNode extends Component<{ host: ISimulatorHost; node: INode }> { + get host(): ISimulatorHost { return this.props.host; } diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 6415a1b4c6..b2a41b831a 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -47,26 +47,26 @@ import { getRectTarget, CanvasPoint, Designer, + IDesigner, } from '../designer'; import { parseMetadata } from './utils/parse-metadata'; import { getClosestClickableNode } from './utils/clickable'; import { IPublicTypeComponentMetadata, - IPublicTypeComponentSchema, IPublicTypePackage, IPublicEnumTransitionType, IPublicEnumDragObjectType, - IPublicTypeDragNodeObject, IPublicTypeNodeInstance, IPublicTypeComponentInstance, IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType, IPublicTypeRect, + IPublicModelNode, } from '@alilc/lowcode-types'; import { BuiltinSimulatorRenderer } from './renderer'; import { clipboard } from '../designer/clipboard'; import { LiveEditing } from './live-editing/live-editing'; -import { Project } from '../project'; +import { IProject, Project } from '../project'; import { IScroller } from '../designer/scroller'; import { isElementNode, isDOMNodeVisible } from '../utils/misc'; import { debounce } from 'lodash'; @@ -164,9 +164,9 @@ const defaultRaxEnvironment = [ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProps> { readonly isSimulator = true; - readonly project: Project; + readonly project: IProject; - readonly designer: Designer; + readonly designer: IDesigner; readonly viewport = new Viewport(); @@ -217,7 +217,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp return this.get('requestHandlersMap') || null; } - get thisRequiredInJSE(): any { + get thisRequiredInJSE(): boolean { return engineConfig.get('thisRequiredInJSE') ?? true; } @@ -559,8 +559,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp return; } // FIXME: dirty fix remove label-for fro liveEditing - (downEvent.target as HTMLElement).removeAttribute('for'); - const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element); + downEvent.target?.removeAttribute('for'); + const nodeInst = this.getNodeInstanceFromElement(downEvent.target); const { focusNode } = documentModel; const node = getClosestClickableNode(nodeInst?.node || focusNode, downEvent); // 如果找不到可点击的节点,直接返回 @@ -675,11 +675,11 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp const x = new Event('click'); x.initEvent('click', true); this._iframe?.dispatchEvent(x); - const target = e.target as HTMLElement; + const target = e.target; const customizeIgnoreSelectors = engineConfig.get('customizeIgnoreSelectors'); // TODO: need more elegant solution to ignore click events of components in designer - const defaultIgnoreSelectors: any = [ + const defaultIgnoreSelectors: string[] = [ '.next-input-group', '.next-checkbox-group', '.next-checkbox-wrapper', @@ -741,7 +741,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp } }; const leave = () => { - this.project.currentDocument && detecting.leave(this.project.currentDocument) + this.project.currentDocument && detecting.leave(this.project.currentDocument); }; doc.addEventListener('mouseover', hover, true); @@ -812,7 +812,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp /** * @see ISimulator */ - setSuspense(suspended: boolean) { + setSuspense(/** _suspended: boolean */) { return false; // if (suspended) { // /* @@ -897,7 +897,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp return this.renderer?.getComponent(componentName) || null; } - createComponent(schema: IPublicTypeComponentSchema): Component | null { + createComponent(/** _schema: IPublicTypeComponentSchema */): Component | null { return null; // return this.renderer?.createComponent(schema) || null; } @@ -1018,7 +1018,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp } if (last) { - const r: any = new DOMRect(last.x, last.y, last.r - last.x, last.b - last.y); + const r: IPublicTypeRect = new DOMRect(last.x, last.y, last.r - last.x, last.b - last.y); r.elements = elements; r.computed = _computed; return r; @@ -1186,13 +1186,14 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp */ locate(e: ILocateEvent): any { const { dragObject } = e; - const { nodes } = dragObject as IPublicTypeDragNodeObject; + + const nodes = dragObject?.nodes; const operationalNodes = nodes?.filter((node) => { const onMoveHook = node.componentMeta?.advanced.callbacks?.onMoveHook; const canMove = onMoveHook && typeof onMoveHook === 'function' ? onMoveHook(node.internalToShellNode()) : true; - let parentContainerNode: Node | null = null; + let parentContainerNode: INode | null = null; let parentNode = node.parent; while (parentNode) { @@ -1254,7 +1255,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp }; const locationData = { - target: container as INode, + target: container, detail, source: `simulator${document.id}`, event: e, @@ -1279,12 +1280,12 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp return this.designer.createLocation(locationData); } - let nearRect = null; - let nearIndex = 0; - let nearNode = null; - let nearDistance = null; - let minTop = null; - let maxBottom = null; + let nearRect: IPublicTypeRect | null = null; + let nearIndex: number = 0; + let nearNode: INode | null = null; + let nearDistance: number | null = null; + let minTop: number | null = null; + let maxBottom: number | null = null; for (let i = 0, l = children.size; i < l; i++) { const node = children.get(i)!; @@ -1341,8 +1342,13 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp const vertical = inline || row; // TODO: fix type - const near: any = { - node: nearNode, + const near: { + node: IPublicModelNode; + pos: 'before' | 'after' | 'replace'; + rect?: IPublicTypeRect; + align?: 'V' | 'H'; + } = { + node: nearNode.internalToShellNode()!, pos: 'before', align: vertical ? 'V' : 'H', }; @@ -1465,7 +1471,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp container = container.parent; instance = this.getClosestNodeInstance(dropContainer.instance, container.id)?.instance; dropContainer = { - container: container, + container, instance, }; } else { @@ -1483,12 +1489,12 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp /** * 控制接受 */ - handleAccept({ container, instance }: DropContainer, e: ILocateEvent): boolean { + handleAccept({ container }: DropContainer, e: ILocateEvent): boolean { const { dragObject } = e; const document = this.currentDocument!; const focusNode = document.focusNode; if (isRootNode(container) || container.contains(focusNode)) { - return document.checkNesting(focusNode, dragObject as any); + return document.checkNesting(focusNode!, dragObject as any); } const meta = (container as Node).componentMeta; @@ -1509,15 +1515,12 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp getNearByContainer( { container, instance }: DropContainer, drillDownExcludes: Set<INode>, - e: ILocateEvent, ) { const { children } = container; - const document = this.project.currentDocument!; if (!children || children.isEmpty()) { return null; } - const nearDistance: any = null; const nearBy: any = null; for (let i = 0, l = children.size; i < l; i++) { let child = children.get(i); diff --git a/packages/designer/src/builtin-simulator/node-selector/index.tsx b/packages/designer/src/builtin-simulator/node-selector/index.tsx index 27211f2242..09c8f12622 100644 --- a/packages/designer/src/builtin-simulator/node-selector/index.tsx +++ b/packages/designer/src/builtin-simulator/node-selector/index.tsx @@ -1,19 +1,19 @@ import { Overlay } from '@alifd/next'; -import React from 'react'; +import React, { MouseEvent } from 'react'; import { Title, globalContext } from '@alilc/lowcode-editor-core'; import { canClickNode } from '@alilc/lowcode-utils'; import './index.less'; -import { Node, INode } from '@alilc/lowcode-designer'; +import { INode } from '@alilc/lowcode-designer'; const { Popup } = Overlay; export interface IProps { - node: Node; + node: INode; } export interface IState { - parentNodes: Node[]; + parentNodes: INode[]; } type UnionNode = INode | null; @@ -26,14 +26,18 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState componentDidMount() { const parentNodes = this.getParentNodes(this.props.node); this.setState({ - parentNodes, + parentNodes: parentNodes ?? [], }); } // 获取节点的父级节点(最多获取 5 层) - getParentNodes = (node: Node) => { + getParentNodes = (node: INode) => { const parentNodes: any[] = []; - const { focusNode } = node.document; + const focusNode = node.document?.focusNode; + + if (!focusNode) { + return null; + } if (node.contains(focusNode) || !focusNode.contains(node)) { return parentNodes; @@ -53,12 +57,12 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState return parentNodes; }; - onSelect = (node: Node) => (e: unknown) => { + onSelect = (node: INode) => (event: MouseEvent) => { if (!node) { return; } - const canClick = canClickNode(node, e as MouseEvent); + const canClick = canClickNode(node.internalToShellNode()!, event); if (canClick && typeof node.select === 'function') { node.select(); @@ -76,19 +80,19 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState } }; - onMouseOver = (node: Node) => (_: any, flag = true) => { + onMouseOver = (node: INode) => (_: any, flag = true) => { if (node && typeof node.hover === 'function') { node.hover(flag); } }; - onMouseOut = (node: Node) => (_: any, flag = false) => { + onMouseOut = (node: INode) => (_: any, flag = false) => { if (node && typeof node.hover === 'function') { node.hover(flag); } }; - renderNodes = (/* node: Node */) => { + renderNodes = () => { const nodes = this.state.parentNodes; if (!nodes || nodes.length < 1) { return null; @@ -136,7 +140,7 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState triggerType="hover" offset={[0, 0]} > - <div className="instance-node-selector">{this.renderNodes(node)}</div> + <div className="instance-node-selector">{this.renderNodes()}</div> </Popup> </div> ); diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index a1d05a8dd7..74c1f51b25 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -16,17 +16,15 @@ import { IPublicModelScroller, IPublicTypeLocationData, IPublicEnumTransformStage, - IPublicModelDragon, - IPublicModelDropLocation, IPublicModelLocateEvent, } from '@alilc/lowcode-types'; import { megreAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils'; -import { Project } from '../project'; +import { IProject, Project } from '../project'; import { Node, DocumentModel, insertChildren, INode } from '../document'; import { ComponentMeta, IComponentMeta } from '../component-meta'; import { INodeSelector, Component } from '../simulator'; import { Scroller } from './scroller'; -import { Dragon, IDragon, ILocateEvent } from './dragon'; +import { Dragon, IDragon } from './dragon'; import { ActiveTracker, IActiveTracker } from './active-tracker'; import { Detecting } from './detecting'; import { DropLocation } from './location'; @@ -64,7 +62,11 @@ export interface DesignerProps { export interface IDesigner { readonly shellModelFactory: IShellModelFactory; - get dragon(): IPublicModelDragon; + viewName: string | undefined; + + readonly project: IProject; + + get dragon(): IDragon; get activeTracker(): IActiveTracker; @@ -78,6 +80,10 @@ export interface IDesigner { createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller; + refreshComponentMetasMap(): void; + + createOffsetObserver(nodeInstance: INodeSelector): OffsetObserver | null; + /** * 创建插入位置,考虑放到 dragon 中 */ @@ -92,6 +98,8 @@ export interface IDesigner { generateMetadata?: () => IPublicTypeComponentMetadata | null, ): IComponentMeta; + clearLocation(): void; + createComponentMeta(data: IPublicTypeComponentMetadata): IComponentMeta | null; getComponentMetasMap(): Map<string, IComponentMeta>; @@ -118,7 +126,7 @@ export class Designer implements IDesigner { readonly detecting = new Detecting(); - readonly project: Project; + readonly project: IProject; readonly editor: IPublicModelEditor; @@ -140,7 +148,7 @@ export class Designer implements IDesigner { @obx.ref private _simulatorComponent?: ComponentType<any>; - @obx.ref private _simulatorProps?: Record<string, any> | ((project: Project) => object); + @obx.ref private _simulatorProps?: Record<string, any> | ((project: IProject) => object); @obx.ref private _suspensed = false; diff --git a/packages/designer/src/designer/dragon.ts b/packages/designer/src/designer/dragon.ts index 2fc0ca3e5b..a96c1eec23 100644 --- a/packages/designer/src/designer/dragon.ts +++ b/packages/designer/src/designer/dragon.ts @@ -11,9 +11,9 @@ import { IPublicModelSensor, } from '@alilc/lowcode-types'; import { setNativeSelection, cursor } from '@alilc/lowcode-utils'; -import { Node } from '../document'; +import { INode, Node } from '../document'; import { ISimulatorHost, isSimulatorHost } from '../simulator'; -import { Designer } from './designer'; +import { IDesigner } from './designer'; import { makeEventsHandler } from '../utils/misc'; export interface ILocateEvent extends IPublicModelLocateEvent { @@ -88,14 +88,14 @@ function getSourceSensor(dragObject: IPublicModelDragObject): ISimulatorHost | n if (!isDragNodeObject(dragObject)) { return null; } - return dragObject.nodes[0]?.document.simulator || null; + return dragObject.nodes[0]?.document?.simulator || null; } function isDragEvent(e: any): e is DragEvent { return e?.type?.startsWith('drag'); } -export interface IDragon extends IPublicModelDragon { +export interface IDragon extends IPublicModelDragon<INode> { emitter: IEventBus; } @@ -130,7 +130,7 @@ export class Dragon implements IDragon { emitter: IEventBus = createModuleEventBus('Dragon'); - constructor(readonly designer: Designer) { + constructor(readonly designer: IDesigner) { makeObservable(this); this.viewName = designer.viewName; } @@ -167,7 +167,7 @@ export class Dragon implements IDragon { * @param dragObject 拖拽对象 * @param boostEvent 拖拽初始时事件 */ - boost(dragObject: IPublicModelDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode) { + boost(dragObject: IPublicModelDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: INode | IPublicModelNode) { const { designer } = this; const masterSensors = this.getMasterSensors(); const handleEvents = makeEventsHandler(boostEvent, masterSensors); @@ -264,7 +264,7 @@ export class Dragon implements IDragon { this.emitter.emit('rgl.add.placeholder', { rglNode, fromRglNode, - node: locateEvent.dragObject.nodes[0], + node: locateEvent.dragObject?.nodes[0], event: e, }); designer.clearLocation(); diff --git a/packages/designer/src/designer/offset-observer.ts b/packages/designer/src/designer/offset-observer.ts index d9dd07dbaf..2cf5bfee26 100644 --- a/packages/designer/src/designer/offset-observer.ts +++ b/packages/designer/src/designer/offset-observer.ts @@ -2,7 +2,7 @@ import requestIdleCallback, { cancelIdleCallback } from 'ric-shim'; import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core'; import { uniqueId } from '@alilc/lowcode-utils'; import { INodeSelector, IViewport } from '../simulator'; -import { Node } from '../document'; +import { INode } from '../document'; export class OffsetObserver { readonly id = uniqueId('oobx'); @@ -93,11 +93,11 @@ export class OffsetObserver { private pid: number | undefined; - readonly viewport: IViewport; + readonly viewport: IViewport | undefined; private isRoot: boolean; - readonly node: Node; + readonly node: INode; readonly compute: () => void; @@ -105,10 +105,10 @@ export class OffsetObserver { const { node, instance } = nodeInstance; this.node = node; const doc = node.document; - const host = doc.simulator!; - const focusNode = doc.focusNode; + const host = doc?.simulator; + const focusNode = doc?.focusNode; this.isRoot = node.contains(focusNode!); - this.viewport = host.viewport; + this.viewport = host?.viewport; makeObservable(this); if (this.isRoot) { this.hasOffset = true; @@ -118,7 +118,7 @@ export class OffsetObserver { return; } - let pid: number; + let pid: number | undefined; const compute = () => { if (pid !== this.pid) { return; diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index e44e21d35a..2731aa5e6a 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -35,7 +35,7 @@ import { isDragNodeDataObject, isNode, } from '@alilc/lowcode-utils'; -import { IProject, Project } from '../project'; +import { IProject } from '../project'; import { ISimulatorHost } from '../simulator'; import { IComponentMeta } from '../component-meta'; import { IDesigner, IHistory } from '../designer'; @@ -56,7 +56,7 @@ export type GetDataType<T, NodeType> = T extends undefined export interface IDocumentModel extends Omit< IPublicModelDocumentModel< ISelection, IHistory, - INode | IRootNode, + INode, IDropLocation, IModalNodesManager, IProject @@ -81,6 +81,8 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel< readonly designer: IDesigner; + selection: ISelection; + get rootNode(): INode | null; get simulator(): ISimulatorHost | null; @@ -98,8 +100,6 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel< get currentRoot(): INode | null; - selection: ISelection; - isBlank(): boolean; /** diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index 837fae4b18..61855020ef 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -6,7 +6,6 @@ import { IPublicApiMaterial, IPublicApiEvent, IPublicApiCommon, - IPublicTypeCompositeObject, IPublicApiPlugins, IPublicTypePluginConfig, IPublicApiLogger, @@ -16,6 +15,7 @@ import { IPublicApiCanvas, IPublicApiWorkspace, IPublicTypePluginMeta, + IPublicTypePluginRegisterOptions, } from '@alilc/lowcode-types'; export type PluginPreference = Map<string, Record<string, IPublicTypePreferenceValueType>>; @@ -72,7 +72,7 @@ export interface ILowCodePluginManagerCore { register( pluginModel: IPublicTypePlugin, pluginOptions?: any, - options?: IPublicTypeCompositeObject, + options?: IPublicTypePluginRegisterOptions, ): Promise<void>; init(pluginPreference?: Map<string, Record<string, IPublicTypePreferenceValueType>>): Promise<void>; get(pluginName: string): ILowCodePluginRuntime | undefined; diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 51db678ad0..3204e5c8b6 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -41,6 +41,14 @@ export interface IProject extends Omit< IBaseApiProject< get documents(): IDocumentModel[]; + get i18n(): { + [local: string]: { + [key: string]: any; + }; + }; + + mountSimulator(simulator: ISimulatorHost): void; + open(doc?: string | IDocumentModel | IPublicTypeRootSchema): IDocumentModel | null; getDocumentByFileName(fileName: string): IDocumentModel | null; diff --git a/packages/designer/src/simulator.ts b/packages/designer/src/simulator.ts index 99586fb815..3a63a685b8 100644 --- a/packages/designer/src/simulator.ts +++ b/packages/designer/src/simulator.ts @@ -1,8 +1,9 @@ import { ComponentType } from 'react'; import { IPublicTypeComponentMetadata, IPublicTypeNodeSchema, IPublicTypeScrollable, IPublicTypeComponentInstance, IPublicModelSensor, IPublicTypeNodeInstance, IPublicTypePackage } from '@alilc/lowcode-types'; -import { Point, ScrollTarget, ILocateEvent } from './designer'; +import { Point, ScrollTarget, ILocateEvent, IDesigner } from './designer'; import { BuiltinSimulatorRenderer } from './builtin-simulator/renderer'; import { INode } from './document'; +import { IProject } from './project'; export type AutoFit = '100%'; // eslint-disable-next-line no-redeclare @@ -89,6 +90,10 @@ export interface ISimulatorHost<P = object> extends IPublicModelSensor<INode> { readonly contentDocument?: Document; readonly renderer?: BuiltinSimulatorRenderer; + readonly project: IProject; + + readonly designer: IDesigner; + // dependsAsset // like react jQuery lodash // themesAsset // componentsAsset diff --git a/packages/editor-core/src/hotkey.ts b/packages/editor-core/src/hotkey.ts index 30390dacab..adc74262a8 100644 --- a/packages/editor-core/src/hotkey.ts +++ b/packages/editor-core/src/hotkey.ts @@ -339,8 +339,8 @@ function fireCallback(callback: IPublicTypeHotkeyCallback, e: KeyboardEvent, com } } -export interface IHotKey extends IPublicApiHotkey { - +export interface IHotKey extends Omit<IPublicApiHotkey, 'bind' | 'callbacks'> { + activate(activate: boolean): void; } export class Hotkey implements IHotKey { diff --git a/packages/editor-core/src/widgets/tip/tip-container.tsx b/packages/editor-core/src/widgets/tip/tip-container.tsx index ae494d5409..619c10423e 100644 --- a/packages/editor-core/src/widgets/tip/tip-container.tsx +++ b/packages/editor-core/src/widgets/tip/tip-container.tsx @@ -1,4 +1,5 @@ import { Component } from 'react'; +import ReactDOM from 'react-dom'; import { TipItem } from './tip-item'; import { tipHandler } from './tip-handler'; @@ -25,11 +26,13 @@ export class TipContainer extends Component { } render() { - return window.ReactDOM.createPortal( + ReactDOM.createPortal( <div className="lc-tips-container"> <TipItem /> </div>, document.querySelector('body')!, ); + + return null; } } diff --git a/packages/shell/src/api/plugins.ts b/packages/shell/src/api/plugins.ts index 6e2b9c6b76..e5a79edbd4 100644 --- a/packages/shell/src/api/plugins.ts +++ b/packages/shell/src/api/plugins.ts @@ -1,5 +1,5 @@ import { - LowCodePluginManager, + ILowCodePluginManager, } from '@alilc/lowcode-designer'; import { globalContext } from '@alilc/lowcode-editor-core'; import { @@ -14,8 +14,8 @@ import { pluginsSymbol } from '../symbols'; const innerPluginsSymbol = Symbol('plugin'); export class Plugins implements IPublicApiPlugins { - private readonly [innerPluginsSymbol]: LowCodePluginManager; - get [pluginsSymbol](): LowCodePluginManager { + private readonly [innerPluginsSymbol]: ILowCodePluginManager; + get [pluginsSymbol](): ILowCodePluginManager { if (this.workspaceMode) { return this[innerPluginsSymbol]; } @@ -27,7 +27,7 @@ export class Plugins implements IPublicApiPlugins { return this[innerPluginsSymbol]; } - constructor(plugins: LowCodePluginManager, public workspaceMode: boolean = false) { + constructor(plugins: ILowCodePluginManager, public workspaceMode: boolean = false) { this[innerPluginsSymbol] = plugins; } diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index 54fccf4268..ae4bc65aad 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -1,13 +1,13 @@ import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; -import { Workspace as InnerWorkSpace } from '@alilc/lowcode-workspace'; +import { IWorkspace } from '@alilc/lowcode-workspace'; import { Plugins } from '@alilc/lowcode-shell'; import { workspaceSymbol } from '../symbols'; import { Resource as ShellResource, Window as ShellWindow } from '../model'; export class Workspace implements IPublicApiWorkspace { - readonly [workspaceSymbol]: InnerWorkSpace; + readonly [workspaceSymbol]: IWorkspace; - constructor(innerWorkspace: InnerWorkSpace) { + constructor(innerWorkspace: IWorkspace) { this[workspaceSymbol] = innerWorkspace; } diff --git a/packages/shell/src/model/resource.ts b/packages/shell/src/model/resource.ts index 63435cdea2..b2b0653981 100644 --- a/packages/shell/src/model/resource.ts +++ b/packages/shell/src/model/resource.ts @@ -1,11 +1,11 @@ import { IPublicModelResource } from '@alilc/lowcode-types'; -import { Resource as InnerResource } from '@alilc/lowcode-workspace'; +import { IResource } from '@alilc/lowcode-workspace'; import { resourceSymbol } from '../symbols'; export class Resource implements IPublicModelResource { - readonly [resourceSymbol]: InnerResource; + readonly [resourceSymbol]: IResource; - constructor(resource: InnerResource) { + constructor(resource: IResource) { this[resourceSymbol] = resource; } diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index e2f17b8892..b1263d5415 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -1,10 +1,10 @@ import { windowSymbol } from '../symbols'; import { IPublicModelResource, IPublicModelWindow, IPublicTypeDisposable } from '@alilc/lowcode-types'; -import { EditorWindow } from '@alilc/lowcode-workspace'; +import { IEditorWindow } from '@alilc/lowcode-workspace'; import { Resource as ShellResource } from './resource'; export class Window implements IPublicModelWindow { - private readonly [windowSymbol]: EditorWindow; + private readonly [windowSymbol]: IEditorWindow; get id() { return this[windowSymbol]?.id; @@ -22,7 +22,7 @@ export class Window implements IPublicModelWindow { return new ShellResource(this[windowSymbol].resource); } - constructor(editorWindow: EditorWindow) { + constructor(editorWindow: IEditorWindow) { this[windowSymbol] = editorWindow; } diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index c1be4cb7e6..8c19846f70 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -2,19 +2,20 @@ import { IPublicModelWindow } from '../model'; import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; export interface IPublicApiWorkspace< - Plugins = IPublicApiPlugins + Plugins = IPublicApiPlugins, + ModelWindow = IPublicModelWindow > { /** 是否启用 workspace 模式 */ isActive: boolean; /** 当前设计器窗口 */ - window: IPublicModelWindow; + window: ModelWindow; plugins: Plugins; /** 当前设计器的编辑窗口 */ - windows: IPublicModelWindow[]; + windows: ModelWindow[]; /** 获取资源树列表 */ get resourceList(): IPublicModelResource[]; diff --git a/packages/types/src/shell/model/drag-object.ts b/packages/types/src/shell/model/drag-object.ts index 9169ea8530..af404a2f00 100644 --- a/packages/types/src/shell/model/drag-object.ts +++ b/packages/types/src/shell/model/drag-object.ts @@ -1,8 +1,3 @@ -export interface IPublicModelDragObject { +import { IPublicTypeDragNodeDataObject, IPublicTypeDragNodeObject } from '../type'; - get type(): any; - - get nodes(): any; - - get data(): any; -} +export type IPublicModelDragObject = Readonly<IPublicTypeDragNodeObject> | Readonly<IPublicTypeDragNodeDataObject>; diff --git a/packages/types/src/shell/model/resource.ts b/packages/types/src/shell/model/resource.ts index c817766598..e18f3d5032 100644 --- a/packages/types/src/shell/model/resource.ts +++ b/packages/types/src/shell/model/resource.ts @@ -1,6 +1,8 @@ import { ReactElement } from 'react'; -export interface IPublicModelResource { +export interface IBaseModelResource< + Resource +> { get title(): string | undefined; get icon(): ReactElement | undefined; @@ -13,7 +15,9 @@ export interface IPublicModelResource { get category(): string | undefined; - get children(): IPublicModelResource[]; + get children(): Resource[]; get viewName(): string | undefined; -} \ No newline at end of file +} + +export type IPublicModelResource = IBaseModelResource<IPublicModelResource>; diff --git a/packages/types/src/shell/model/window.ts b/packages/types/src/shell/model/window.ts index f772dc9f49..bb27ce317c 100644 --- a/packages/types/src/shell/model/window.ts +++ b/packages/types/src/shell/model/window.ts @@ -2,7 +2,9 @@ import { ReactElement } from 'react'; import { IPublicTypeDisposable, IPublicTypeNodeSchema } from '../type'; import { IPublicModelResource } from './resource'; -export interface IPublicModelWindow { +export interface IPublicModelWindow< + Resource = IPublicModelResource +> { /** 窗口 id */ id: string; @@ -14,7 +16,7 @@ export interface IPublicModelWindow { icon?: ReactElement; /** 窗口资源类型 */ - resource?: IPublicModelResource; + resource?: Resource; /** 当前窗口导入 schema */ importSchema(schema: IPublicTypeNodeSchema): void; diff --git a/packages/types/src/shell/type/action-content-object.ts b/packages/types/src/shell/type/action-content-object.ts index 25e913f022..cf3e0c0481 100644 --- a/packages/types/src/shell/type/action-content-object.ts +++ b/packages/types/src/shell/type/action-content-object.ts @@ -1,19 +1,23 @@ +import { IPublicModelNode } from '../model'; import { IPublicTypeIconType, TipContent } from './'; /** * 动作描述 */ export interface IPublicTypeActionContentObject { + /** * 图标 */ icon?: IPublicTypeIconType; + /** * 描述 */ title?: TipContent; + /** * 执行动作 */ - action?: (currentNode: any) => void; + action?: (currentNode: IPublicModelNode) => void; } diff --git a/packages/types/src/shell/type/location.ts b/packages/types/src/shell/type/location.ts index c9e2df67fd..4f8b59a7c5 100644 --- a/packages/types/src/shell/type/location.ts +++ b/packages/types/src/shell/type/location.ts @@ -15,13 +15,14 @@ export enum LocationDetailType { } export type IPublicTypeRect = DOMRect & { - elements: Array<Element | Text>; + elements?: Array<Element | Text>; computed?: boolean; }; export interface IPublicTypeLocationChildrenDetail { type: IPublicTypeLocationDetailType.Children; index?: number | null; + /** * 是否有效位置 */ @@ -43,8 +44,7 @@ export interface IPublicTypeLocationPropDetail { domNode?: HTMLElement; } -// eslint-disable-next-line max-len -export type IPublicTypeLocationDetail = IPublicTypeLocationChildrenDetail | IPublicTypeLocationPropDetail | { type: string; [key: string]: any }; +export type IPublicTypeLocationDetail = IPublicTypeLocationChildrenDetail | IPublicTypeLocationPropDetail | { [key: string]: any; type: string }; export interface IPublicTypeLocationData< Node = IPublicModelNode diff --git a/packages/types/src/shell/type/metadata.ts b/packages/types/src/shell/type/metadata.ts index 7f972622be..7ed9dc6be6 100644 --- a/packages/types/src/shell/type/metadata.ts +++ b/packages/types/src/shell/type/metadata.ts @@ -1,3 +1,4 @@ +import { MouseEvent } from 'react'; import { IPublicTypePropType, IPublicTypeComponentAction } from './'; import { IPublicModelNode, IPublicModelProp, IPublicModelSettingField } from '../model'; diff --git a/packages/types/src/shell/type/resource-list.ts b/packages/types/src/shell/type/resource-list.ts index db5e33dc8a..5831d7b507 100644 --- a/packages/types/src/shell/type/resource-list.ts +++ b/packages/types/src/shell/type/resource-list.ts @@ -1,20 +1,27 @@ import { ReactElement } from 'react'; export interface IPublicResourceData { + /** 资源名字 */ resourceName: string; + /** 资源标题 */ - title: string; + title?: string; + /** 分类 */ category?: string; + /** 资源视图 */ viewName?: string; + /** 资源 icon */ icon?: ReactElement; + /** 资源其他配置 */ options: { [key: string]: any; }; + /** 资源子元素 */ children?: IPublicResourceData[]; } diff --git a/packages/utils/src/check-types/is-action-content-object.ts b/packages/utils/src/check-types/is-action-content-object.ts index 20c8171774..4e9a6545a4 100644 --- a/packages/utils/src/check-types/is-action-content-object.ts +++ b/packages/utils/src/check-types/is-action-content-object.ts @@ -1,4 +1,5 @@ +import { IPublicTypeActionContentObject } from '@alilc/lowcode-types'; -export function isActionContentObject(obj: any): boolean { +export function isActionContentObject(obj: any): obj is IPublicTypeActionContentObject { return obj && typeof obj === 'object'; } diff --git a/packages/utils/src/check-types/is-location-data.ts b/packages/utils/src/check-types/is-location-data.ts index 3fa3a4204c..8bb3103461 100644 --- a/packages/utils/src/check-types/is-location-data.ts +++ b/packages/utils/src/check-types/is-location-data.ts @@ -1,4 +1,5 @@ +import { IPublicTypeLocationData } from '@alilc/lowcode-types'; -export function isLocationData(obj: any): boolean { +export function isLocationData(obj: any): obj is IPublicTypeLocationData { return obj && obj.target && obj.detail; } \ No newline at end of file diff --git a/packages/utils/src/css-helper.ts b/packages/utils/src/css-helper.ts index 9858d0d54e..98bf1bbf0c 100644 --- a/packages/utils/src/css-helper.ts +++ b/packages/utils/src/css-helper.ts @@ -10,14 +10,13 @@ const pseudoMap = ['hover', 'focus', 'active', 'visited']; const RE_CAMEL = /[A-Z]/g; const RE_HYPHEN = /[-\s]+(.)?/g; -const CSS_REG = /:root(.*)\{.*/i; const PROPS_REG = /([^:]*):\s?(.*)/i; // 给 css 分组 -function groupingCss(css) { +function groupingCss(css: string) { let stackLength = 0; let startIndex = 0; - const group = []; + const group: string[] = []; css.split('').forEach((char, index) => { if (char === '{') { stackLength++; @@ -33,38 +32,38 @@ function groupingCss(css) { return group; } - -function isString(str) { +function isString(str: any): str is string { return {}.toString.call(str) === '[object String]'; } -function hyphenate(str) { +function hyphenate(str: string): string { return str.replace(RE_CAMEL, w => `-${w}`).toLowerCase(); } -function camelize(str) { +function camelize(str: string): string { return str.replace(RE_HYPHEN, (m, w) => (w ? w.toUpperCase() : '')); } + /** * convert * {background-color: "red"} * to * background-color: red; */ -function runtimeToCss(runtime) { - const css = []; +function runtimeToCss(runtime: Record<string, string>) { + const css: string[] = []; Object.keys(runtime).forEach((key) => { css.push(` ${key}: ${runtime[key]};`); }); return css.join('\n'); } -function toNativeStyle(runtime) { +function toNativeStyle(runtime: Record<string, string> | undefined) { if (!runtime) { return {}; } if (runtime.default) { - const normalized = {}; + const normalized: Record<string, string> = {}; Object.keys(runtime).forEach((pseudo) => { if (pseudo === 'extra') { normalized[pseudo] = runtime[pseudo]; @@ -98,14 +97,13 @@ function normalizeStyle(style) { return normalized; } - const normalized = {}; + const normalized: Record<string, string | Record<string, string>> = {}; Object.keys(style).forEach((key) => { normalized[hyphenate(key)] = style[key]; }); return normalized; } - function toCss(runtime) { if (!runtime) { return ( @@ -115,7 +113,7 @@ function toCss(runtime) { } if (runtime.default) { - const css = []; + const css: string[] = []; Object.keys(runtime).forEach((pseudo) => { if (pseudo === 'extra') { Array.isArray(runtime.extra) && css.push(runtime.extra.join('\n')); @@ -140,11 +138,14 @@ ${runtimeToCss(normalizeStyle(runtime))} ); } -function cssToRuntime(css) { +function cssToRuntime(css: string) { if (!css) { return {}; } - const runtime = {}; + const runtime: { + extra?: string[]; + default?: Record<string, string>; + } = {}; const groups = groupingCss(css); groups.forEach((cssItem) => { if (!cssItem.startsWith(':root')) { @@ -153,7 +154,7 @@ function cssToRuntime(css) { } else { const res = /:root:?(.*)?{(.*)/ig.exec(cssItem.replace(/[\r\n]+/ig, '').trim()); if (res) { - let pseudo; + let pseudo: string | undefined; if (res[1] && res[1].trim() && some(pseudoMap, pse => res[1].indexOf(pse) === 0)) { pseudo = res[1].trim(); @@ -161,8 +162,8 @@ function cssToRuntime(css) { pseudo = res[1]; } - const s = {}; - res[2].split(';').reduce((prev, next) => { + const s: Record<string, string> = {}; + res[2].split(';').reduce<string[]>((prev, next) => { if (next.indexOf('base64') > -1) { prev[prev.length - 1] += `;${next}`; } else { @@ -173,8 +174,8 @@ function cssToRuntime(css) { if (item) { if (PROPS_REG.test(item)) { const props = item.match(PROPS_REG); - const key = props[1]; - const value = props[2]; + const key = props?.[1]; + const value = props?.[2]; if (key && value) { s[key.trim()] = value.trim(); } @@ -182,10 +183,7 @@ function cssToRuntime(css) { } }); - if (!pseudo) { - pseudo = 'default'; - } - runtime[pseudo] = s; + runtime[pseudo || 'default'] = s; } } }); diff --git a/packages/utils/src/is-react.ts b/packages/utils/src/is-react.ts index 02ef50fa67..1f17f9afc2 100644 --- a/packages/utils/src/is-react.ts +++ b/packages/utils/src/is-react.ts @@ -23,7 +23,8 @@ export function isReactComponent(obj: any): obj is ComponentType<any> { export function wrapReactClass(view: FunctionComponent) { let ViewComponentClass = class extends Component { render() { - return createElement(view, this.props); + const { children, ...other } = this.props; + return createElement(view, other, children); } } as any; ViewComponentClass = cloneEnumerableProperty(ViewComponentClass, view); diff --git a/packages/utils/src/node-helper.ts b/packages/utils/src/node-helper.ts index 55d42be4e6..60102d6794 100644 --- a/packages/utils/src/node-helper.ts +++ b/packages/utils/src/node-helper.ts @@ -1,5 +1,6 @@ // 仅使用类型 import { IPublicModelNode } from '@alilc/lowcode-types'; +import { MouseEvent } from 'react'; export const getClosestNode = <Node extends IPublicModelNode = IPublicModelNode>( node: Node, @@ -12,7 +13,7 @@ export const getClosestNode = <Node extends IPublicModelNode = IPublicModelNode> return node; } else { // @ts-ignore - return getClosestNode(node.getParent(), until); + return getClosestNode(node.parent, until); } }; @@ -22,8 +23,8 @@ export const getClosestNode = <Node extends IPublicModelNode = IPublicModelNode> * @param {unknown} e 点击事件 * @returns {boolean} 是否可点击,true表示可点击 */ -export function canClickNode<Node extends IPublicModelNode = IPublicModelNode>(node: Node, e: unknown): boolean { +export function canClickNode<Node extends IPublicModelNode = IPublicModelNode>(node: Node, e: MouseEvent): boolean { const onClickHook = node.componentMeta?.advanced?.callbacks?.onClickHook; - const canClick = typeof onClickHook === 'function' ? onClickHook(e as MouseEvent, node) : true; + const canClick = typeof onClickHook === 'function' ? onClickHook(e, node) : true; return canClick; -}; +} diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index b67842fe8d..b82e25872a 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -3,13 +3,17 @@ import { engineConfig, Setters as InnerSetters, Hotkey as InnerHotkey, commonEvent, + IEngineConfig, + IHotKey, } from '@alilc/lowcode-editor-core'; import { Designer, ILowCodePluginContextApiAssembler, LowCodePluginManager, ILowCodePluginContextPrivate, - Project as InnerProject, + IProject, + IDesigner, + ILowCodePluginManager, } from '@alilc/lowcode-designer'; import { Skeleton as InnerSkeleton, @@ -29,40 +33,72 @@ import { } from '@alilc/lowcode-shell'; import { IPluginPreferenceMananger, + IPublicApiCanvas, + IPublicApiCommon, IPublicApiEvent, - IPublicApiWorkspace, + IPublicApiHotkey, + IPublicApiMaterial, + IPublicApiPlugins, + IPublicApiProject, + IPublicApiSetters, + IPublicApiSkeleton, IPublicModelPluginContext, IPublicTypePluginMeta, } from '@alilc/lowcode-types'; -import { getLogger } from '@alilc/lowcode-utils'; -import { Workspace as InnerWorkspace } from '../workspace'; -import { EditorWindow } from '../window'; +import { getLogger, Logger as InnerLogger } from '@alilc/lowcode-utils'; +import { IWorkspace } from '../workspace'; +import { IEditorWindow } from '../window'; -export class BasicContext implements IPublicModelPluginContext { - skeleton: Skeleton; - plugins: Plugins; - project: Project; - setters: Setters; - material: Material; - common: Common; - config; - event; - logger; - hotkey: Hotkey; - innerProject: InnerProject; +export interface IBasicContext extends Omit<IPublicModelPluginContext, 'workspace'> { + skeleton: IPublicApiSkeleton; + plugins: IPublicApiPlugins; + project: IPublicApiProject; + setters: IPublicApiSetters; + material: IPublicApiMaterial; + common: IPublicApiCommon; + config: IEngineConfig; + event: IPublicApiEvent; + logger: InnerLogger; + hotkey: IPublicApiHotkey; + innerProject: IProject; editor: Editor; - designer: Designer; + designer: IDesigner; registerInnerPlugins: () => Promise<void>; innerSetters: InnerSetters; innerSkeleton: InnerSkeleton; - innerHotkey: InnerHotkey; - innerPlugins: LowCodePluginManager; - canvas: Canvas; + innerHotkey: IHotKey; + innerPlugins: ILowCodePluginManager; + canvas: IPublicApiCanvas; pluginEvent: IPublicApiEvent; preference: IPluginPreferenceMananger; - workspace: IPublicApiWorkspace; + workspace: IWorkspace; +} - constructor(innerWorkspace: InnerWorkspace, viewName: string, public editorWindow?: EditorWindow) { +export class BasicContext implements IBasicContext { + skeleton: IPublicApiSkeleton; + plugins: IPublicApiPlugins; + project: IPublicApiProject; + setters: IPublicApiSetters; + material: IPublicApiMaterial; + common: IPublicApiCommon; + config: IEngineConfig; + event: IPublicApiEvent; + logger: InnerLogger; + hotkey: IPublicApiHotkey; + innerProject: IProject; + editor: Editor; + designer: IDesigner; + registerInnerPlugins: () => Promise<void>; + innerSetters: InnerSetters; + innerSkeleton: InnerSkeleton; + innerHotkey: IHotKey; + innerPlugins: ILowCodePluginManager; + canvas: IPublicApiCanvas; + pluginEvent: IPublicApiEvent; + preference: IPluginPreferenceMananger; + workspace: IWorkspace; + + constructor(innerWorkspace: IWorkspace, viewName: string, public editorWindow?: IEditorWindow) { const editor = new Editor(viewName, true); const innerSkeleton = new InnerSkeleton(editor, viewName); @@ -110,7 +146,7 @@ export class BasicContext implements IPublicModelPluginContext { this.canvas = canvas; const common = new Common(editor, innerSkeleton); this.common = common; - let plugins: any; + let plugins: IPublicApiPlugins; const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { assembleApis: (context: ILowCodePluginContextPrivate, pluginName: string, meta: IPublicTypePluginMeta) => { diff --git a/packages/workspace/src/context/view-context.ts b/packages/workspace/src/context/view-context.ts index d145496676..38a9e570fa 100644 --- a/packages/workspace/src/context/view-context.ts +++ b/packages/workspace/src/context/view-context.ts @@ -1,9 +1,9 @@ import { computed, makeObservable, obx } from '@alilc/lowcode-editor-core'; import { IPublicEditorViewConfig, IPublicTypeEditorView } from '@alilc/lowcode-types'; import { flow } from 'mobx'; -import { Workspace as InnerWorkspace } from '../workspace'; +import { IWorkspace } from '../workspace'; import { BasicContext } from './base-context'; -import { EditorWindow } from '../window'; +import { IEditorWindow } from '../window'; import { getWebviewPlugin } from '../inner-plugins/webview'; export class Context extends BasicContext { @@ -21,7 +21,7 @@ export class Context extends BasicContext { return this._activate; } - init = flow(function* (this: any) { + init = flow(function* (this: Context) { if (this.viewType === 'webview') { const url = yield this.instance?.url?.(); yield this.plugins.register(getWebviewPlugin(url, this.viewName)); @@ -33,7 +33,7 @@ export class Context extends BasicContext { this.isInit = true; }); - constructor(public workspace: InnerWorkspace, public editorWindow: EditorWindow, public editorView: IPublicTypeEditorView, options: Object | undefined) { + constructor(public workspace: IWorkspace, public editorWindow: IEditorWindow, public editorView: IPublicTypeEditorView, options: Object | undefined) { super(workspace, editorView.viewName, editorWindow); this.viewType = editorView.viewType || 'editor'; this.viewName = editorView.viewName; diff --git a/packages/workspace/src/index.ts b/packages/workspace/src/index.ts index 9442266bb1..157219e9f2 100644 --- a/packages/workspace/src/index.ts +++ b/packages/workspace/src/index.ts @@ -1,4 +1,4 @@ -export { Workspace } from './workspace'; +export { Workspace, IWorkspace } from './workspace'; export * from './window'; export * from './layouts/workbench'; -export { Resource } from './resource'; +export { Resource, IResource } from './resource'; diff --git a/packages/workspace/src/resource-type.ts b/packages/workspace/src/resource-type.ts index b521830689..28d54e56b3 100644 --- a/packages/workspace/src/resource-type.ts +++ b/packages/workspace/src/resource-type.ts @@ -1,6 +1,14 @@ import { IPublicTypeResourceType } from '@alilc/lowcode-types'; -export class ResourceType { +export interface IResourceType extends Omit<IPublicTypeResourceType, 'resourceName' | 'resourceType'> { + name: string; + + type: 'editor' | 'webview'; + + resourceTypeModel: IPublicTypeResourceType; +} + +export class ResourceType implements IResourceType { constructor(readonly resourceTypeModel: IPublicTypeResourceType) { } diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index ffb60ff6ac..e9033cca76 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -1,13 +1,31 @@ -import { IPublicTypeEditorView, IPublicModelResource, IPublicResourceData, IPublicResourceTypeConfig } from '@alilc/lowcode-types'; +import { IPublicTypeEditorView, IPublicResourceData, IPublicResourceTypeConfig, IBaseModelResource } from '@alilc/lowcode-types'; import { Logger } from '@alilc/lowcode-utils'; -import { BasicContext } from './context/base-context'; -import { ResourceType } from './resource-type'; -import { Workspace as InnerWorkSpace } from './workspace'; +import { BasicContext, IBasicContext } from './context/base-context'; +import { ResourceType, IResourceType } from './resource-type'; +import { IWorkspace } from './workspace'; const logger = new Logger({ level: 'warn', bizName: 'workspace:resource' }); -export class Resource implements IPublicModelResource { - private context: BasicContext; +export interface IBaseResource<T> extends IBaseModelResource<T> { + readonly resourceType: ResourceType; + + get editorViews(): IPublicTypeEditorView[]; + + get defaultViewType(): string; + + getEditorView(name: string): IPublicTypeEditorView | undefined; + + import(schema: any): Promise<any>; + + save(value: any): Promise<any>; + + url(): Promise<string | undefined>; +} + +export type IResource = IBaseResource<IResource>; + +export class Resource implements IResource { + private context: IBasicContext; resourceTypeInstance: IPublicResourceTypeConfig; @@ -49,13 +67,13 @@ export class Resource implements IPublicModelResource { return this.context.innerSkeleton; } - get children(): Resource[] { + get children(): IResource[] { return this.resourceData?.children?.map(d => new Resource(d, this.resourceType, this.workspace)) || []; } - constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, readonly workspace: InnerWorkSpace) { + constructor(readonly resourceData: IPublicResourceData, readonly resourceType: IResourceType, readonly workspace: IWorkspace) { this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`); - this.resourceTypeInstance = resourceType.resourceTypeModel(this.context, this.options); + this.resourceTypeInstance = resourceType.resourceTypeModel(this.context.innerPlugins._getLowCodePluginContext(), this.options); this.init(); if (this.resourceTypeInstance.editorViews) { this.resourceTypeInstance.editorViews.forEach((d: any) => { diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index e7e08757f0..1fa4265241 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -1,9 +1,10 @@ import { uniqueId } from '@alilc/lowcode-utils'; import { createModuleEventBus, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; import { Context } from './context/view-context'; -import { Workspace } from './workspace'; -import { Resource } from './resource'; +import { IWorkspace } from './workspace'; +import { IResource } from './resource'; import { IPublicTypeDisposable } from '../../types/es/shell/type/disposable'; +import { IPublicModelWindow } from '@alilc/lowcode-types'; interface IWindowCOnfig { title: string | undefined; @@ -11,7 +12,13 @@ interface IWindowCOnfig { viewType?: string | undefined; } -export class EditorWindow { +export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'changeViewType'> { + readonly resource: IResource; + + changeViewType: (name: string, ignoreEmit?: boolean) => void; +} + +export class EditorWindow implements IEditorWindow { id: string = uniqueId('window'); icon: React.ReactElement | undefined; @@ -27,7 +34,7 @@ export class EditorWindow { @obx initReady = false; - constructor(readonly resource: Resource, readonly workspace: Workspace, private config: IWindowCOnfig) { + constructor(readonly resource: IResource, readonly workspace: IWorkspace, private config: IWindowCOnfig) { makeObservable(this); this.init(); this.title = config.title; diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index f7d49ed49e..526e1f2ca1 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -1,23 +1,33 @@ -import { Designer, LowCodePluginManager } from '@alilc/lowcode-designer'; +import { IDesigner, ILowCodePluginManager, LowCodePluginManager } from '@alilc/lowcode-designer'; import { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; -import { Plugins } from '@alilc/lowcode-shell'; -import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types'; +import { IPublicApiPlugins, IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types'; import { BasicContext } from './context/base-context'; -import { EditorWindow } from './window'; -import { Resource } from './resource'; -import { ResourceType } from './resource-type'; +import { EditorWindow, IEditorWindow } from './window'; +import { IResource, Resource } from './resource'; +import { IResourceType, ResourceType } from './resource-type'; -enum event { - ChangeWindow = 'change_window', +enum EVENT { + CHANGE_WINDOW = 'change_window', - ChangeActiveWindow = 'change_active_window', + CHANGE_ACTIVE_WINDOW = 'change_active_window', } const CHANGE_EVENT = 'resource.list.change'; -interface IWorkspace extends Omit<IPublicApiWorkspace< -LowCodePluginManager ->, 'resourceList'> {} +export interface IWorkspace extends Omit<IPublicApiWorkspace< + LowCodePluginManager, + IEditorWindow +>, 'resourceList' | 'plugins'> { + readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise<void>; + + readonly shellModelFactory: IShellModelFactory; + + window: IEditorWindow; + + plugins: ILowCodePluginManager; + + getResourceList(): IResource[]; +} export class Workspace implements IWorkspace { context: BasicContext; @@ -28,7 +38,7 @@ export class Workspace implements IWorkspace { private resourceTypeMap: Map<string, ResourceType> = new Map(); - private resourceList: Resource[] = []; + private resourceList: IResource[] = []; get skeleton() { return this.context.innerSkeleton; @@ -50,14 +60,14 @@ export class Workspace implements IWorkspace { return null; } - @obx.ref windows: EditorWindow[] = []; + @obx.ref windows: IEditorWindow[] = []; - editorWindowMap: Map<string, EditorWindow> = new Map<string, EditorWindow>(); + editorWindowMap: Map<string, IEditorWindow> = new Map<string, IEditorWindow>(); - @obx.ref window: EditorWindow; + @obx.ref window: IEditorWindow; constructor( - readonly registryInnerPlugin: (designer: Designer, editor: Editor, plugins: Plugins) => Promise<void>, + readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise<void>, readonly shellModelFactory: any, ) { this.init(); @@ -74,7 +84,10 @@ export class Workspace implements IWorkspace { return; } const title = this.defaultResourceType.name; - const resource = new Resource({}, this.defaultResourceType, this); + const resource = new Resource({ + resourceName: title, + options: {}, + }, this.defaultResourceType, this); this.window = new EditorWindow(resource, this, { title, }); @@ -113,7 +126,7 @@ export class Workspace implements IWorkspace { }; } - getResourceType(resourceName: string): ResourceType { + getResourceType(resourceName: string): IResourceType { return this.resourceTypeMap.get(resourceName)!; } @@ -139,7 +152,7 @@ export class Workspace implements IWorkspace { } removeEditorWindow(resourceName: string) { - const index = this.windows.findIndex(d => (d.resource.name === resourceName && d.title)); + const index = this.windows.findIndex(d => (d.resource?.name === resourceName && d.title)); this.remove(index); } @@ -157,7 +170,7 @@ export class Workspace implements IWorkspace { console.error(`${name} resourceType is not available`); return; } - const filterWindows = this.windows.filter(d => (d.resource.name === name && d.resource.title == title)); + const filterWindows = this.windows.filter(d => (d.resource?.name === name && d.resource.title == title)); if (filterWindows && filterWindows.length) { this.window = filterWindows[0]; this.emitChangeActiveWindow(); @@ -180,24 +193,24 @@ export class Workspace implements IWorkspace { } onChangeWindows(fn: () => void) { - this.emitter.on(event.ChangeWindow, fn); + this.emitter.on(EVENT.CHANGE_WINDOW, fn); return () => { - this.emitter.removeListener(event.ChangeWindow, fn); + this.emitter.removeListener(EVENT.CHANGE_WINDOW, fn); }; } emitChangeWindow() { - this.emitter.emit(event.ChangeWindow); + this.emitter.emit(EVENT.CHANGE_WINDOW); } emitChangeActiveWindow() { - this.emitter.emit(event.ChangeActiveWindow); + this.emitter.emit(EVENT.CHANGE_ACTIVE_WINDOW); } onChangeActiveWindow(fn: () => void) { - this.emitter.on(event.ChangeActiveWindow, fn); + this.emitter.on(EVENT.CHANGE_ACTIVE_WINDOW, fn); return () => { - this.emitter.removeListener(event.ChangeActiveWindow, fn); + this.emitter.removeListener(EVENT.CHANGE_ACTIVE_WINDOW, fn); }; } } From fc7c217f8cec0e0db064b7ebf8038c75c3ef253a Mon Sep 17 00:00:00 2001 From: huxingyi1997 <xingyi.hu@shopee.com> Date: Fri, 17 Mar 2023 12:04:37 +0800 Subject: [PATCH 059/469] fix: missing i18n parameter in simulater and renderer --- packages/designer/src/builtin-simulator/host.ts | 3 ++- packages/react-simulator-renderer/src/renderer.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index b2a41b831a..91ab1a17b5 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -6,6 +6,7 @@ import { getPublicPath, focusTracker, engineConfig, + globalLocale, IReactionPublic, IReactionOptions, IReactionDisposer, @@ -198,7 +199,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp } @computed get locale(): string { - return this.get('locale'); + return this.get('locale') || globalLocale.getLocale(); } @computed get deviceClassName(): string | undefined { diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index dbb24a5bb5..44fec00098 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -461,6 +461,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { locale: renderer.locale, messages: _schema.i18n || {}, device: renderer.device, + locale: renderer.locale, appHelper: renderer.context, rendererName: 'LowCodeRenderer', thisRequiredInJSE: host.thisRequiredInJSE, @@ -632,4 +633,4 @@ function getLowCodeComponentProps(props: any) { return newProps; } -export default new SimulatorRendererContainer(); \ No newline at end of file +export default new SimulatorRendererContainer(); From 21f74f0cc1566c0a69b7420f3603b16cd8331931 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 20 Mar 2023 18:09:59 +0800 Subject: [PATCH 060/469] feat: update skeleton ts defined --- packages/editor-core/src/editor.ts | 59 +++++++++------- packages/editor-skeleton/src/area.ts | 8 +-- .../src/components/settings/settings-pane.tsx | 5 +- .../src/components/stage-box/stage-box.tsx | 7 +- packages/editor-skeleton/src/context.ts | 4 +- .../src/layouts/left-float-pane.tsx | 3 +- .../editor-skeleton/src/layouts/workbench.tsx | 4 +- packages/editor-skeleton/src/skeleton.ts | 69 +++++++++++++++++-- .../src/transducers/parse-func.ts | 1 + packages/editor-skeleton/src/types.ts | 11 +-- packages/editor-skeleton/src/widget/dock.ts | 4 +- .../editor-skeleton/src/widget/panel-dock.ts | 19 +++-- packages/editor-skeleton/src/widget/panel.ts | 6 +- packages/editor-skeleton/src/widget/stage.ts | 4 +- packages/editor-skeleton/src/widget/utils.ts | 36 ++++++---- packages/editor-skeleton/src/widget/widget.ts | 6 +- packages/shell/src/api/event.ts | 8 +-- packages/shell/src/api/skeleton.ts | 13 ++-- .../src/shell/type/widget-base-config.ts | 20 +++++- 19 files changed, 188 insertions(+), 99 deletions(-) diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index 737a9fa26c..e1d25bdfff 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -2,7 +2,7 @@ /* eslint-disable max-len */ import { StrictEventEmitter } from 'strict-event-emitter-types'; import { EventEmitter } from 'events'; -import { EventBus } from './event-bus'; +import { EventBus, IEventBus } from './event-bus'; import { IPublicModelEditor, EditorConfig, @@ -52,15 +52,18 @@ export declare interface Editor extends StrictEventEmitter<EventEmitter, GlobalE eventNames(): Array<string | symbol>; } +export interface IEditor extends IPublicModelEditor { + config?: EditorConfig; + + components?: PluginClassSet; + + eventBus: IEventBus; + + init(config?: EditorConfig, components?: PluginClassSet): Promise<any>; +} + // eslint-disable-next-line no-redeclare -export class Editor extends (EventEmitter as any) implements IPublicModelEditor { - constructor(readonly viewName: string = 'global', readonly workspaceMode: boolean = false) { - // eslint-disable-next-line constructor-super - super(); - // set global emitter maxListeners - this.setMaxListeners(200); - this.eventBus = new EventBus(this); - } +export class Editor extends EventEmitter implements IEditor { /** * Ioc Container @@ -71,10 +74,32 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor return globalLocale.getLocale(); } + config?: EditorConfig; + + eventBus: EventBus; + + components?: PluginClassSet; + // readonly utils = utils; private hooks: HookConfig[] = []; + private waits = new Map< + IPublicTypeEditorValueKey, + Array<{ + once?: boolean; + resolve: (data: any) => void; + }> + >(); + + constructor(readonly viewName: string = 'global', readonly workspaceMode: boolean = false) { + // eslint-disable-next-line constructor-super + super(); + // set global emitter maxListeners + this.setMaxListeners(200); + this.eventBus = new EventBus(this); + } + get<T = undefined, KeyOrType = any>( keyOrType: KeyOrType, ): IPublicTypeEditorGetResult<T, KeyOrType> | undefined { @@ -202,12 +227,6 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor this.notifyGot(key || data); } - config?: EditorConfig; - - eventBus: EventBus; - - components?: PluginClassSet; - async init(config?: EditorConfig, components?: PluginClassSet): Promise<any> { this.config = config || {}; this.components = components || {}; @@ -270,16 +289,6 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor }); }; - /* eslint-disable */ - private waits = new Map< - IPublicTypeEditorValueKey, - Array<{ - once?: boolean; - resolve: (data: any) => void; - }> - >(); - /* eslint-enable */ - private notifyGot(key: IPublicTypeEditorValueKey) { let waits = this.waits.get(key); if (!waits) { diff --git a/packages/editor-skeleton/src/area.ts b/packages/editor-skeleton/src/area.ts index e96103ad64..8dc711084b 100644 --- a/packages/editor-skeleton/src/area.ts +++ b/packages/editor-skeleton/src/area.ts @@ -3,7 +3,7 @@ import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core'; import { Logger } from '@alilc/lowcode-utils'; import { IPublicTypeWidgetBaseConfig } from '@alilc/lowcode-types'; import { WidgetContainer } from './widget/widget-container'; -import { Skeleton } from './skeleton'; +import { ISkeleton } from './skeleton'; import { IWidget } from './widget/widget'; const logger = new Logger({ level: 'warn', bizName: 'skeleton:area' }); @@ -35,7 +35,9 @@ export class Area<C extends IPublicTypeWidgetBaseConfig = any, T extends IWidget readonly container: WidgetContainer<T, C>; - constructor(readonly skeleton: Skeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent = false) { + private lastCurrent: T | null = null; + + constructor(readonly skeleton: ISkeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent = false) { makeObservable(this); this.container = skeleton.createContainer(name, handle, exclusive, () => this.visible, defaultSetCurrent); } @@ -57,8 +59,6 @@ export class Area<C extends IPublicTypeWidgetBaseConfig = any, T extends IWidget return this.container.remove(config); } - private lastCurrent: T | null = null; - setVisible(flag: boolean) { if (this.exclusive) { const { current } = this.container; diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index 0a70c36c97..46b188acc5 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -92,7 +92,10 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView const { extraProps } = this.field; const { ignoreDefaultValue } = extraProps; try { - return typeof ignoreDefaultValue === 'function' ? ignoreDefaultValue(this.field.internalToShell()) : false; + if (typeof ignoreDefaultValue === 'function') { + return ignoreDefaultValue(this.field.internalToShellField()); + } + return false; } catch (error) { console.error('exception when ignoreDefaultValue is excuted', error); } diff --git a/packages/editor-skeleton/src/components/stage-box/stage-box.tsx b/packages/editor-skeleton/src/components/stage-box/stage-box.tsx index 7be509097f..5015853824 100644 --- a/packages/editor-skeleton/src/components/stage-box/stage-box.tsx +++ b/packages/editor-skeleton/src/components/stage-box/stage-box.tsx @@ -1,10 +1,9 @@ import React, { Component } from 'react'; import classNames from 'classnames'; import { observer } from '@alilc/lowcode-editor-core'; -import { SettingTopEntry, SettingField } from '@alilc/lowcode-designer'; import StageChain from './stage-chain'; import Stage from './stage'; -import { Skeleton } from '../../skeleton'; +import { ISkeleton } from '../../skeleton'; import PopupService, { PopupPipe } from '../popup'; import { Stage as StageWidget } from '../../widget/stage'; @@ -14,9 +13,7 @@ export type StageBoxProps = typeof StageBoxDefaultProps & { stageChain?: StageChain; className?: string; children: React.ReactNode; - skeleton: Skeleton; - // @todo to remove - target?: SettingTopEntry | SettingField; + skeleton: ISkeleton; }; type WillDetachMember = () => void; diff --git a/packages/editor-skeleton/src/context.ts b/packages/editor-skeleton/src/context.ts index ee213e8861..58eb48ac61 100644 --- a/packages/editor-skeleton/src/context.ts +++ b/packages/editor-skeleton/src/context.ts @@ -1,4 +1,4 @@ import { createContext } from 'react'; -import { Skeleton } from './skeleton'; +import { ISkeleton } from './skeleton'; -export const SkeletonContext = createContext<Skeleton>({} as any); +export const SkeletonContext = createContext<ISkeleton>({} as any); diff --git a/packages/editor-skeleton/src/layouts/left-float-pane.tsx b/packages/editor-skeleton/src/layouts/left-float-pane.tsx index f44f602407..0be5ea6c3f 100644 --- a/packages/editor-skeleton/src/layouts/left-float-pane.tsx +++ b/packages/editor-skeleton/src/layouts/left-float-pane.tsx @@ -3,9 +3,10 @@ import classNames from 'classnames'; import { observer, Focusable, focusTracker } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; import { Panel } from '../widget/panel'; +import { PanelConfig } from '../types'; @observer -export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }> { +export default class LeftFloatPane extends Component<{ area: Area<PanelConfig, Panel> }> { private dispose?: () => void; private focusing?: Focusable; diff --git a/packages/editor-skeleton/src/layouts/workbench.tsx b/packages/editor-skeleton/src/layouts/workbench.tsx index e50bec4ec8..1e412ed678 100644 --- a/packages/editor-skeleton/src/layouts/workbench.tsx +++ b/packages/editor-skeleton/src/layouts/workbench.tsx @@ -1,7 +1,7 @@ import { Component } from 'react'; import { TipContainer, observer } from '@alilc/lowcode-editor-core'; import classNames from 'classnames'; -import { Skeleton } from '../skeleton'; +import { ISkeleton } from '../skeleton'; import TopArea from './top-area'; import LeftArea from './left-area'; import LeftFixedPane from './left-fixed-pane'; @@ -16,7 +16,7 @@ import { EditorConfig, PluginClassSet } from '@alilc/lowcode-types'; @observer export class Workbench extends Component<{ - skeleton: Skeleton; + skeleton: ISkeleton; config?: EditorConfig; components?: PluginClassSet; className?: string; diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 22f165b1d9..180859f1d9 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -1,4 +1,4 @@ -import { Editor, action, makeObservable, obx, engineConfig } from '@alilc/lowcode-editor-core'; +import { action, makeObservable, obx, engineConfig, IEditor } from '@alilc/lowcode-editor-core'; import { DockConfig, PanelConfig, @@ -27,6 +27,7 @@ import { IPublicTypeWidgetBaseConfig, IPublicTypeWidgetConfigArea, IPublicTypeSkeletonConfig, + IPublicApiSkeleton, } from '@alilc/lowcode-types'; const logger = new Logger({ level: 'warn', bizName: 'skeleton' }); @@ -42,6 +43,66 @@ export enum SkeletonEvents { WIDGET_ENABLE = 'skeleton.widget.enable', } +export interface ISkeleton extends Omit<IPublicApiSkeleton, + 'showPanel' | + 'hidePanel' | + 'showWidget' | + 'enableWidget' | + 'hideWidget' | + 'disableWidget' | + 'showArea' | + 'onShowPanel' | + 'onHidePanel' | + 'onShowWidget' | + 'onHideWidget' | + 'remove' | + 'hideArea' +> { + editor: IEditor; + + readonly leftArea: Area<DockConfig | PanelDockConfig | DialogDockConfig>; + + readonly topArea: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>; + + readonly subTopArea: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>; + + readonly toolbar: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>; + + readonly leftFixedArea: Area<PanelConfig, Panel>; + + readonly leftFloatArea: Area<PanelConfig, Panel>; + + readonly rightArea: Area<PanelConfig, Panel>; + + readonly mainArea: Area<WidgetConfig | PanelConfig, Widget | Panel>; + + readonly bottomArea: Area<PanelConfig, Panel>; + + readonly stages: Area<StageConfig, Stage>; + + readonly widgets: IWidget[]; + + getPanel(name: string): Panel | undefined; + + getWidget(name: string): IWidget | undefined; + + buildFromConfig(config?: EditorConfig, components?: PluginClassSet): void; + + createStage(config: any): string | undefined; + + getStage(name: string): Stage | null; + + createContainer( + name: string, + handle: (item: any) => any, + exclusive?: boolean, + checkVisible?: () => boolean, + defaultSetCurrent?: boolean, + ): WidgetContainer; + + createPanel(config: PanelConfig): Panel; +} + export class Skeleton { private panels = new Map<string, Panel>(); @@ -69,7 +130,7 @@ export class Skeleton { readonly widgets: IWidget[] = []; - constructor(readonly editor: Editor, readonly viewName: string = 'global') { + constructor(readonly editor: IEditor, readonly viewName: string = 'global') { makeObservable(this); this.leftArea = new Area( this, @@ -244,7 +305,7 @@ export class Skeleton { Object.keys(plugins).forEach((area) => { plugins[area].forEach((item) => { const { pluginKey, type, props = {}, pluginProps } = item; - const config: Partial<IPublicTypeWidgetBaseConfig> = { + const config: IPublicTypeWidgetBaseConfig = { area: area as IPublicTypeWidgetConfigArea, type: 'Widget', name: pluginKey, @@ -272,7 +333,7 @@ export class Skeleton { if (pluginKey in components) { config.content = components[pluginKey]; } - this.add(config as IPublicTypeWidgetBaseConfig); + this.add(config); }); }); } diff --git a/packages/editor-skeleton/src/transducers/parse-func.ts b/packages/editor-skeleton/src/transducers/parse-func.ts index d6e83667a7..b253103504 100644 --- a/packages/editor-skeleton/src/transducers/parse-func.ts +++ b/packages/editor-skeleton/src/transducers/parse-func.ts @@ -4,6 +4,7 @@ import { isPlainObject, isJSFunction, getLogger } from '@alilc/lowcode-utils'; const leadingFnRe = /^function/; const leadingFnNameRe = /^\w+\s*\(/; const logger = getLogger({ level: 'warn', bizName: 'skeleton:transducers' }); + /** * 将函数字符串转成函数,支持几种类型 * 类型一:() => {} / val => {} diff --git a/packages/editor-skeleton/src/types.ts b/packages/editor-skeleton/src/types.ts index a51369f153..b73dc4adce 100644 --- a/packages/editor-skeleton/src/types.ts +++ b/packages/editor-skeleton/src/types.ts @@ -1,12 +1,11 @@ import { ReactElement, ComponentType } from 'react'; import { IPublicTypeTitleContent, - IPublicTypeIconType, IPublicTypeI18nData, - TipContent, IPublicTypeWidgetConfigArea, IPublicTypeWidgetBaseConfig, IPublicTypePanelDockPanelProps, + IPublicTypePanelDockProps, } from '@alilc/lowcode-types'; import { IWidget } from './widget/widget'; @@ -24,13 +23,7 @@ export function isWidgetConfig(obj: any): obj is WidgetConfig { return obj && obj.type === 'Widget'; } -export interface DockProps { - title?: IPublicTypeTitleContent; - icon?: IPublicTypeIconType; - size?: 'small' | 'medium' | 'large'; - className?: string; - description?: TipContent; - onClick?: () => void; +export interface DockProps extends IPublicTypePanelDockProps { } export interface DividerConfig extends IPublicTypeWidgetBaseConfig { diff --git a/packages/editor-skeleton/src/widget/dock.ts b/packages/editor-skeleton/src/widget/dock.ts index 819d5c616f..20cdd425da 100644 --- a/packages/editor-skeleton/src/widget/dock.ts +++ b/packages/editor-skeleton/src/widget/dock.ts @@ -3,7 +3,7 @@ import { makeObservable, obx } from '@alilc/lowcode-editor-core'; import { uniqueId, createContent } from '@alilc/lowcode-utils'; import { getEvent } from '@alilc/lowcode-shell'; import { DockConfig } from '../types'; -import { Skeleton } from '../skeleton'; +import { ISkeleton } from '../skeleton'; import { DockView, WidgetView } from '../components/widget-views'; import { IWidget } from './widget'; @@ -59,7 +59,7 @@ export class Dock implements IWidget { return this._body; } - constructor(readonly skeleton: Skeleton, readonly config: DockConfig) { + constructor(readonly skeleton: ISkeleton, readonly config: DockConfig) { makeObservable(this); const { props = {}, name } = config; this.name = name; diff --git a/packages/editor-skeleton/src/widget/panel-dock.ts b/packages/editor-skeleton/src/widget/panel-dock.ts index f2a56e80c0..896849706a 100644 --- a/packages/editor-skeleton/src/widget/panel-dock.ts +++ b/packages/editor-skeleton/src/widget/panel-dock.ts @@ -1,7 +1,7 @@ import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core'; import { uniqueId } from '@alilc/lowcode-utils'; import { createElement, ReactNode, ReactInstance } from 'react'; -import { Skeleton } from '../skeleton'; +import { ISkeleton } from '../skeleton'; import { PanelDockConfig } from '../types'; import { Panel } from './panel'; import { PanelDockView, WidgetView } from '../components/widget-views'; @@ -18,7 +18,7 @@ export class PanelDock implements IWidget { readonly name: string; - readonly align?: string; + readonly align?: 'left' | 'right' | 'bottom' | 'center' | 'top' | undefined; private inited = false; @@ -51,11 +51,6 @@ export class PanelDock implements IWidget { }); } - getDOMNode() { - // eslint-disable-next-line react/no-find-dom-node - return this._shell ? findDOMNode(this._shell) : null; - } - @obx.ref private _visible = true; get visible() { @@ -76,7 +71,7 @@ export class PanelDock implements IWidget { return this._panel || this.skeleton.getPanel(this.panelName); } - constructor(readonly skeleton: Skeleton, readonly config: PanelDockConfig) { + constructor(readonly skeleton: ISkeleton, readonly config: PanelDockConfig) { makeObservable(this); const { content, contentProps, panelProps, name, props } = config; this.name = name; @@ -84,7 +79,7 @@ export class PanelDock implements IWidget { this.panelName = config.panelName || name; this.align = props?.align; if (content) { - const _panelProps: any = { ...panelProps }; + const _panelProps = { ...panelProps }; if (_panelProps.title == null && props) { _panelProps.title = composeTitle(props.title, undefined, props.description, true, true); } @@ -102,6 +97,11 @@ export class PanelDock implements IWidget { } } + getDOMNode() { + // eslint-disable-next-line react/no-find-dom-node + return this._shell ? findDOMNode(this._shell) : null; + } + setVisible(flag: boolean) { if (flag === this._visible) { return; @@ -170,7 +170,6 @@ export class PanelDock implements IWidget { } } - export function isPanelDock(obj: any): obj is PanelDock { return obj && obj.isPanelDock; } diff --git a/packages/editor-skeleton/src/widget/panel.ts b/packages/editor-skeleton/src/widget/panel.ts index b74c87b948..feec08da7a 100644 --- a/packages/editor-skeleton/src/widget/panel.ts +++ b/packages/editor-skeleton/src/widget/panel.ts @@ -6,7 +6,7 @@ import { WidgetContainer } from './widget-container'; import { getEvent } from '@alilc/lowcode-shell'; import { PanelConfig, HelpTipConfig } from '../types'; import { TitledPanelView, TabsPanelView, PanelView } from '../components/widget-views'; -import { Skeleton } from '../skeleton'; +import { ISkeleton } from '../skeleton'; import { composeTitle } from './utils'; import { IWidget } from './widget'; import { isPanelDock, PanelDock } from './panel-dock'; @@ -80,7 +80,7 @@ export class Panel implements IWidget { @obx.ref public parent?: WidgetContainer; - constructor(readonly skeleton: Skeleton, readonly config: PanelConfig) { + constructor(readonly skeleton: ISkeleton, readonly config: PanelConfig) { makeObservable(this); const { name, content, props = {} } = config; const { hideTitleBar, title, icon, description, help } = props; @@ -111,7 +111,7 @@ export class Panel implements IWidget { props.onInit.call(this, this); } - if (content.onInit) { + if (typeof content !== 'string' && content && content.onInit) { content.onInit.call(this, this); } // todo: process shortcut diff --git a/packages/editor-skeleton/src/widget/stage.ts b/packages/editor-skeleton/src/widget/stage.ts index bd233ad955..2b177af61f 100644 --- a/packages/editor-skeleton/src/widget/stage.ts +++ b/packages/editor-skeleton/src/widget/stage.ts @@ -1,6 +1,6 @@ // import { uniqueId } from '@alilc/lowcode-utils'; import { Widget } from './widget'; -import { Skeleton } from '../skeleton'; +import { ISkeleton } from '../skeleton'; import { WidgetConfig } from '../types'; export interface StageConfig extends WidgetConfig { @@ -17,7 +17,7 @@ export class Stage extends Widget { direction?: 'right' | 'left'; }; - constructor(skeleton: Skeleton, config: StageConfig) { + constructor(skeleton: ISkeleton, config: StageConfig) { super(skeleton, config); this.isRoot = config.isRoot || false; } diff --git a/packages/editor-skeleton/src/widget/utils.ts b/packages/editor-skeleton/src/widget/utils.ts index a5d105969e..c4096d2e26 100644 --- a/packages/editor-skeleton/src/widget/utils.ts +++ b/packages/editor-skeleton/src/widget/utils.ts @@ -3,45 +3,51 @@ import { isI18nData, isTitleConfig } from '@alilc/lowcode-utils'; import { isValidElement } from 'react'; export function composeTitle(title?: IPublicTypeTitleContent, icon?: IPublicTypeIconType, tip?: TipContent, tipAsTitle?: boolean, noIcon?: boolean) { + let _title: IPublicTypeTitleContent | undefined; if (!title) { - title = {}; + _title = {}; if (!icon || tipAsTitle) { - title.label = tip; + _title = { + label: tip, + }; tip = undefined; } + } else { + _title = title; } + if (icon || tip) { - if (typeof title !== 'object' || isValidElement(title) || isI18nData(title)) { - if (isValidElement(title)) { - if (title.type === 'svg' || (title.type as any).getIcon) { + if (typeof _title !== 'object' || isValidElement(_title) || isI18nData(_title)) { + if (isValidElement(_title)) { + if (_title.type === 'svg' || _title.type.getIcon) { if (!icon) { - icon = title as any; + icon = _title; } if (tipAsTitle) { - title = tip as any; + _title = tip; tip = null; } else { - title = undefined; + _title = undefined; } } } - title = { - label: title, + _title = { + label: _title, icon, tip, }; } else { - title = { - ...title, + _title = { + ..._title, icon, tip, }; } } - if (isTitleConfig(title) && noIcon) { + if (isTitleConfig(_title) && noIcon) { if (!isValidElement(title)) { - title.icon = undefined; + _title.icon = undefined; } } - return title; + return _title; } diff --git a/packages/editor-skeleton/src/widget/widget.ts b/packages/editor-skeleton/src/widget/widget.ts index d0df99a1e2..c956738774 100644 --- a/packages/editor-skeleton/src/widget/widget.ts +++ b/packages/editor-skeleton/src/widget/widget.ts @@ -3,7 +3,7 @@ import { makeObservable, obx } from '@alilc/lowcode-editor-core'; import { createContent, uniqueId } from '@alilc/lowcode-utils'; import { getEvent } from '@alilc/lowcode-shell'; import { WidgetConfig } from '../types'; -import { Skeleton } from '../skeleton'; +import { ISkeleton } from '../skeleton'; import { WidgetView } from '../components/widget-views'; import { IPublicTypeTitleContent, IPublicTypeWidgetBaseConfig } from '@alilc/lowcode-types'; @@ -15,7 +15,7 @@ export interface IWidget { readonly visible: boolean; readonly disabled?: boolean; readonly body: ReactNode; - readonly skeleton: Skeleton; + readonly skeleton: ISkeleton; readonly config: IPublicTypeWidgetBaseConfig; getName(): string; @@ -71,7 +71,7 @@ export class Widget implements IWidget { readonly title: IPublicTypeTitleContent; - constructor(readonly skeleton: Skeleton, readonly config: WidgetConfig) { + constructor(readonly skeleton: ISkeleton, readonly config: WidgetConfig) { makeObservable(this); const { props = {}, name } = config; this.name = name; diff --git a/packages/shell/src/api/event.ts b/packages/shell/src/api/event.ts index 746d9ae6ab..0fb41966e7 100644 --- a/packages/shell/src/api/event.ts +++ b/packages/shell/src/api/event.ts @@ -1,4 +1,4 @@ -import { Editor as InnerEditor, EventBus } from '@alilc/lowcode-editor-core'; +import { IEditor, IEventBus } from '@alilc/lowcode-editor-core'; import { getLogger, isPluginEventName } from '@alilc/lowcode-utils'; import { IPublicApiEvent, IPublicTypeDisposable } from '@alilc/lowcode-types'; @@ -11,10 +11,10 @@ type EventOptions = { const eventBusSymbol = Symbol('eventBus'); export class Event implements IPublicApiEvent { - private readonly [eventBusSymbol]: EventBus; + private readonly [eventBusSymbol]: IEventBus; private readonly options: EventOptions; - constructor(eventBus: EventBus, options: EventOptions, public workspaceMode = false) { + constructor(eventBus: IEventBus, options: EventOptions, public workspaceMode = false) { this[eventBusSymbol] = eventBus; this.options = options; if (!this.options.prefix) { @@ -69,6 +69,6 @@ export class Event implements IPublicApiEvent { } } -export function getEvent(editor: InnerEditor, options: any = { prefix: 'common' }) { +export function getEvent(editor: IEditor, options: any = { prefix: 'common' }) { return new Event(editor.eventBus, options); } diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index e9bb283285..928c55a0de 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -1,17 +1,18 @@ import { globalContext } from '@alilc/lowcode-editor-core'; import { - Skeleton as InnerSkeleton, + ISkeleton, SkeletonEvents, } from '@alilc/lowcode-editor-skeleton'; import { skeletonSymbol } from '../symbols'; import { IPublicApiSkeleton, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; const innerSkeletonSymbol = Symbol('skeleton'); + export class Skeleton implements IPublicApiSkeleton { - private readonly [innerSkeletonSymbol]: InnerSkeleton; + private readonly [innerSkeletonSymbol]: ISkeleton; private readonly pluginName: string; - get [skeletonSymbol](): InnerSkeleton { + get [skeletonSymbol](): ISkeleton { if (this.workspaceMode) { return this[innerSkeletonSymbol]; } @@ -24,7 +25,7 @@ export class Skeleton implements IPublicApiSkeleton { } constructor( - skeleton: InnerSkeleton, + skeleton: ISkeleton, pluginName: string, readonly workspaceMode: boolean = false, ) { @@ -57,7 +58,7 @@ export class Skeleton implements IPublicApiSkeleton { if (!normalizeArea(area)) { return; } - skeleton[normalizeArea(area)!].container?.remove(name); + skeleton[normalizeArea(area)].container?.remove(name); } /** @@ -185,7 +186,7 @@ export class Skeleton implements IPublicApiSkeleton { } } -function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined) { +function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea' | 'rightArea' | 'topArea' | 'toolbar' | 'mainArea' | 'bottomArea' | 'leftFixedArea' | 'leftFloatArea' | 'stages' { switch (area) { case 'leftArea': case 'left': diff --git a/packages/types/src/shell/type/widget-base-config.ts b/packages/types/src/shell/type/widget-base-config.ts index 08c14c8db5..8a8cda24f3 100644 --- a/packages/types/src/shell/type/widget-base-config.ts +++ b/packages/types/src/shell/type/widget-base-config.ts @@ -1,4 +1,4 @@ -import { IPublicTypeWidgetConfigArea } from './'; +import { IPublicTypeIconType, IPublicTypeTitleContent, IPublicTypeWidgetConfigArea, TipContent } from './'; export interface IPublicTypeWidgetBaseConfig { [extra: string]: any; @@ -21,6 +21,24 @@ export interface IPublicTypePanelDockConfig extends IPublicTypeWidgetBaseConfig type: 'PanelDock'; panelProps?: IPublicTypePanelDockPanelProps; + + props?: IPublicTypePanelDockProps; +} + +export interface IPublicTypePanelDockProps { + [key: string]: any; + + size?: 'small' | 'medium' | 'large'; + + className?: string; + + description?: TipContent; + + onClick?: () => void; + + icon?: IPublicTypeIconType; + + title?: IPublicTypeTitleContent; } export interface IPublicTypePanelDockPanelProps { From a645af7e0b0ce439548f5573102d8c22f35c4fc0 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 20 Mar 2023 16:01:57 +0800 Subject: [PATCH 061/469] feat: support PanelDock icon pointer cursor is always pointer --- packages/designer/src/designer/dragon.ts | 5 ++- packages/designer/src/plugin/plugin-types.ts | 2 ++ .../src/widgets/tip/tip-container.tsx | 4 +-- .../editor-core/src/widgets/title/index.tsx | 35 +++++++++++-------- .../src/components/widget-views/index.tsx | 20 +++++------ .../src/layouts/workbench.less | 4 +-- packages/shell/src/model/dragon.ts | 17 +++++---- packages/shell/src/model/locate-event.ts | 8 ++--- packages/types/src/shell/model/dragon.ts | 7 ++-- packages/workspace/src/resource.ts | 4 ++- 10 files changed, 61 insertions(+), 45 deletions(-) diff --git a/packages/designer/src/designer/dragon.ts b/packages/designer/src/designer/dragon.ts index a96c1eec23..8dcce2b4a2 100644 --- a/packages/designer/src/designer/dragon.ts +++ b/packages/designer/src/designer/dragon.ts @@ -95,7 +95,10 @@ function isDragEvent(e: any): e is DragEvent { return e?.type?.startsWith('drag'); } -export interface IDragon extends IPublicModelDragon<INode> { +export interface IDragon extends IPublicModelDragon< + INode, + ILocateEvent +> { emitter: IEventBus; } diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index 61855020ef..f76e20827d 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -17,6 +17,7 @@ import { IPublicTypePluginMeta, IPublicTypePluginRegisterOptions, } from '@alilc/lowcode-types'; +import PluginContext from './plugin-context'; export type PluginPreference = Map<string, Record<string, IPublicTypePreferenceValueType>>; @@ -81,6 +82,7 @@ export interface ILowCodePluginManagerCore { delete(pluginName: string): any; setDisabled(pluginName: string, flag: boolean): void; dispose(): void; + _getLowCodePluginContext (options: IPluginContextOptions): PluginContext; } export type ILowCodePluginManager = ILowCodePluginManagerCore & ILowCodePluginManagerPluginAccessor; diff --git a/packages/editor-core/src/widgets/tip/tip-container.tsx b/packages/editor-core/src/widgets/tip/tip-container.tsx index 619c10423e..ed3af589a1 100644 --- a/packages/editor-core/src/widgets/tip/tip-container.tsx +++ b/packages/editor-core/src/widgets/tip/tip-container.tsx @@ -26,13 +26,11 @@ export class TipContainer extends Component { } render() { - ReactDOM.createPortal( + return ReactDOM.createPortal( <div className="lc-tips-container"> <TipItem /> </div>, document.querySelector('body')!, ); - - return null; } } diff --git a/packages/editor-core/src/widgets/title/index.tsx b/packages/editor-core/src/widgets/title/index.tsx index b616ce69d8..88a15ab29b 100644 --- a/packages/editor-core/src/widgets/title/index.tsx +++ b/packages/editor-core/src/widgets/title/index.tsx @@ -1,7 +1,7 @@ import { Component, isValidElement, ReactNode } from 'react'; import classNames from 'classnames'; -import { createIcon, isI18nData } from '@alilc/lowcode-utils'; -import { IPublicTypeTitleContent, IPublicTypeI18nData } from '@alilc/lowcode-types'; +import { createIcon, isI18nData, isTitleConfig } from '@alilc/lowcode-utils'; +import { IPublicTypeTitleContent, IPublicTypeI18nData, IPublicTypeTitleConfig } from '@alilc/lowcode-types'; import { intl } from '../../intl'; import { Tip } from '../tip'; import './title.less'; @@ -88,7 +88,8 @@ export class Title extends Component<{ render() { // eslint-disable-next-line prefer-const - let { title, className } = this.props; + const { title, className } = this.props; + let _title: IPublicTypeTitleConfig; if (title == null) { return null; } @@ -96,34 +97,40 @@ export class Title extends Component<{ return title; } if (typeof title === 'string' || isI18nData(title)) { - title = { label: title }; + _title = { label: title }; + } else if (isTitleConfig(title)) { + _title = title; + } else { + _title = { + label: title, + }; } - const icon = title.icon ? createIcon(title.icon, { size: 20 }) : null; + const icon = _title.icon ? createIcon(_title.icon, { size: 20 }) : null; let tip: any = null; - if (title.tip) { - if (isValidElement(title.tip) && title.tip.type === Tip) { - tip = title.tip; + if (_title.tip) { + if (isValidElement(_title.tip) && _title.tip.type === Tip) { + tip = _title.tip; } else { const tipProps = - typeof title.tip === 'object' && !(isValidElement(title.tip) || isI18nData(title.tip)) - ? title.tip - : { children: title.tip }; + typeof _title.tip === 'object' && !(isValidElement(_title.tip) || isI18nData(_title.tip)) + ? _title.tip + : { children: _title.tip }; tip = <Tip {...tipProps} />; } } return ( <span - className={classNames('lc-title', className, title.className, { + className={classNames('lc-title', className, _title.className, { 'has-tip': !!tip, - 'only-icon': !title.label, + 'only-icon': !_title.label, })} onClick={this.handleClick} > {icon ? <b className="lc-title-icon">{icon}</b> : null} - {this.renderLabel(title.label)} + {this.renderLabel(_title.label)} {tip} </span> ); diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index ba7a3756b4..87f11664c9 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -47,6 +47,8 @@ function HelpTip({ tip }: any) { @observer export class PanelDockView extends Component<DockProps & { dock: PanelDock }> { + private lastActived = false; + componentDidMount() { this.checkActived(); } @@ -55,8 +57,6 @@ export class PanelDockView extends Component<DockProps & { dock: PanelDock }> { this.checkActived(); } - private lastActived = false; - checkActived() { const { dock } = this.props; if (dock.actived !== this.lastActived) { @@ -134,7 +134,7 @@ export class DraggableLineView extends Component<{ panel: Panel }> { // 默认 关闭,通过配置开启 const enableDrag = this.props.panel.config.props?.enableDrag; const isRightArea = this.props.panel.config?.area === 'rightArea'; - if (isRightArea || !enableDrag || this.props.panel?.parent.name === 'leftFixedArea') { + if (isRightArea || !enableDrag || this.props.panel?.parent?.name === 'leftFixedArea') { return null; } return ( @@ -159,6 +159,8 @@ export class DraggableLineView extends Component<{ panel: Panel }> { @observer export class TitledPanelView extends Component<{ panel: Panel; area?: string }> { + private lastVisible = false; + componentDidMount() { this.checkVisible(); } @@ -167,8 +169,6 @@ export class TitledPanelView extends Component<{ panel: Panel; area?: string }> this.checkVisible(); } - private lastVisible = false; - checkVisible() { const { panel } = this.props; const currentVisible = panel.inited && panel.visible; @@ -218,6 +218,8 @@ export class PanelView extends Component<{ hideOperationRow?: boolean; hideDragLine?: boolean; }> { + private lastVisible = false; + componentDidMount() { this.checkVisible(); } @@ -226,8 +228,6 @@ export class PanelView extends Component<{ this.checkVisible(); } - private lastVisible = false; - checkVisible() { const { panel } = this.props; const currentVisible = panel.inited && panel.visible; @@ -331,6 +331,9 @@ class PanelTitle extends Component<{ panel: Panel; className?: string }> { @observer export class WidgetView extends Component<{ widget: IWidget }> { + private lastVisible = false; + private lastDisabled: boolean | undefined = false; + componentDidMount() { this.checkVisible(); this.checkDisabled(); @@ -341,9 +344,6 @@ export class WidgetView extends Component<{ widget: IWidget }> { this.checkDisabled(); } - private lastVisible = false; - private lastDisabled = false; - checkVisible() { const { widget } = this.props; const currentVisible = widget.visible; diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 34018aa86f..f97e1f46f2 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -323,10 +323,8 @@ body { display: flex; align-items: center; justify-content: center; + cursor: pointer; - &.has-tip { - cursor: pointer; - } &.actived { color: #0079f2; } diff --git a/packages/shell/src/model/dragon.ts b/packages/shell/src/model/dragon.ts index 392e3d1582..7f2492e7ea 100644 --- a/packages/shell/src/model/dragon.ts +++ b/packages/shell/src/model/dragon.ts @@ -1,5 +1,7 @@ import { + IDragon, ILocateEvent as InnerLocateEvent, + INode, } from '@alilc/lowcode-designer'; import { dragonSymbol, nodeSymbol } from '../symbols'; import LocateEvent from './locate-event'; @@ -11,18 +13,19 @@ import { IPublicModelDragObject, IPublicTypeDragNodeDataObject, IPublicModelNode, + IPublicTypeDragObject, } from '@alilc/lowcode-types'; export const innerDragonSymbol = Symbol('innerDragonSymbol'); export class Dragon implements IPublicModelDragon { - private readonly [innerDragonSymbol]: IPublicModelDragon; + private readonly [innerDragonSymbol]: IDragon; - constructor(innerDragon: IPublicModelDragon, readonly workspaceMode: boolean) { + constructor(innerDragon: IDragon, readonly workspaceMode: boolean) { this[innerDragonSymbol] = innerDragon; } - get [dragonSymbol](): any { + get [dragonSymbol](): IDragon { if (this.workspaceMode) { return this[innerDragonSymbol]; } @@ -38,7 +41,7 @@ export class Dragon implements IPublicModelDragon { } static create( - dragon: IPublicModelDragon | null, + dragon: IDragon | null, workspaceMode: boolean, ): IPublicModelDragon | null { if (!dragon) { @@ -102,11 +105,13 @@ export class Dragon implements IPublicModelDragon { * @param dragObject 拖拽对象 * @param boostEvent 拖拽初始时事件 */ - boost(dragObject: DragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode): void { + boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: IPublicModelNode & { + [nodeSymbol]: INode; + }): void { return this[dragonSymbol].boost({ ...dragObject, nodes: dragObject.nodes.map((node: any) => node[nodeSymbol]), - }, boostEvent, fromRglNode); + }, boostEvent, fromRglNode?.[nodeSymbol]); } /** diff --git a/packages/shell/src/model/locate-event.ts b/packages/shell/src/model/locate-event.ts index 4c8f955b0b..20451f9462 100644 --- a/packages/shell/src/model/locate-event.ts +++ b/packages/shell/src/model/locate-event.ts @@ -1,16 +1,16 @@ -import { ILocateEvent as InnerLocateEvent } from '@alilc/lowcode-designer'; +import { ILocateEvent } from '@alilc/lowcode-designer'; import { locateEventSymbol } from '../symbols'; import { DragObject } from './drag-object'; import { IPublicModelLocateEvent, IPublicModelDragObject } from '@alilc/lowcode-types'; export default class LocateEvent implements IPublicModelLocateEvent { - private readonly [locateEventSymbol]: InnerLocateEvent; + private readonly [locateEventSymbol]: ILocateEvent; - constructor(locateEvent: InnerLocateEvent) { + constructor(locateEvent: ILocateEvent) { this[locateEventSymbol] = locateEvent; } - static create(locateEvent: InnerLocateEvent): IPublicModelLocateEvent | null { + static create(locateEvent: ILocateEvent): IPublicModelLocateEvent | null { if (!locateEvent) { return null; } diff --git a/packages/types/src/shell/model/dragon.ts b/packages/types/src/shell/model/dragon.ts index 67ddb82c74..662eb6a007 100644 --- a/packages/types/src/shell/model/dragon.ts +++ b/packages/types/src/shell/model/dragon.ts @@ -3,7 +3,8 @@ import { IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type'; import { IPublicModelDragObject, IPublicModelLocateEvent, IPublicModelNode } from './'; export interface IPublicModelDragon< - Node = IPublicModelNode + Node = IPublicModelNode, + LocateEvent = IPublicModelLocateEvent > { /** @@ -18,7 +19,7 @@ export interface IPublicModelDragon< * @param func * @returns */ - onDragstart(func: (e: IPublicModelLocateEvent) => any): () => void; + onDragstart(func: (e: LocateEvent) => any): () => void; /** * 绑定 drag 事件 @@ -26,7 +27,7 @@ export interface IPublicModelDragon< * @param func * @returns */ - onDrag(func: (e: IPublicModelLocateEvent) => any): () => void; + onDrag(func: (e: LocateEvent) => any): () => void; /** * 绑定 dragend 事件 diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index e9033cca76..27b1fdcd14 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -73,7 +73,9 @@ export class Resource implements IResource { constructor(readonly resourceData: IPublicResourceData, readonly resourceType: IResourceType, readonly workspace: IWorkspace) { this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`); - this.resourceTypeInstance = resourceType.resourceTypeModel(this.context.innerPlugins._getLowCodePluginContext(), this.options); + this.resourceTypeInstance = resourceType.resourceTypeModel(this.context.innerPlugins._getLowCodePluginContext({ + pluginName: '', + }), this.options); this.init(); if (this.resourceTypeInstance.editorViews) { this.resourceTypeInstance.editorViews.forEach((d: any) => { From ebe21c4d07d9b2805c524bad0e40d45cc8f12c91 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 21 Mar 2023 17:12:38 +0800 Subject: [PATCH 062/469] feat: resourceList children support different resourceName --- packages/workspace/src/context/base-context.ts | 3 ++- packages/workspace/src/inner-plugins/webview.tsx | 2 +- packages/workspace/src/resource.ts | 5 ++++- packages/workspace/src/view/resource-view.tsx | 8 ++++---- packages/workspace/src/window.ts | 2 ++ packages/workspace/src/workspace.ts | 2 ++ 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index b82e25872a..e74ae2ffb4 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -16,6 +16,7 @@ import { ILowCodePluginManager, } from '@alilc/lowcode-designer'; import { + ISkeleton, Skeleton as InnerSkeleton, } from '@alilc/lowcode-editor-skeleton'; import { @@ -65,7 +66,7 @@ export interface IBasicContext extends Omit<IPublicModelPluginContext, 'workspac designer: IDesigner; registerInnerPlugins: () => Promise<void>; innerSetters: InnerSetters; - innerSkeleton: InnerSkeleton; + innerSkeleton: ISkeleton; innerHotkey: IHotKey; innerPlugins: ILowCodePluginManager; canvas: IPublicApiCanvas; diff --git a/packages/workspace/src/inner-plugins/webview.tsx b/packages/workspace/src/inner-plugins/webview.tsx index de40bb5219..820b843ab8 100644 --- a/packages/workspace/src/inner-plugins/webview.tsx +++ b/packages/workspace/src/inner-plugins/webview.tsx @@ -2,7 +2,7 @@ import { IPublicModelPluginContext } from '@alilc/lowcode-types'; export function DesignerView(props: { url: string; - viewName: string; + viewName?: string; }) { return ( <div className="lc-designer lowcode-plugin-designer"> diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index 27b1fdcd14..10cb7f0a15 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -1,3 +1,4 @@ +import { ISkeleton } from '@alilc/lowcode-editor-skeleton'; import { IPublicTypeEditorView, IPublicResourceData, IPublicResourceTypeConfig, IBaseModelResource } from '@alilc/lowcode-types'; import { Logger } from '@alilc/lowcode-utils'; import { BasicContext, IBasicContext } from './context/base-context'; @@ -9,6 +10,8 @@ const logger = new Logger({ level: 'warn', bizName: 'workspace:resource' }); export interface IBaseResource<T> extends IBaseModelResource<T> { readonly resourceType: ResourceType; + skeleton: ISkeleton; + get editorViews(): IPublicTypeEditorView[]; get defaultViewType(): string; @@ -68,7 +71,7 @@ export class Resource implements IResource { } get children(): IResource[] { - return this.resourceData?.children?.map(d => new Resource(d, this.resourceType, this.workspace)) || []; + return this.resourceData?.children?.map(d => new Resource(d, this.workspace.getResourceType(d.resourceName || this.resourceType.name), this.workspace)) || []; } constructor(readonly resourceData: IPublicResourceData, readonly resourceType: IResourceType, readonly workspace: IWorkspace) { diff --git a/packages/workspace/src/view/resource-view.tsx b/packages/workspace/src/view/resource-view.tsx index 37e960b999..9ef30af092 100644 --- a/packages/workspace/src/view/resource-view.tsx +++ b/packages/workspace/src/view/resource-view.tsx @@ -2,14 +2,14 @@ import { PureComponent } from 'react'; import { EditorView } from './editor-view'; import { observer } from '@alilc/lowcode-editor-core'; import TopArea from '../layouts/top-area'; -import { Resource } from '../resource'; -import { EditorWindow } from '../window'; +import { IResource } from '../resource'; +import { IEditorWindow } from '../window'; import './resource-view.less'; @observer export class ResourceView extends PureComponent<{ - window: EditorWindow; - resource: Resource; + window: IEditorWindow; + resource: IResource; }, any> { render() { const { skeleton } = this.props.resource; diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index 1fa4265241..96707dcb84 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -15,6 +15,8 @@ interface IWindowCOnfig { export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'changeViewType'> { readonly resource: IResource; + editorViews: Map<string, Context>; + changeViewType: (name: string, ignoreEmit?: boolean) => void; } diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 526e1f2ca1..24c81cc797 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -27,6 +27,8 @@ export interface IWorkspace extends Omit<IPublicApiWorkspace< plugins: ILowCodePluginManager; getResourceList(): IResource[]; + + getResourceType(resourceName: string): IResourceType; } export class Workspace implements IWorkspace { From 06aaef777dbdd45850c26e9a8a4b808cdf9ae03f Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 21 Mar 2023 19:14:44 +0800 Subject: [PATCH 063/469] fix: fixed an issue where the outline tree was not displayed correctly when deleting a node --- .../designer/src/document/document-model.ts | 8 +++--- packages/designer/src/document/node/node.ts | 9 ++++-- .../src/controllers/tree.ts | 21 +++----------- .../src/views/tree-branches.tsx | 10 ++++--- .../src/views/tree-node.tsx | 28 +++++++++++++++---- packages/shell/src/model/document-model.ts | 2 +- 6 files changed, 44 insertions(+), 34 deletions(-) diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 2731aa5e6a..63b1a45dde 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -342,18 +342,18 @@ export class DocumentModel implements IDocumentModel { } onChangeNodeVisible(fn: (node: INode, visible: boolean) => void): IPublicTypeDisposable { - this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_CHILDREN_CHANGE, fn); + this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_VISIBLE_CHANGE, fn); return () => { - this.designer.editor?.eventBus.off(EDITOR_EVENT.NODE_CHILDREN_CHANGE, fn); + this.designer.editor?.eventBus.off(EDITOR_EVENT.NODE_VISIBLE_CHANGE, fn); }; } onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions<INode>) => void): IPublicTypeDisposable { - this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_VISIBLE_CHANGE, fn); + this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_CHILDREN_CHANGE, fn); return () => { - this.designer.editor?.eventBus.off(EDITOR_EVENT.NODE_VISIBLE_CHANGE, fn); + this.designer.editor?.eventBus.off(EDITOR_EVENT.NODE_CHILDREN_CHANGE, fn); }; } diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index d8b371ddf4..df4e30c6fc 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -98,11 +98,11 @@ export interface IBaseNode<Schema extends IPublicTypeNodeSchema = IPublicTypeNod /** * 导出 schema */ - export<T = IPublicTypeNodeSchema>(stage: IPublicEnumTransformStage, options?: any): T; + export<T = Schema>(stage: IPublicEnumTransformStage, options?: any): T; emitPropChange(val: IPublicTypePropChangeOptions): void; - import(data: IPublicTypeNodeSchema, checkId?: boolean): void; + import(data: Schema, checkId?: boolean): void; internalSetSlotFor(slotFor: Prop | null | undefined): void; @@ -394,7 +394,10 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> editor?.eventBus.emit(EDITOR_EVENT.NODE_VISIBLE_CHANGE, this, visible); }); this.onChildrenChange((info?: { type: string; node: INode }) => { - editor?.eventBus.emit(EDITOR_EVENT.NODE_VISIBLE_CHANGE, info); + editor?.eventBus.emit(EDITOR_EVENT.NODE_CHILDREN_CHANGE, { + type: info?.type, + node: this, + }); }); } diff --git a/packages/plugin-outline-pane/src/controllers/tree.ts b/packages/plugin-outline-pane/src/controllers/tree.ts index 2256d45d93..be44db2f65 100644 --- a/packages/plugin-outline-pane/src/controllers/tree.ts +++ b/packages/plugin-outline-pane/src/controllers/tree.ts @@ -20,23 +20,10 @@ export class Tree { const doc = this.pluginContext.project.currentDocument; this.id = doc?.id; - doc?.onMountNode((payload: {node: IPublicModelNode }) => { - const { node } = payload; - const parentNode = node.parent; - if (!parentNode) { - return; - } - const parentTreeNode = this.getTreeNodeById(parentNode.id); - parentTreeNode?.notifyExpandableChanged(); - }); - - doc?.onRemoveNode((node: IPublicModelNode) => { - const parentNode = node.parent; - if (!parentNode) { - return; - } - const parentTreeNode = this.getTreeNodeById(parentNode.id); - parentTreeNode?.notifyExpandableChanged(); + doc?.onChangeNodeChildren((info: {node: IPublicModelNode }) => { + const { node } = info; + const treeNode = this.getTreeNodeById(node.id); + treeNode?.notifyExpandableChanged(); }); } diff --git a/packages/plugin-outline-pane/src/views/tree-branches.tsx b/packages/plugin-outline-pane/src/views/tree-branches.tsx index abbc5a840c..210fe0af85 100644 --- a/packages/plugin-outline-pane/src/views/tree-branches.tsx +++ b/packages/plugin-outline-pane/src/views/tree-branches.tsx @@ -9,6 +9,7 @@ export default class TreeBranches extends PureComponent<{ isModal?: boolean; pluginContext: IPublicModelPluginContext; expanded: boolean; + treeChildren: TreeNode[] | null; }> { state = { filterWorking: false, @@ -56,13 +57,13 @@ export default class TreeBranches extends PureComponent<{ treeNode={treeNode} isModal={isModal || false} pluginContext={this.props.pluginContext} + treeChildren={this.props.treeChildren} /> </div> ); } } - interface ITreeNodeChildrenState { filterWorking: boolean; matchSelf: boolean; @@ -73,6 +74,7 @@ class TreeNodeChildren extends PureComponent<{ treeNode: TreeNode; isModal?: boolean; pluginContext: IPublicModelPluginContext; + treeChildren: TreeNode[] | null; }, ITreeNodeChildrenState> { state: ITreeNodeChildrenState = { filterWorking: false, @@ -115,7 +117,7 @@ class TreeNodeChildren extends PureComponent<{ } render() { - const { treeNode, isModal } = this.props; + const { isModal } = this.props; const children: any = []; let groupContents: any[] = []; let currentGrp: IPublicModelExclusiveGroup; @@ -150,7 +152,7 @@ class TreeNodeChildren extends PureComponent<{ })} /> ); - treeNode.children?.forEach((child, index) => { + this.props.treeChildren?.forEach((child, index) => { const childIsModal = child.node.componentMeta?.isModal || false; if (isModal != childIsModal) { return; @@ -178,7 +180,7 @@ class TreeNodeChildren extends PureComponent<{ } }); endGroup(); - const length = treeNode.children?.length || 0; + const length = this.props.treeChildren?.length || 0; if (dropIndex != null && dropIndex >= length) { children.push(insertion); } diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx index 1531eaf635..712dc20fac 100644 --- a/packages/plugin-outline-pane/src/views/tree-node.tsx +++ b/packages/plugin-outline-pane/src/views/tree-node.tsx @@ -4,7 +4,7 @@ import TreeNode from '../controllers/tree-node'; import TreeTitle from './tree-title'; import TreeBranches from './tree-branches'; import { IconEyeClose } from '../icons/eye-close'; -import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicModelDocumentModel, IPublicTypeDisposable } from '@alilc/lowcode-types'; +import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicTypeDisposable } from '@alilc/lowcode-types'; class ModalTreeNodeView extends PureComponent<{ treeNode: TreeNode; @@ -49,6 +49,7 @@ class ModalTreeNodeView extends PureComponent<{ <div className="tree-pane-modal-content"> <TreeBranches treeNode={rootTreeNode} + treeChildren={rootTreeNode.children} expanded={expanded} isModal pluginContext={this.pluginContext} @@ -65,7 +66,19 @@ export default class TreeNodeView extends PureComponent<{ pluginContext: IPublicModelPluginContext; isRootNode?: boolean; }> { - state = { + state: { + expanded: boolean; + selected: boolean; + hidden: boolean; + locked: boolean; + detecting: boolean; + isRoot: boolean; + highlight: boolean; + dropping: boolean; + conditionFlow: boolean; + expandable: boolean; + treeChildren: TreeNode[] | null; + } = { expanded: false, selected: false, hidden: false, @@ -76,6 +89,7 @@ export default class TreeNodeView extends PureComponent<{ dropping: false, conditionFlow: false, expandable: false, + treeChildren: [], }; eventOffCallbacks: Array<IPublicTypeDisposable | undefined> = []; @@ -95,6 +109,7 @@ export default class TreeNodeView extends PureComponent<{ conditionFlow: treeNode.node.conditionGroup != null, highlight: treeNode.isFocusingNode(), expandable: treeNode.expandable, + treeChildren: treeNode.children, }; } @@ -114,11 +129,13 @@ export default class TreeNodeView extends PureComponent<{ this.setState({ locked }); }); treeNode.onExpandableChanged((expandable: boolean) => { - this.setState({ expandable }); + this.setState({ + expandable, + treeChildren: treeNode.children, + }); }); - this.eventOffCallbacks.push( - doc?.onDropLocationChanged((document: IPublicModelDocumentModel) => { + doc?.onDropLocationChanged(() => { this.setState({ dropping: treeNode.dropDetail?.index != null, }); @@ -210,6 +227,7 @@ export default class TreeNodeView extends PureComponent<{ isModal={false} expanded={this.state.expanded} pluginContext={this.props.pluginContext} + treeChildren={this.state.treeChildren} /> </div> ); diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts index b1015b8de8..b8698ebf74 100644 --- a/packages/shell/src/model/document-model.ts +++ b/packages/shell/src/model/document-model.ts @@ -300,7 +300,7 @@ export class DocumentModel implements IPublicModelDocumentModel { * @param fn */ onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): IPublicTypeDisposable { - return this[documentSymbol].onChangeNodeChildren((info?: IPublicTypeOnChangeOptions) => { + return this[documentSymbol].onChangeNodeChildren((info?: IPublicTypeOnChangeOptions<InnerNode>) => { if (!info) { return; } From 203568ea2de302c578dc1a8dc3dd8e9d389847c0 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Wed, 22 Mar 2023 09:17:06 +0800 Subject: [PATCH 064/469] chore(release): publish 1.1.4 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 10 +++++----- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 67 insertions(+), 67 deletions(-) diff --git a/lerna.json b/lerna.json index b1ce00bbf5..b89c797fc2 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.3", + "version": "1.1.4", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index ec63d191c5..e4516ebe52 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.3", + "version": "1.1.4", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.1.3", - "@alilc/lowcode-types": "1.1.3", - "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.4", + "@alilc/lowcode-types": "1.1.4", + "@alilc/lowcode-utils": "1.1.4", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 87022ad09b..8725765f2f 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.1.3", + "version": "1.1.4", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.3", - "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-types": "1.1.4", + "@alilc/lowcode-utils": "1.1.4", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index d799bb68ba..dfc83d116a 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.1.3", + "version": "1.1.4", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -18,10 +18,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.1.3", - "@alilc/lowcode-editor-core": "1.1.3", - "@alilc/lowcode-types": "1.1.3", - "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-designer": "1.1.4", + "@alilc/lowcode-editor-core": "1.1.4", + "@alilc/lowcode-types": "1.1.4", + "@alilc/lowcode-utils": "1.1.4", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 768b80ffd4..b46349bd59 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.3", + "version": "1.1.4", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.1.3", - "@alilc/lowcode-editor-core": "1.1.3", - "@alilc/lowcode-editor-skeleton": "1.1.3", + "@alilc/lowcode-designer": "1.1.4", + "@alilc/lowcode-editor-core": "1.1.4", + "@alilc/lowcode-editor-skeleton": "1.1.4", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.3", - "@alilc/lowcode-plugin-outline-pane": "1.1.3", - "@alilc/lowcode-shell": "1.1.3", - "@alilc/lowcode-utils": "1.1.3", - "@alilc/lowcode-workspace": "1.1.3", + "@alilc/lowcode-plugin-designer": "1.1.4", + "@alilc/lowcode-plugin-outline-pane": "1.1.4", + "@alilc/lowcode-shell": "1.1.4", + "@alilc/lowcode-utils": "1.1.4", + "@alilc/lowcode-workspace": "1.1.4", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 71ea2b4c0b..40fb88804f 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.3", + "version": "1.1.4", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index ca426b6ebc..683fb14b20 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.1.3", + "version": "1.1.4", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.3", - "@alilc/lowcode-editor-core": "1.1.3", - "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-designer": "1.1.4", + "@alilc/lowcode-editor-core": "1.1.4", + "@alilc/lowcode-utils": "1.1.4", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index ff05813c4f..c71657bdc8 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.1.3", + "version": "1.1.4", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,10 +13,10 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-designer": "1.1.3", - "@alilc/lowcode-editor-core": "1.1.3", - "@alilc/lowcode-types": "1.1.3", - "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-designer": "1.1.4", + "@alilc/lowcode-editor-core": "1.1.4", + "@alilc/lowcode-types": "1.1.4", + "@alilc/lowcode-utils": "1.1.4", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 50209be4ed..759c1e2f95 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.1.3", + "version": "1.1.4", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.1.3", - "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-renderer-core": "1.1.4", + "@alilc/lowcode-utils": "1.1.4", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index e5b08717da..25c99408b2 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.1.3", + "version": "1.1.4", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.3", - "@alilc/lowcode-rax-renderer": "1.1.3", - "@alilc/lowcode-types": "1.1.3", - "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-designer": "1.1.4", + "@alilc/lowcode-rax-renderer": "1.1.4", + "@alilc/lowcode-types": "1.1.4", + "@alilc/lowcode-utils": "1.1.4", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index b897eea682..2f2e74b150 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.1.3", + "version": "1.1.4", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.1.3" + "@alilc/lowcode-renderer-core": "1.1.4" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 49c991f2ac..faa2a0ca83 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.1.3", + "version": "1.1.4", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.3", - "@alilc/lowcode-react-renderer": "1.1.3", - "@alilc/lowcode-types": "1.1.3", - "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-designer": "1.1.4", + "@alilc/lowcode-react-renderer": "1.1.4", + "@alilc/lowcode-types": "1.1.4", + "@alilc/lowcode-utils": "1.1.4", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index aa1c7d2046..547385edfa 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.1.3", + "version": "1.1.4", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.1.3", - "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-types": "1.1.4", + "@alilc/lowcode-utils": "1.1.4", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-designer": "1.1.4", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 7608df5f5d..04ddc611c5 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.3", + "version": "1.1.4", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,12 +15,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.3", - "@alilc/lowcode-editor-core": "1.1.3", - "@alilc/lowcode-editor-skeleton": "1.1.3", - "@alilc/lowcode-types": "1.1.3", - "@alilc/lowcode-utils": "1.1.3", - "@alilc/lowcode-workspace": "1.1.3", + "@alilc/lowcode-designer": "1.1.4", + "@alilc/lowcode-editor-core": "1.1.4", + "@alilc/lowcode-editor-skeleton": "1.1.4", + "@alilc/lowcode-types": "1.1.4", + "@alilc/lowcode-utils": "1.1.4", + "@alilc/lowcode-workspace": "1.1.4", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 351c0311d2..edabf93d24 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.3", + "version": "1.1.4", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 4f391d23c4..bb3fecc887 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.3", + "version": "1.1.4", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-types": "1.1.4", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index ef80c7d671..12404ba181 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.3", + "version": "1.1.4", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.3", - "@alilc/lowcode-editor-core": "1.1.3", - "@alilc/lowcode-editor-skeleton": "1.1.3", - "@alilc/lowcode-types": "1.1.3", - "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-designer": "1.1.4", + "@alilc/lowcode-editor-core": "1.1.4", + "@alilc/lowcode-editor-skeleton": "1.1.4", + "@alilc/lowcode-types": "1.1.4", + "@alilc/lowcode-utils": "1.1.4", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 4ddff259f8e7ffaabade44309b75317a0b91d5ff Mon Sep 17 00:00:00 2001 From: AndyJin <jjj706@163.com> Date: Thu, 23 Mar 2023 16:13:26 +0800 Subject: [PATCH 065/469] fix: optimize interface type export --- packages/workspace/src/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/workspace/src/index.ts b/packages/workspace/src/index.ts index 157219e9f2..1f3b77a7aa 100644 --- a/packages/workspace/src/index.ts +++ b/packages/workspace/src/index.ts @@ -1,4 +1,6 @@ -export { Workspace, IWorkspace } from './workspace'; +export { Workspace } from './workspace'; +export type { IWorkspace } from './workspace'; export * from './window'; export * from './layouts/workbench'; -export { Resource, IResource } from './resource'; +export { Resource } from './resource'; +export type { IResource } from './resource'; From 33289bae9cc39581c22e09f62fb1b536f9dc09b5 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 24 Mar 2023 09:00:54 +0800 Subject: [PATCH 066/469] chore(docs): publish 1.0.22 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index e2ffbd0359..137cba035c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.21", + "version": "1.0.22", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From fc964ec7156f7598ead2a568c4c315fbb1264d2f Mon Sep 17 00:00:00 2001 From: Justin-lu <gdjyluxiaoyong@gmail.com> Date: Thu, 23 Mar 2023 10:51:38 +0800 Subject: [PATCH 067/469] fix: ts interface error --- packages/designer/src/designer/detecting.ts | 6 ++--- packages/designer/src/designer/location.ts | 4 ++-- .../src/designer/setting/setting-field.ts | 12 ++++++---- .../designer/setting/setting-prop-entry.ts | 2 +- .../src/designer/setting/setting-top-entry.ts | 2 +- .../designer/src/document/document-model.ts | 23 +++++++++++-------- .../src/document/node/exclusive-group.ts | 2 +- packages/designer/src/document/node/node.ts | 9 ++++---- .../designer/src/document/node/props/prop.ts | 5 ++-- .../designer/src/document/node/props/props.ts | 3 ++- packages/designer/src/project/project.ts | 17 ++++++++------ packages/shell/src/model/condition-group.ts | 4 ++-- packages/shell/src/model/history.ts | 2 +- packages/workspace/src/workspace.ts | 3 ++- 14 files changed, 53 insertions(+), 41 deletions(-) diff --git a/packages/designer/src/designer/detecting.ts b/packages/designer/src/designer/detecting.ts index 568639c372..a5d898d6e0 100644 --- a/packages/designer/src/designer/detecting.ts +++ b/packages/designer/src/designer/detecting.ts @@ -1,10 +1,10 @@ import { makeObservable, obx, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { IPublicModelDetecting } from '@alilc/lowcode-types'; -import { IDocumentModel } from '../document/document-model'; -import { INode } from '../document/node/node'; +import type { IDocumentModel } from '../document/document-model'; +import type { INode } from '../document/node/node'; const DETECTING_CHANGE_EVENT = 'detectingChange'; -export interface IDetecting extends Omit< IPublicModelDetecting<INode>, +export interface IDetecting extends Omit<IPublicModelDetecting<INode>, 'capture' | 'release' | 'leave' diff --git a/packages/designer/src/designer/location.ts b/packages/designer/src/designer/location.ts index 00ee4681cf..3b9b080cd6 100644 --- a/packages/designer/src/designer/location.ts +++ b/packages/designer/src/designer/location.ts @@ -1,4 +1,4 @@ -import { IDocumentModel, INode } from '../document'; +import type { IDocumentModel, INode } from '../document'; import { ILocateEvent } from './dragon'; import { IPublicModelDropLocation, @@ -98,7 +98,7 @@ function isDocument(elem: any): elem is Document { export function getWindow(elem: Element | Document): Window { return (isDocument(elem) ? elem : elem.ownerDocument!).defaultView!; } -export interface IDropLocation extends Omit< IPublicModelDropLocation, 'target' | 'clone' > { +export interface IDropLocation extends Omit<IPublicModelDropLocation, 'target' | 'clone'> { readonly source: string; diff --git a/packages/designer/src/designer/setting/setting-field.ts b/packages/designer/src/designer/setting/setting-field.ts index 7e91f02ce0..139373c0bf 100644 --- a/packages/designer/src/designer/setting/setting-field.ts +++ b/packages/designer/src/designer/setting/setting-field.ts @@ -6,11 +6,13 @@ import { IPublicTypeFieldExtraProps, IPublicTypeFieldConfig, IPublicTypeCustomView, - IPublicTypeSetValueOptions, IPublicTypeDisposable, IPublicModelSettingField, IBaseModelSettingField, } from '@alilc/lowcode-types'; +import type { + IPublicTypeSetValueOptions, +} from '@alilc/lowcode-types'; import { Transducer } from './utils'; import { ISettingPropEntry, SettingPropEntry } from './setting-prop-entry'; import { computed, obx, makeObservable, action, untracked, intl } from '@alilc/lowcode-editor-core'; @@ -31,10 +33,10 @@ function getSettingFieldCollectorKey(parent: ISettingTopEntry | ISettingField, c } export interface ISettingField extends ISettingPropEntry, Omit<IBaseModelSettingField< -ISettingTopEntry, -ISettingField, -IComponentMeta, -INode + ISettingTopEntry, + ISettingField, + IComponentMeta, + INode >, 'setValue' | 'key' | 'node'> { get items(): Array<ISettingField | IPublicTypeCustomView>; diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts index c061c4c8eb..271ea4f3c9 100644 --- a/packages/designer/src/designer/setting/setting-prop-entry.ts +++ b/packages/designer/src/designer/setting/setting-prop-entry.ts @@ -3,7 +3,7 @@ import { GlobalEvent, IPublicApiSetters, IPublicModelEditor, IPublicModelSetting import { uniqueId, isJSExpression } from '@alilc/lowcode-utils'; import { ISettingEntry } from './setting-entry-type'; import { INode } from '../../document'; -import { IComponentMeta } from '../../component-meta'; +import type { IComponentMeta } from '../../component-meta'; import { IDesigner } from '../designer'; import { ISettingTopEntry } from './setting-top-entry'; import { ISettingField, isSettingField } from './setting-field'; diff --git a/packages/designer/src/designer/setting/setting-top-entry.ts b/packages/designer/src/designer/setting/setting-top-entry.ts index 62efd5f539..f89ff8a62b 100644 --- a/packages/designer/src/designer/setting/setting-top-entry.ts +++ b/packages/designer/src/designer/setting/setting-top-entry.ts @@ -4,7 +4,7 @@ import { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor import { ISettingEntry } from './setting-entry-type'; import { ISettingField, SettingField } from './setting-field'; import { INode } from '../../document'; -import { IComponentMeta } from '../../component-meta'; +import type { IComponentMeta } from '../../component-meta'; import { IDesigner } from '../designer'; import { Setters } from '@alilc/lowcode-shell'; diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 63b1a45dde..c55e7a8e47 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -11,7 +11,6 @@ import { import { IPublicTypeNodeData, IPublicTypeNodeSchema, - IPublicTypeRootSchema, IPublicTypePageSchema, IPublicTypeComponentsMap, IPublicTypeDragNodeObject, @@ -21,7 +20,10 @@ import { IPublicTypeOnChangeOptions, IPublicTypeDisposable, } from '@alilc/lowcode-types'; -import { +import type { + IPublicTypeRootSchema, +} from '@alilc/lowcode-types'; +import type { IDropLocation, } from '@alilc/lowcode-designer'; import { @@ -37,9 +39,10 @@ import { } from '@alilc/lowcode-utils'; import { IProject } from '../project'; import { ISimulatorHost } from '../simulator'; -import { IComponentMeta } from '../component-meta'; +import type { IComponentMeta } from '../component-meta'; import { IDesigner, IHistory } from '../designer'; -import { insertChildren, insertChild, IRootNode, INode } from './node/node'; +import { insertChildren, insertChild, IRootNode } from './node/node'; +import type { INode } from './node/node'; import { Selection, ISelection } from './selection'; import { History } from './history'; import { IModalNodesManager, ModalNodesManager, Node } from './node'; @@ -49,11 +52,11 @@ export type GetDataType<T, NodeType> = T extends undefined ? NodeType extends { schema: infer R; } - ? R - : any + ? R + : any : T; -export interface IDocumentModel extends Omit< IPublicModelDocumentModel< +export interface IDocumentModel extends Omit<IPublicModelDocumentModel< ISelection, IHistory, INode, @@ -656,9 +659,9 @@ export class DocumentModel implements IDocumentModel { } checkNesting( - dropTarget: INode, - dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject, - ): boolean { + dropTarget: INode, + dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject, + ): boolean { let items: Array<INode | IPublicTypeNodeSchema>; if (isDragNodeDataObject(dragObject)) { items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data]; diff --git a/packages/designer/src/document/node/exclusive-group.ts b/packages/designer/src/document/node/exclusive-group.ts index d8c14cedb5..9f57b12fc7 100644 --- a/packages/designer/src/document/node/exclusive-group.ts +++ b/packages/designer/src/document/node/exclusive-group.ts @@ -1,7 +1,7 @@ import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core'; import { uniqueId } from '@alilc/lowcode-utils'; import { IPublicTypeTitleContent, IPublicModelExclusiveGroup } from '@alilc/lowcode-types'; -import { INode } from './node'; +import type { INode } from './node'; import { intl } from '../../locale'; export interface IExclusiveGroup extends IPublicModelExclusiveGroup<INode> { diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index df4e30c6fc..4ff300f36a 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -21,11 +21,12 @@ import { import { compatStage, isDOMText, isJSExpression, isNode, isNodeSchema } from '@alilc/lowcode-utils'; import { ISettingTopEntry } from '@alilc/lowcode-designer'; import { Props, getConvertedExtraKey, IProps } from './props/props'; -import { IDocumentModel } from '../document-model'; +import type { IDocumentModel } from '../document-model'; import { NodeChildren, INodeChildren } from './node-children'; import { IProp, Prop } from './props/prop'; -import { IComponentMeta } from '../../component-meta'; -import { ExclusiveGroup, IExclusiveGroup, isExclusiveGroup } from './exclusive-group'; +import type { IComponentMeta } from '../../component-meta'; +import { ExclusiveGroup, isExclusiveGroup } from './exclusive-group'; +import type { IExclusiveGroup } from './exclusive-group'; import { includeSlot, removeSlot } from '../../utils/slot'; import { foreachReverse } from '../../utils/tree'; import { NodeRemoveOptions, EDITOR_EVENT } from '../../types'; @@ -1095,7 +1096,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> condition(this) !== false : condition !== false; }) - .map((action: IPublicTypeComponentAction) => action.name) || []; + .map((action: IPublicTypeComponentAction) => action.name) || []; return availableActions.indexOf(actionName) >= 0; } diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index a679c28c85..f93f2b6083 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -1,5 +1,6 @@ import { untracked, computed, obx, engineConfig, action, makeObservable, mobx, runInAction } from '@alilc/lowcode-editor-core'; -import { IPublicTypeCompositeValue, GlobalEvent, IPublicTypeJSSlot, IPublicTypeSlotSchema, IPublicEnumTransformStage, IPublicModelProp } from '@alilc/lowcode-types'; +import { GlobalEvent, IPublicEnumTransformStage } from '@alilc/lowcode-types'; +import type { IPublicTypeCompositeValue, IPublicTypeJSSlot, IPublicTypeSlotSchema, IPublicModelProp } from '@alilc/lowcode-types'; import { uniqueId, isPlainObject, hasOwnProperty, compatStage, isJSExpression, isJSSlot, isNodeSchema } from '@alilc/lowcode-utils'; import { valueToSource } from './value-to-source'; import { IProps, IPropParent } from './props'; @@ -13,7 +14,7 @@ export type UNSET = typeof UNSET; export interface IProp extends Omit<IPublicModelProp< INode ->, 'exportSchema' | 'node' > { +>, 'exportSchema' | 'node'> { readonly props: IProps; diff --git a/packages/designer/src/document/node/props/props.ts b/packages/designer/src/document/node/props/props.ts index 23519519b8..09c90849d5 100644 --- a/packages/designer/src/document/node/props/props.ts +++ b/packages/designer/src/document/node/props/props.ts @@ -1,5 +1,6 @@ import { computed, makeObservable, obx, action } from '@alilc/lowcode-editor-core'; -import { IPublicTypePropsMap, IPublicTypePropsList, IPublicTypeCompositeValue, IPublicEnumTransformStage, IBaseModelProps } from '@alilc/lowcode-types'; +import { IPublicTypePropsList, IPublicTypeCompositeValue, IPublicEnumTransformStage, IBaseModelProps } from '@alilc/lowcode-types'; +import type { IPublicTypePropsMap } from '@alilc/lowcode-types'; import { uniqueId, compatStage } from '@alilc/lowcode-utils'; import { Prop, IProp, UNSET } from './prop'; import { INode } from '../node'; diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 3204e5c8b6..3f9a68dc7e 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -1,17 +1,20 @@ import { obx, computed, makeObservable, action, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { IDesigner } from '../designer'; -import { DocumentModel, IDocumentModel, isDocumentModel } from '../document'; +import { DocumentModel, isDocumentModel } from '../document'; +import type { IDocumentModel } from "../document"; import { - IPublicTypeProjectSchema, - IPublicTypeRootSchema, IPublicTypeComponentsMap, IPublicEnumTransformStage, IBaseApiProject, } from '@alilc/lowcode-types'; +import type { + IPublicTypeProjectSchema, + IPublicTypeRootSchema, +} from '@alilc/lowcode-types'; import { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils'; import { ISimulatorHost } from '../simulator'; -export interface IProject extends Omit< IBaseApiProject< +export interface IProject extends Omit<IBaseApiProject< IDocumentModel >, 'simulatorHost' | @@ -146,7 +149,7 @@ export class Project implements IProject { return this.documents.reduce<IPublicTypeComponentsMap>(( componentsMap: IPublicTypeComponentsMap, curDoc: IDocumentModel, - ): IPublicTypeComponentsMap => { + ): IPublicTypeComponentsMap => { const curComponentsMap = curDoc.getComponentsMap(); if (Array.isArray(curComponentsMap)) { curComponentsMap.forEach((item) => { @@ -178,8 +181,8 @@ export class Project implements IProject { * 获取项目整体 schema */ getSchema( - stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save, - ): IPublicTypeProjectSchema { + stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save, + ): IPublicTypeProjectSchema { return { ...this.data, componentsMap: this.getComponentsMap(), diff --git a/packages/shell/src/model/condition-group.ts b/packages/shell/src/model/condition-group.ts index 22b926615a..e2dd316edc 100644 --- a/packages/shell/src/model/condition-group.ts +++ b/packages/shell/src/model/condition-group.ts @@ -1,4 +1,4 @@ -import { IExclusiveGroup } from '@alilc/lowcode-designer'; +import type { IExclusiveGroup } from '@alilc/lowcode-designer'; import { IPublicModelExclusiveGroup, IPublicModelNode } from '@alilc/lowcode-types'; import { conditionGroupSymbol, nodeSymbol } from '../symbols'; import { Node } from './node'; @@ -39,4 +39,4 @@ export class ConditionGroup implements IPublicModelExclusiveGroup { shellConditionGroup[conditionGroupSymbol] = shellConditionGroup; return shellConditionGroup; } -} \ No newline at end of file +} diff --git a/packages/shell/src/model/history.ts b/packages/shell/src/model/history.ts index d16f1e3f86..ddc567aeef 100644 --- a/packages/shell/src/model/history.ts +++ b/packages/shell/src/model/history.ts @@ -1,4 +1,4 @@ -import { IDocumentModel as InnerDocumentModel, IHistory as InnerHistory } from '@alilc/lowcode-designer'; +import type { IDocumentModel as InnerDocumentModel, IHistory as InnerHistory } from '@alilc/lowcode-designer'; import { historySymbol, documentSymbol } from '../symbols'; import { IPublicModelHistory, IPublicTypeDisposable } from '@alilc/lowcode-types'; diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 24c81cc797..d959c55eb8 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -2,7 +2,8 @@ import { IDesigner, ILowCodePluginManager, LowCodePluginManager } from '@alilc/l import { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; import { IPublicApiPlugins, IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types'; import { BasicContext } from './context/base-context'; -import { EditorWindow, IEditorWindow } from './window'; +import { EditorWindow } from './window'; +import type { IEditorWindow } from './window'; import { IResource, Resource } from './resource'; import { IResourceType, ResourceType } from './resource-type'; From 80fc9766b19a762dd5d773cbb12cda128e79a942 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 24 Mar 2023 14:22:30 +0800 Subject: [PATCH 068/469] fix: fix cant change the panel tree item title with prop api --- .../src/controllers/tree-node.ts | 263 +++++++++--------- .../src/controllers/tree.ts | 10 +- 2 files changed, 143 insertions(+), 130 deletions(-) diff --git a/packages/plugin-outline-pane/src/controllers/tree-node.ts b/packages/plugin-outline-pane/src/controllers/tree-node.ts index 1f15405e56..62f373e2aa 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-node.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-node.ts @@ -41,43 +41,22 @@ export default class TreeNode { readonly pluginContext: IPublicModelPluginContext; event = new EventEmitter(); - onFilterResultChanged(fn: () => void): IPublicTypeDisposable { - this.event.on(EVENT_NAMES.filterResultChanged, fn); - return () => { - this.event.off(EVENT_NAMES.filterResultChanged, fn); - } - }; - onExpandedChanged(fn: (expanded: boolean) => void): IPublicTypeDisposable { - this.event.on(EVENT_NAMES.expandedChanged, fn); - return () => { - this.event.off(EVENT_NAMES.expandedChanged, fn); - } - }; - onHiddenChanged(fn: (hidden: boolean) => void): IPublicTypeDisposable { - this.event.on(EVENT_NAMES.hiddenChanged, fn); - return () => { - this.event.off(EVENT_NAMES.hiddenChanged, fn); - } - }; - onLockedChanged(fn: (locked: boolean) => void): IPublicTypeDisposable { - this.event.on(EVENT_NAMES.lockedChanged, fn); - return () => { - this.event.off(EVENT_NAMES.lockedChanged, fn); - } - }; - onTitleLabelChanged(fn: (treeNode: TreeNode) => void): IPublicTypeDisposable { - this.event.on(EVENT_NAMES.titleLabelChanged, fn); + private _node: IPublicModelNode; - return () => { - this.event.off(EVENT_NAMES.titleLabelChanged, fn); - } + readonly tree: Tree; + + private _filterResult: FilterResult = { + filterWorking: false, + matchChild: false, + matchSelf: false, + keywords: '', }; - onExpandableChanged(fn: (expandable: boolean) => void): IPublicTypeDisposable { - this.event.on(EVENT_NAMES.expandableChanged, fn); - return () => { - this.event.off(EVENT_NAMES.expandableChanged, fn); - } - } + + /** + * 默认为折叠状态 + * 在初始化根节点时,设置为展开状态 + */ + private _expanded = false; get id(): string { return this.node.id; @@ -91,11 +70,8 @@ export default class TreeNode { return this.hasChildren() || this.hasSlots() || this.dropDetail?.index != null; } - /** - * 触发 onExpandableChanged 回调 - */ - notifyExpandableChanged(): void { - this.event.emit(EVENT_NAMES.expandableChanged, this.expandable); + get expanded(): boolean { + return this.isRoot(true) || (this.expandable && this._expanded); } /** @@ -110,47 +86,6 @@ export default class TreeNode { return this.node.zLevel; } - isRoot(includeOriginalRoot = false) { - const rootNode = this.pluginContext.project.getCurrentDocument()?.root; - return this.tree.root === this || (includeOriginalRoot && rootNode === this.node); - } - - /** - * 是否是响应投放区 - */ - isResponseDropping(): boolean { - const loc = this.pluginContext.project.getCurrentDocument()?.dropLocation; - if (!loc) { - return false; - } - return loc.target?.id === this.id; - } - - isFocusingNode(): boolean { - const loc = this.pluginContext.project.getCurrentDocument()?.dropLocation; - if (!loc) { - return false; - } - return ( - isLocationChildrenDetail(loc.detail) && loc.detail.focus?.type === 'node' && loc.detail?.focus?.node.id === this.id - ); - } - - /** - * 默认为折叠状态 - * 在初始化根节点时,设置为展开状态 - */ - private _expanded = false; - - get expanded(): boolean { - return this.isRoot(true) || (this.expandable && this._expanded); - } - - setExpanded(value: boolean) { - this._expanded = value; - this.event.emit(EVENT_NAMES.expandedChanged, value); - } - get detecting() { const doc = this.pluginContext.project.currentDocument; return !!(doc?.isDetectingNode(this.node)); @@ -164,23 +99,10 @@ export default class TreeNode { return !cv; } - setHidden(flag: boolean) { - if (this.node.conditionGroup) { - return; - } - this.node.visible = !flag; - this.event.emit(EVENT_NAMES.hiddenChanged, flag); - } - get locked(): boolean { return this.node.isLocked; } - setLocked(flag: boolean) { - this.node.lock(flag); - this.event.emit(EVENT_NAMES.lockedChanged, flag); - } - get selected(): boolean { // TODO: check is dragging const selection = this.pluginContext.project.getCurrentDocument()?.selection; @@ -213,19 +135,6 @@ export default class TreeNode { return this.node.componentName; } - setTitleLabel(label: string) { - const origLabel = this.titleLabel; - if (label === origLabel) { - return; - } - if (label === '') { - this.node.getExtraProp('title', false)?.remove(); - } else { - this.node.getExtraProp('title', true)?.setValue(label); - } - this.event.emit(EVENT_NAMES.titleLabelChanged, this); - } - get icon() { return this.node.componentMeta?.icon; } @@ -247,6 +156,123 @@ export default class TreeNode { return this.node.children?.map((node) => this.tree.getTreeNode(node)) || null; } + get node(): IPublicModelNode { + return this._node; + } + + constructor(tree: Tree, node: IPublicModelNode, pluginContext: IPublicModelPluginContext) { + this.tree = tree; + this.pluginContext = pluginContext; + this._node = node; + } + + setLocked(flag: boolean) { + this.node.lock(flag); + this.event.emit(EVENT_NAMES.lockedChanged, flag); + } + + onFilterResultChanged(fn: () => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.filterResultChanged, fn); + return () => { + this.event.off(EVENT_NAMES.filterResultChanged, fn); + }; + } + onExpandedChanged(fn: (expanded: boolean) => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.expandedChanged, fn); + return () => { + this.event.off(EVENT_NAMES.expandedChanged, fn); + }; + } + onHiddenChanged(fn: (hidden: boolean) => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.hiddenChanged, fn); + return () => { + this.event.off(EVENT_NAMES.hiddenChanged, fn); + }; + } + onLockedChanged(fn: (locked: boolean) => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.lockedChanged, fn); + return () => { + this.event.off(EVENT_NAMES.lockedChanged, fn); + }; + } + + onTitleLabelChanged(fn: (treeNode: TreeNode) => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.titleLabelChanged, fn); + + return () => { + this.event.off(EVENT_NAMES.titleLabelChanged, fn); + }; + } + onExpandableChanged(fn: (expandable: boolean) => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.expandableChanged, fn); + return () => { + this.event.off(EVENT_NAMES.expandableChanged, fn); + }; + } + + /** + * 触发 onExpandableChanged 回调 + */ + notifyExpandableChanged(): void { + this.event.emit(EVENT_NAMES.expandableChanged, this.expandable); + } + + notifyTitleLabelChanged(): void { + this.event.emit(EVENT_NAMES.titleLabelChanged, this.title); + } + + setHidden(flag: boolean) { + if (this.node.conditionGroup) { + return; + } + this.node.visible = !flag; + this.event.emit(EVENT_NAMES.hiddenChanged, flag); + } + + isFocusingNode(): boolean { + const loc = this.pluginContext.project.getCurrentDocument()?.dropLocation; + if (!loc) { + return false; + } + return ( + isLocationChildrenDetail(loc.detail) && loc.detail.focus?.type === 'node' && loc.detail?.focus?.node.id === this.id + ); + } + + setExpanded(value: boolean) { + this._expanded = value; + this.event.emit(EVENT_NAMES.expandedChanged, value); + } + + isRoot(includeOriginalRoot = false) { + const rootNode = this.pluginContext.project.getCurrentDocument()?.root; + return this.tree.root === this || (includeOriginalRoot && rootNode === this.node); + } + + /** + * 是否是响应投放区 + */ + isResponseDropping(): boolean { + const loc = this.pluginContext.project.getCurrentDocument()?.dropLocation; + if (!loc) { + return false; + } + return loc.target?.id === this.id; + } + + setTitleLabel(label: string) { + const origLabel = this.titleLabel; + if (label === origLabel) { + return; + } + if (label === '') { + this.node.getExtraProp('title', false)?.remove(); + } else { + this.node.getExtraProp('title', true)?.setValue(label); + } + this.event.emit(EVENT_NAMES.titleLabelChanged, this); + } + /** * 是否是容器,允许子节点拖入 */ @@ -298,39 +324,18 @@ export default class TreeNode { } } - private _node: IPublicModelNode; - - get node(): IPublicModelNode { - return this._node; - } - - readonly tree: Tree; - - constructor(tree: Tree, node: IPublicModelNode, pluginContext: IPublicModelPluginContext) { - this.tree = tree; - this.pluginContext = pluginContext; - this._node = node; - } - setNode(node: IPublicModelNode) { if (this._node !== node) { this._node = node; } } - private _filterResult: FilterResult = { - filterWorking: false, - matchChild: false, - matchSelf: false, - keywords: '', - }; - get filterReult(): FilterResult { return this._filterResult; } setFilterReult(val: FilterResult) { this._filterResult = val; - this.event.emit(EVENT_NAMES.filterResultChanged) + this.event.emit(EVENT_NAMES.filterResultChanged); } } diff --git a/packages/plugin-outline-pane/src/controllers/tree.ts b/packages/plugin-outline-pane/src/controllers/tree.ts index be44db2f65..c0098794c6 100644 --- a/packages/plugin-outline-pane/src/controllers/tree.ts +++ b/packages/plugin-outline-pane/src/controllers/tree.ts @@ -1,5 +1,5 @@ import TreeNode from './tree-node'; -import { IPublicModelNode, IPublicModelPluginContext } from '@alilc/lowcode-types'; +import { IPublicModelNode, IPublicModelPluginContext, IPublicTypePropChangeOptions } from '@alilc/lowcode-types'; export class Tree { private treeNodesMap = new Map<string, TreeNode>(); @@ -25,6 +25,14 @@ export class Tree { const treeNode = this.getTreeNodeById(node.id); treeNode?.notifyExpandableChanged(); }); + + doc?.onChangeNodeProp((info: IPublicTypePropChangeOptions) => { + const { node, key } = info; + if (key === '___title___') { + const treeNode = this.getTreeNodeById(node.id); + treeNode?.notifyTitleLabelChanged(); + } + }); } setNodeSelected(nodeId: string): void { From 8c073c3c95585ea426d28dbe43d9b58021b74115 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 24 Mar 2023 14:32:51 +0800 Subject: [PATCH 069/469] feat: update props ts defined --- .../designer/src/document/node/props/prop.ts | 52 +++++++++++-------- .../designer/src/document/node/props/props.ts | 35 +++++++------ .../types/src/shell/model/document-model.ts | 2 +- packages/types/src/shell/type/slot-schema.ts | 3 +- 4 files changed, 52 insertions(+), 40 deletions(-) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index f93f2b6083..74e93c1063 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -3,7 +3,8 @@ import { GlobalEvent, IPublicEnumTransformStage } from '@alilc/lowcode-types'; import type { IPublicTypeCompositeValue, IPublicTypeJSSlot, IPublicTypeSlotSchema, IPublicModelProp } from '@alilc/lowcode-types'; import { uniqueId, isPlainObject, hasOwnProperty, compatStage, isJSExpression, isJSSlot, isNodeSchema } from '@alilc/lowcode-utils'; import { valueToSource } from './value-to-source'; -import { IProps, IPropParent } from './props'; +import { IPropParent } from './props'; +import type { IProps } from './props'; import { ISlotNode, INode } from '../node'; // import { TransformStage } from '../transform-stage'; @@ -14,13 +15,14 @@ export type UNSET = typeof UNSET; export interface IProp extends Omit<IPublicModelProp< INode ->, 'exportSchema' | 'node'> { +>, 'exportSchema' | 'node'>, IPropParent { + key: string | number | undefined; readonly props: IProps; readonly owner: INode; - delete(prop: Prop): void; + delete(prop: IProp): void; export(stage: IPublicEnumTransformStage): IPublicTypeCompositeValue; @@ -36,7 +38,15 @@ export interface IProp extends Omit<IPublicModelProp< isUnset(): boolean; - key: string | number | undefined; + purge(): void; + + setupItems(): IProp[] | null; + + get type(): ValueTypes; + + get size(): number; + + get code(): string; } export type ValueTypes = 'unset' | 'literal' | 'map' | 'list' | 'expression' | 'slot'; @@ -126,15 +136,15 @@ export class Prop implements IProp, IPropParent { this._code = code; } - private _slotNode?: INode; + private _slotNode?: INode | null; get slotNode(): INode | null { return this._slotNode || null; } - @obx.shallow private _items: Prop[] | null = null; + @obx.shallow private _items: IProp[] | null = null; - @obx.shallow private _maps: Map<string | number, Prop> | null = null; + @obx.shallow private _maps: Map<string | number, IProp> | null = null; /** * 作为 _maps 的一层缓存机制,主要是复用部分已存在的 Prop,保持响应式关系,比如: @@ -142,15 +152,15 @@ export class Prop implements IProp, IPropParent { * 导致假如外部有 mobx reaction(常见于 observer),此时响应式链路会被打断, * 因为 reaction 监听的是原 Prop(a) 的 _value,而不是新 Prop(a) 的 _value。 */ - private _prevMaps: Map<string | number, Prop> | null = null; + private _prevMaps: Map<string | number, IProp> | null = null; /** * 构造 items 属性,同时构造 maps 属性 */ - private get items(): Prop[] | null { + private get items(): IProp[] | null { if (this._items) return this._items; return runInAction(() => { - let items: Prop[] | null = null; + let items: IProp[] | null = null; if (this._type === 'list') { const data = this._value; data.forEach((item: any, idx: number) => { @@ -160,10 +170,10 @@ export class Prop implements IProp, IPropParent { this._maps = null; } else if (this._type === 'map') { const data = this._value; - const maps = new Map<string, Prop>(); + const maps = new Map<string, IProp>(); const keys = Object.keys(data); for (const key of keys) { - let prop: Prop; + let prop: IProp; if (this._prevMaps?.has(key)) { prop = this._prevMaps.get(key)!; prop.setValue(data[key]); @@ -184,7 +194,7 @@ export class Prop implements IProp, IPropParent { }); } - @computed private get maps(): Map<string | number, Prop> | null { + @computed private get maps(): Map<string | number, IProp> | null { if (!this.items) { return null; } @@ -434,7 +444,7 @@ export class Prop implements IProp, IPropParent { this._slotNode.import(slotSchema); } else { const { owner } = this.props; - this._slotNode = owner.document.createNode<ISlotNode>(slotSchema); + this._slotNode = owner.document?.createNode<ISlotNode>(slotSchema); if (this._slotNode) { owner.addSlot(this._slotNode); this._slotNode.internalSetSlotFor(this); @@ -465,7 +475,7 @@ export class Prop implements IProp, IPropParent { /** * @returns 0: the same 1: maybe & like 2: not the same */ - compare(other: Prop | null): number { + compare(other: IProp | null): number { if (!other || other.isUnset()) { return this.isUnset() ? 0 : 2; } @@ -489,7 +499,7 @@ export class Prop implements IProp, IPropParent { * @param createIfNone 当没有的时候,是否创建一个 */ @action - get(path: string | number, createIfNone = true): Prop | null { + get(path: string | number, createIfNone = true): IProp | null { const type = this._type; if (type !== 'map' && type !== 'list' && type !== 'unset' && !createIfNone) { return null; @@ -548,7 +558,7 @@ export class Prop implements IProp, IPropParent { * 删除项 */ @action - delete(prop: Prop): void { + delete(prop: IProp): void { /* istanbul ignore else */ if (this._items) { const i = this._items.indexOf(prop); @@ -582,7 +592,7 @@ export class Prop implements IProp, IPropParent { * @param force 强制 */ @action - add(value: IPublicTypeCompositeValue, force = false): Prop | null { + add(value: IPublicTypeCompositeValue, force = false): IProp | null { const type = this._type; if (type !== 'list' && type !== 'unset' && !force) { return null; @@ -688,7 +698,7 @@ export class Prop implements IProp, IPropParent { /** * 迭代器 */ - [Symbol.iterator](): { next(): { value: Prop } } { + [Symbol.iterator](): { next(): { value: IProp } } { let index = 0; const { items } = this; const length = items?.length || 0; @@ -712,7 +722,7 @@ export class Prop implements IProp, IPropParent { * 遍历 */ @action - forEach(fn: (item: Prop, key: number | string | undefined) => void): void { + forEach(fn: (item: IProp, key: number | string | undefined) => void): void { const { items } = this; if (!items) { return; @@ -727,7 +737,7 @@ export class Prop implements IProp, IPropParent { * 遍历 */ @action - map<T>(fn: (item: Prop, key: number | string | undefined) => T): T[] | null { + map<T>(fn: (item: IProp, key: number | string | undefined) => T): T[] | null { const { items } = this; if (!items) { return null; diff --git a/packages/designer/src/document/node/props/props.ts b/packages/designer/src/document/node/props/props.ts index 09c90849d5..213592a5de 100644 --- a/packages/designer/src/document/node/props/props.ts +++ b/packages/designer/src/document/node/props/props.ts @@ -2,7 +2,8 @@ import { computed, makeObservable, obx, action } from '@alilc/lowcode-editor-cor import { IPublicTypePropsList, IPublicTypeCompositeValue, IPublicEnumTransformStage, IBaseModelProps } from '@alilc/lowcode-types'; import type { IPublicTypePropsMap } from '@alilc/lowcode-types'; import { uniqueId, compatStage } from '@alilc/lowcode-utils'; -import { Prop, IProp, UNSET } from './prop'; +import { Prop, UNSET } from './prop'; +import type { IProp } from './prop'; import { INode } from '../node'; // import { TransformStage } from '../transform-stage'; @@ -27,23 +28,23 @@ export function getOriginalExtraKey(key: string): string { export interface IPropParent { - readonly props: Props; + readonly props: IProps; readonly owner: INode; get path(): string[]; - delete(prop: Prop): void; + delete(prop: IProp): void; } -export interface IProps extends Omit<IBaseModelProps<IProp>, | 'getExtraProp' | 'getExtraPropValue' | 'setExtraPropValue' | 'node'> { +export interface IProps extends Omit<IBaseModelProps<IProp>, | 'getExtraProp' | 'getExtraPropValue' | 'setExtraPropValue' | 'node'>, IPropParent { /** * 获取 props 对应的 node */ getNode(): INode; - get(path: string, createIfNone?: boolean): Prop | null; + get(path: string, createIfNone?: boolean): IProp | null; export(stage?: IPublicEnumTransformStage): { props?: IPublicTypePropsMap | IPublicTypePropsList; @@ -54,7 +55,7 @@ export interface IProps extends Omit<IBaseModelProps<IProp>, | 'getExtraProp' | purge(): void; - query(path: string, createIfNone: boolean): Prop | null; + query(path: string, createIfNone: boolean): IProp | null; import(value?: IPublicTypePropsMap | IPublicTypePropsList | null, extras?: ExtrasObject): void; } @@ -62,7 +63,7 @@ export interface IProps extends Omit<IBaseModelProps<IProp>, | 'getExtraProp' | export class Props implements IProps, IPropParent { readonly id = uniqueId('props'); - @obx.shallow private items: Prop[] = []; + @obx.shallow private items: IProp[] = []; @computed private get maps(): Map<string, Prop> { const maps = new Map(); @@ -78,7 +79,7 @@ export class Props implements IProps, IPropParent { readonly path = []; - get props(): Props { + get props(): IProps { return this; } @@ -229,7 +230,7 @@ export class Props implements IProps, IPropParent { * @param createIfNone 当没有的时候,是否创建一个 */ @action - query(path: string, createIfNone = true): Prop | null { + query(path: string, createIfNone = true): IProp | null { return this.get(path, createIfNone); } @@ -238,7 +239,7 @@ export class Props implements IProps, IPropParent { * @param createIfNone 当没有的时候,是否创建一个 */ @action - get(path: string, createIfNone = false): Prop | null { + get(path: string, createIfNone = false): IProp | null { let entry = path; let nest = ''; const i = path.indexOf('.'); @@ -266,7 +267,7 @@ export class Props implements IProps, IPropParent { * 删除项 */ @action - delete(prop: Prop): void { + delete(prop: IProp): void { const i = this.items.indexOf(prop); if (i > -1) { this.items.splice(i, 1); @@ -298,7 +299,7 @@ export class Props implements IProps, IPropParent { key?: string | number, spread = false, options: any = {}, - ): Prop { + ): IProp { const prop = new Prop(this, value, key, spread, options); this.items.push(prop); return prop; @@ -314,7 +315,7 @@ export class Props implements IProps, IPropParent { /** * 迭代器 */ - [Symbol.iterator](): { next(): { value: Prop } } { + [Symbol.iterator](): { next(): { value: IProp } } { let index = 0; const { items } = this; const length = items.length || 0; @@ -338,7 +339,7 @@ export class Props implements IProps, IPropParent { * 遍历 */ @action - forEach(fn: (item: Prop, key: number | string | undefined) => void): void { + forEach(fn: (item: IProp, key: number | string | undefined) => void): void { this.items.forEach((item) => { return fn(item, item.key); }); @@ -348,14 +349,14 @@ export class Props implements IProps, IPropParent { * 遍历 */ @action - map<T>(fn: (item: Prop, key: number | string | undefined) => T): T[] | null { + map<T>(fn: (item: IProp, key: number | string | undefined) => T): T[] | null { return this.items.map((item) => { return fn(item, item.key); }); } @action - filter(fn: (item: Prop, key: number | string | undefined) => boolean) { + filter(fn: (item: IProp, key: number | string | undefined) => boolean) { return this.items.filter((item) => { return fn(item, item.key); }); @@ -378,7 +379,7 @@ export class Props implements IProps, IPropParent { * @param createIfNone 当没有的时候,是否创建一个 */ @action - getProp(path: string, createIfNone = true): Prop | null { + getProp(path: string, createIfNone = true): IProp | null { return this.query(path, createIfNone) || null; } diff --git a/packages/types/src/shell/model/document-model.ts b/packages/types/src/shell/model/document-model.ts index b11ac6f085..2ef0b532be 100644 --- a/packages/types/src/shell/model/document-model.ts +++ b/packages/types/src/shell/model/document-model.ts @@ -108,7 +108,7 @@ export interface IPublicModelDocumentModel< * @param data * @returns */ - createNode(data: IPublicTypeNodeSchema): Node | null; + createNode<T = Node>(data: IPublicTypeNodeSchema): T | null; /** * 移除指定节点/节点id diff --git a/packages/types/src/shell/type/slot-schema.ts b/packages/types/src/shell/type/slot-schema.ts index d4c1f5d976..8928a98247 100644 --- a/packages/types/src/shell/type/slot-schema.ts +++ b/packages/types/src/shell/type/slot-schema.ts @@ -1,3 +1,4 @@ +import { IPublicTypeNodeData } from './node-data'; import { IPublicTypeNodeSchema } from './node-schema'; /** @@ -13,5 +14,5 @@ export interface IPublicTypeSlotSchema extends IPublicTypeNodeSchema { slotName?: string; slotParams?: string[]; }; - children?: IPublicTypeNodeSchema[]; + children?: IPublicTypeNodeData[] | IPublicTypeNodeData; } From affdfbbb1cc336361b26be6ffb043bbec6017164 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 24 Mar 2023 15:45:16 +0800 Subject: [PATCH 070/469] fix: fix the problem that the props value appears when the name is 0 --- packages/designer/jest.config.js | 1 + .../designer/setting/setting-prop-entry.ts | 14 +++---- packages/designer/src/document/node/node.ts | 2 +- .../designer/setting/setting-field.test.ts | 40 +++++++++++++++---- packages/types/src/shell/model/node.ts | 4 +- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index 594eb6f365..05347a0c95 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -16,6 +16,7 @@ const jestConfig = { // testMatch: ['**/prop.test.ts'], // testMatch: ['(/tests?/.*(test))\\.[jt]s$'], // testMatch: ['**/document/node/node.add.test.ts'], + // testMatch: ['**/setting-field.test.ts'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts index 271ea4f3c9..d6904f0c82 100644 --- a/packages/designer/src/designer/setting/setting-prop-entry.ts +++ b/packages/designer/src/designer/setting/setting-prop-entry.ts @@ -9,10 +9,10 @@ import { ISettingTopEntry } from './setting-top-entry'; import { ISettingField, isSettingField } from './setting-field'; export interface ISettingPropEntry extends ISettingEntry { - get props(): ISettingTopEntry; - readonly isGroup: boolean; + get props(): ISettingTopEntry; + get name(): string | number | undefined; valueChange(options: IPublicTypeSetValueOptions): void; @@ -75,7 +75,7 @@ export class SettingPropEntry implements ISettingPropEntry { @computed get path() { const path = this.parent.path.slice(); - if (this.type === 'field' && this.name) { + if (this.type === 'field' && this.name?.toString()) { path.push(this.name); } return path; @@ -191,7 +191,7 @@ export class SettingPropEntry implements ISettingPropEntry { */ getValue(): any { let val: any; - if (this.type === 'field' && this.name) { + if (this.type === 'field' && this.name?.toString()) { val = this.parent.getPropValue(this.name); } const { getValue } = this.extraProps; @@ -209,7 +209,7 @@ export class SettingPropEntry implements ISettingPropEntry { setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: IPublicTypeSetValueOptions) { const oldValue = this.getValue(); if (this.type === 'field') { - this.name && this.parent.setPropValue(this.name, val); + this.name?.toString() && this.parent.setPropValue(this.name, val); } const { setValue } = this.extraProps; @@ -233,7 +233,7 @@ export class SettingPropEntry implements ISettingPropEntry { */ clearValue() { if (this.type === 'field') { - this.name && this.parent.clearPropValue(this.name); + this.name?.toString() && this.parent.clearPropValue(this.name); } const { setValue } = this.extraProps; if (setValue) { @@ -395,6 +395,6 @@ export class SettingPropEntry implements ISettingPropEntry { } internalToShellField(): IPublicModelSettingField { - return this.designer!.shellModelFactory.createSettingField(this);; + return this.designer!.shellModelFactory.createSettingField(this); } } diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 4ff300f36a..e1dce17dda 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -155,7 +155,7 @@ export interface IBaseNode<Schema extends IPublicTypeNodeSchema = IPublicTypeNod getChildren(): INodeChildren | null; - clearPropValue(path: string): void; + clearPropValue(path: string | number): void; setProps(props?: IPublicTypePropsMap | IPublicTypePropsList | Props | null): void; diff --git a/packages/designer/tests/designer/setting/setting-field.test.ts b/packages/designer/tests/designer/setting/setting-field.test.ts index 2a5ef4c230..9114d2577a 100644 --- a/packages/designer/tests/designer/setting/setting-field.test.ts +++ b/packages/designer/tests/designer/setting/setting-field.test.ts @@ -65,8 +65,8 @@ describe('setting-field 测试', () => { it('常规方法', () => { // 普通 field - const settingEntry = mockNode.settingEntry as SettingTopEntry; - const field = settingEntry.get('behavior') as SettingField; + const settingEntry = mockNode.settingEntry; + const field = settingEntry.get('behavior'); expect(field.title).toBe('默认状态'); expect(field.expanded).toBeTruthy(); field.setExpanded(false); @@ -103,24 +103,24 @@ describe('setting-field 测试', () => { expect(nonExistingField.setter).toBeNull(); // group 类型的 field - const groupField = settingEntry.get('groupkgzzeo41') as SettingField; + const groupField = settingEntry.get('groupkgzzeo41'); expect(groupField.items).toEqual([]); // 有子节点的 field - const objField = settingEntry.get('obj') as SettingField; + const objField = settingEntry.get('obj'); expect(objField.items).toHaveLength(3); expect(objField.getItems()).toHaveLength(3); expect(objField.getItems(x => x.name === 'a')).toHaveLength(1); objField.purge(); expect(objField.items).toHaveLength(0); - const objAField = settingEntry.get('obj.a') as SettingField; + const objAField = settingEntry.get('obj.a'); expect(objAField.setter).toBe('StringSetter'); }); it('setValue / getValue / setHotValue / getHotValue', () => { // 获取已有的 prop const settingEntry = mockNode.settingEntry as SettingTopEntry; - const field = settingEntry.get('behavior') as SettingField; + const field = settingEntry.get('behavior'); // 会读取 extraProps.defaultValue expect(field.getHotValue()).toBe('NORMAL'); @@ -140,11 +140,37 @@ describe('setting-field 测试', () => { // dirty fix list setter field.setHotValue([{ __sid__: 1 }]); + + // 数组的 field + const arrField = settingEntry.get('arr'); + const subArrField = arrField.createField({ + name: 0, + title: 'sub', + }); + const subArrField02 = arrField.createField({ + name: 1, + title: 'sub', + }); + const subArrField03 = arrField.createField({ + name: '2', + title: 'sub', + }); + subArrField.setValue({name: '1'}); + expect(subArrField.path).toEqual(['arr', 0]); + expect(subArrField02.path).toEqual(['arr', 1]); + subArrField02.setValue({name: '2'}); + expect(subArrField.getValue()).toEqual({name: '1'}); + expect(arrField.getHotValue()).toEqual([{name: '1'}, {name: '2'}]); + subArrField.clearValue(); + expect(subArrField.getValue()).toBeUndefined(); + expect(arrField.getHotValue()).toEqual([undefined, {name: '2'}]); + subArrField03.setValue({name: '3'}); + expect(arrField.getHotValue()).toEqual([undefined, {name: '2'}, {name: '3'}]); }); it('onEffect', async () => { const settingEntry = mockNode.settingEntry as SettingTopEntry; - const field = settingEntry.get('behavior') as SettingField; + const field = settingEntry.get('behavior'); const mockFn = jest.fn(); diff --git a/packages/types/src/shell/model/node.ts b/packages/types/src/shell/model/node.ts index 1cbf63e13f..0255376aec 100644 --- a/packages/types/src/shell/model/node.ts +++ b/packages/types/src/shell/model/node.ts @@ -299,7 +299,7 @@ export interface IBaseModelNode< * @param path 属性路径,支持 a / a.b / a.0 等格式 * @param createIfNone 如果不存在,是否新建,默认为 true */ - getProp(path: string, createIfNone?: boolean): Prop | null; + getProp(path: string | number, createIfNone?: boolean): Prop | null; /** * 获取指定 path 的属性模型实例值 @@ -336,7 +336,7 @@ export interface IBaseModelNode< * @param path 属性路径,支持 a / a.b / a.0 等格式 * @param value 值 */ - setPropValue(path: string, value: IPublicTypeCompositeValue): void; + setPropValue(path: string | number, value: IPublicTypeCompositeValue): void; /** * 设置指定 path 的属性模型实例值 From 3fea312906686f2c6d79da9e9f6e9a27c99a7896 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 24 Mar 2023 16:59:27 +0800 Subject: [PATCH 071/469] feat: update IPublicTypeComponentMetadata interface --- packages/shell/src/api/material.ts | 2 +- packages/types/src/shell/api/material.ts | 2 +- .../src/shell/type/component-metadata.ts | 21 +++++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/shell/src/api/material.ts b/packages/shell/src/api/material.ts index fb12ab8c07..e3ebd20ec5 100644 --- a/packages/shell/src/api/material.ts +++ b/packages/shell/src/api/material.ts @@ -63,7 +63,7 @@ export class Material implements IPublicApiMaterial { * 获取「资产包」结构 * @returns */ - getAssets() { + getAssets(): IPublicTypeAssetsJson | undefined { return this[editorSymbol].get('assets'); } diff --git a/packages/types/src/shell/api/material.ts b/packages/types/src/shell/api/material.ts index 7771aa6baa..1e9f54996b 100644 --- a/packages/types/src/shell/api/material.ts +++ b/packages/types/src/shell/api/material.ts @@ -22,7 +22,7 @@ export interface IPublicApiMaterial { * get AssetsJson data * @returns IPublicTypeAssetsJson */ - getAssets(): IPublicTypeAssetsJson; + getAssets(): IPublicTypeAssetsJson | undefined; /** * 加载增量的「资产包」结构,该增量包会与原有的合并 diff --git a/packages/types/src/shell/type/component-metadata.ts b/packages/types/src/shell/type/component-metadata.ts index 04c4ae0d33..69dc36c309 100644 --- a/packages/types/src/shell/type/component-metadata.ts +++ b/packages/types/src/shell/type/component-metadata.ts @@ -5,74 +5,95 @@ import { IPublicTypeIconType, IPublicTypeNpmInfo, IPublicTypeFieldConfig, IPubli */ export interface IPublicTypeComponentMetadata { + + /** 其他扩展协议 */ + [key: string]: any; + /** * 组件名 */ componentName: string; + /** * unique id */ uri?: string; + /** * title or description */ title?: IPublicTypeTitleContent; + /** * svg icon for component */ icon?: IPublicTypeIconType; + /** * 组件标签 */ tags?: string[]; + /** * 组件描述 */ description?: string; + /** * 组件文档链接 */ docUrl?: string; + /** * 组件快照 */ screenshot?: string; + /** * 组件研发模式 */ devMode?: 'proCode' | 'lowCode'; + /** * npm 源引入完整描述对象 */ npm?: IPublicTypeNpmInfo; + /** * 组件属性信息 */ props?: IPublicTypePropConfig[]; + /** * 编辑体验增强 */ configure?: IPublicTypeFieldConfig[] | IPublicTypeConfigure; + /** * @deprecated, use advanced instead */ experimental?: IPublicTypeAdvanced; + /** * @todo 待补充文档 */ schema?: IPublicTypeComponentSchema; + /** * 可用片段 */ snippets?: IPublicTypeSnippet[]; + /** * 一级分组 */ group?: string | IPublicTypeI18nData; + /** * 二级分组 */ category?: string | IPublicTypeI18nData; + /** * 组件优先级排序 */ From 298ab0f62f4045bbf121908f9c2cfed639768418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Fri, 24 Mar 2023 09:24:21 +0800 Subject: [PATCH 072/469] feat: add code review job by chatgpt --- .github/workflows/pr comment by chatgpt.yml | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/pr comment by chatgpt.yml diff --git a/.github/workflows/pr comment by chatgpt.yml b/.github/workflows/pr comment by chatgpt.yml new file mode 100644 index 0000000000..52585c4778 --- /dev/null +++ b/.github/workflows/pr comment by chatgpt.yml @@ -0,0 +1,23 @@ +name: Pull Request Review By ChatGPT + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + code-review: + name: Code Review + runs-on: ubuntu-latest + + steps: + # 判断用户是否有写仓库权限 + - name: 'Check User Permission' + uses: 'lannonbr/repo-permission-check-action@2.0.0' + with: + permission: 'write' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - uses: opensumi/actions/.github/actions/code-review@main + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} \ No newline at end of file From 3d51fe00bfced9af6f06cd6defdb67e3ebc76e3f Mon Sep 17 00:00:00 2001 From: "knight.chen" <knightchen@knx.com.cn> Date: Sat, 25 Mar 2023 13:16:39 +0800 Subject: [PATCH 073/469] feat: add setConfig method for project --- docs/docs/api/project.md | 29 +++++++++ packages/designer/src/project/project.ts | 61 ++++++------------- packages/shell/src/api/project.ts | 20 ++++++ packages/types/src/shell/api/project.ts | 14 ++++- packages/types/src/shell/type/app-config.ts | 1 - .../types/src/shell/type/project-schema.ts | 4 +- 6 files changed, 81 insertions(+), 48 deletions(-) diff --git a/docs/docs/api/project.md b/docs/docs/api/project.md index 0c7213aaca..e31672e25f 100644 --- a/docs/docs/api/project.md +++ b/docs/docs/api/project.md @@ -252,6 +252,35 @@ 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<T extends keyof IPublicTypeAppConfig>(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 {}; +``` + ## 事件 diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 3f9a68dc7e..0675190b28 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -29,6 +29,7 @@ export interface IProject extends Omit<IBaseApiProject< 'onSimulatorHostReady' | 'onSimulatorRendererReady' | 'setI18n' | + 'setConfig' | 'currentDocument' | 'selection' | 'documents' | @@ -75,21 +76,15 @@ export interface IProject extends Omit<IBaseApiProject< /** * 分字段设置储存数据,不记录操作记录 */ - set( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - key: - | 'version' - | 'componentsTree' - | 'componentsMap' - | 'utils' - | 'constants' - | 'i18n' - | 'css' - | 'dataSource' - | string, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - value: any, - ): void; + set<T extends keyof IPublicTypeProjectSchema>(key: T, value: IPublicTypeProjectSchema[T]): void; + set(key: string, value: unknown): void; + + /** + * 分字段获取储存数据 + */ + get<T extends keyof IPublicTypeProjectSchema>(key: T): IPublicTypeProjectSchema[T]; + get<T>(key: string): T; + get(key: string): unknown; checkExclusive(activeDoc: DocumentModel): void; } @@ -268,21 +263,9 @@ export class Project implements IProject { /** * 分字段设置储存数据,不记录操作记录 */ - set( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - key: - | 'version' - | 'componentsTree' - | 'componentsMap' - | 'utils' - | 'constants' - | 'i18n' - | 'css' - | 'dataSource' - | string, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - value: any, - ): void { + set<T extends keyof IPublicTypeProjectSchema>(key: T, value: IPublicTypeProjectSchema[T]): void; + set(key: string, value: unknown): void; + set(key: string, value: unknown): void { if (key === 'config') { this.config = value; } @@ -295,20 +278,10 @@ export class Project implements IProject { /** * 分字段设置储存数据 */ - get( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - key: - | 'version' - | 'componentsTree' - | 'componentsMap' - | 'utils' - | 'constants' - | 'i18n' - | 'css' - | 'dataSource' - | 'config' - | string, - ): any { + get<T extends keyof IPublicTypeRootSchema>(key: T): IPublicTypeRootSchema[T]; + get<T>(key: string): T; + get(key: string): unknown; + get(key: string): any { if (key === 'config') { return this.config; } diff --git a/packages/shell/src/api/project.ts b/packages/shell/src/api/project.ts index a409cbcd57..ed45701b3c 100644 --- a/packages/shell/src/api/project.ts +++ b/packages/shell/src/api/project.ts @@ -13,6 +13,7 @@ import { IPublicTypePropsTransducer, IPublicEnumTransformStage, IPublicTypeDisposable, + IPublicTypeAppConfig, } from '@alilc/lowcode-types'; import { DocumentModel as ShellDocumentModel } from '../model'; import { SimulatorHost } from './simulator-host'; @@ -216,4 +217,23 @@ export class Project implements IPublicApiProject { setI18n(value: object): void { this[projectSymbol].set('i18n', value); } + + /** + * 设置项目配置 + * @param value object + * @returns + */ + setConfig<T extends keyof IPublicTypeAppConfig>(key: T, value: IPublicTypeAppConfig[T]): void; + setConfig(value: IPublicTypeAppConfig): void; + setConfig(...params: any[]): void{ + if(params.length === 2) { + const oldConfig = this[projectSymbol].get('config'); + this[projectSymbol].set('config', { + ...oldConfig, + [params[0]]: params[1], + }) + } else { + this[projectSymbol].set('config', params[0]) + } + } } diff --git a/packages/types/src/shell/api/project.ts b/packages/types/src/shell/api/project.ts index baea41b948..662f302ccc 100644 --- a/packages/types/src/shell/api/project.ts +++ b/packages/types/src/shell/api/project.ts @@ -1,4 +1,4 @@ -import { IPublicTypeProjectSchema, IPublicTypeDisposable, IPublicTypeRootSchema, IPublicTypePropsTransducer } from '../type'; +import { IPublicTypeProjectSchema, IPublicTypeDisposable, IPublicTypeRootSchema, IPublicTypePropsTransducer, IPublicTypeAppConfig } from '../type'; import { IPublicEnumTransformStage } from '../enum'; import { IPublicApiSimulatorHost } from './'; import { IPublicModelDocumentModel } from '../model'; @@ -132,6 +132,16 @@ export interface IBaseApiProject< * @since v1.0.17 */ setI18n(value: object): void; + + /** + * 设置当前项目配置 + * + * set config data for this project + * @param value object + * @since v1.1.4 + */ + setConfig<T extends keyof IPublicTypeAppConfig>(key: T, value: IPublicTypeAppConfig[T]): void; + setConfig(value: IPublicTypeAppConfig): void; } -export interface IPublicApiProject extends IBaseApiProject<IPublicModelDocumentModel> {} \ No newline at end of file +export interface IPublicApiProject extends IBaseApiProject<IPublicModelDocumentModel> {} diff --git a/packages/types/src/shell/type/app-config.ts b/packages/types/src/shell/type/app-config.ts index 370defaa60..2bcb5f47a9 100644 --- a/packages/types/src/shell/type/app-config.ts +++ b/packages/types/src/shell/type/app-config.ts @@ -4,7 +4,6 @@ export interface IPublicTypeAppConfig { targetRootID?: string; layout?: IPublicTypeLayout; theme?: IPublicTypeTheme; - [key: string]: any; } interface IPublicTypeTheme { diff --git a/packages/types/src/shell/type/project-schema.ts b/packages/types/src/shell/type/project-schema.ts index 66a5aaa8a2..271841bfb3 100644 --- a/packages/types/src/shell/type/project-schema.ts +++ b/packages/types/src/shell/type/project-schema.ts @@ -57,8 +57,10 @@ export interface IPublicTypeProjectSchema<T = IPublicTypeRootSchema> { dataSource?: DataSource; /** * 当前应用配置信息 + * + * TODO: 需要在后续版本中移除 `Record<string, unknown>` 类型签名 */ - config?: IPublicTypeAppConfig | Record<string, any>; + config?: IPublicTypeAppConfig & Record<string, unknown>; /** * 当前应用元数据信息 */ From a5f45e939774868844f4f2241b976283bd92a710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 27 Mar 2023 11:22:58 +0800 Subject: [PATCH 074/469] docs: update article list --- docs/docs/article/index.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index 5a065e9971..44823653a8 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -3,17 +3,17 @@ title: 低代码引擎相关文章资料 --- ## 官方文章 - -- [基于 LowCodeEngine 的低代码组件体系的建设和实践](https://mp.weixin.qq.com/s/rnvbGHImGt6oJuX2wCtaqw) -- [低代码多分支协同开发的建设与实践](https://mp.weixin.qq.com/s/DmwxL67htHfTUP1U966N-Q) -- [低代码引擎半岁啦,来跟大家唠唠嗑...](https://segmentfault.com/a/1190000042884409) -- [低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ) -- [关于 LowCode&ProCode 混合研发的思考](https://mp.weixin.qq.com/s/TY3VXjkSmsQoT47xma3wig) -- [低代码渲染那些事](https://mp.weixin.qq.com/s/yqYey76qLGYPfDtpGkVFfA) -- [阿里低代码引擎和生态建设实战及思考](https://mp.weixin.qq.com/s/MI6MrUKKydtnSdO4xq6jwA) -- [磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw) -- [2B 领域下的低代码探索之路](https://mp.weixin.qq.com/s/HAxrMHLT43dPH488RiEIdw) -- [阿里低代码引擎 LowCodeEngine 正式开源!](https://mp.weixin.qq.com/s/T66LghtWLz2Oh048XqaniA) +- [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/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) ## Portal 设计项目实战 #### 直播回放 From 1b0e7e288a5bd6c618222746900fade6a1b1090a Mon Sep 17 00:00:00 2001 From: iqinning <qinning@newland.com.cn> Date: Sun, 26 Mar 2023 15:50:35 +0800 Subject: [PATCH 075/469] fix: duplicate key "locale" in renderer.ts --- packages/react-simulator-renderer/src/renderer.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index 44fec00098..b3ba1df247 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -461,7 +461,6 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { locale: renderer.locale, messages: _schema.i18n || {}, device: renderer.device, - locale: renderer.locale, appHelper: renderer.context, rendererName: 'LowCodeRenderer', thisRequiredInJSE: host.thisRequiredInJSE, From 1d7c8f2597089a50b5db9c622608b6a74e496dff Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 27 Mar 2023 17:05:13 +0800 Subject: [PATCH 076/469] chore(docs): publish 1.0.23 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 137cba035c..791dd88c27 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.22", + "version": "1.0.23", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 10511507a57571bed11ef51ba3ef55217108c437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Tue, 28 Mar 2023 15:39:30 +0800 Subject: [PATCH 077/469] docs: add @alifd/layout to npms.md --- docs/docs/guide/appendix/npms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/guide/appendix/npms.md b/docs/docs/guide/appendix/npms.md index ce25283e68..93980f32ce 100644 --- a/docs/docs/guide/appendix/npms.md +++ b/docs/docs/guide/appendix/npms.md @@ -44,6 +44,6 @@ sidebar_position: 3 | @alifd/fusion-ui | [https://github.com/alibaba/lowcode-materials](https://github.com/alibaba/lowcode-materials) | packages/fusion-ui | | @alilc/lowcode-materials | [https://github.com/alibaba/lowcode-materials](https://github.com/alibaba/lowcode-materials) | packages/fusion-lowcode-materials | | @alilc/antd-lowcode-materials | [https://github.com/alibaba/lowcode-materials](https://github.com/alibaba/lowcode-materials) | packages/antd-lowcode-materials | -| | | | +| @alifd/layout(原 @alifd/pro-layout 升级后的版本) | [https://github.com/alibaba-fusion/layout](https://github.com/alibaba-fusion/layout) | | | | | | | | | | From 505a6401cba62ee081de563e27d920ed4af19a78 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 28 Mar 2023 16:54:43 +0800 Subject: [PATCH 078/469] docs: add setting-field and setting-prop-entry api docs --- docs/docs/api/model/node.md | 2 + docs/docs/api/model/setting-field.md | 340 ++++++++++++++++++ docs/docs/api/model/setting-top-entry.md | 74 ++++ .../types/src/shell/model/setting-field.ts | 14 +- 4 files changed, 423 insertions(+), 7 deletions(-) create mode 100644 docs/docs/api/model/setting-field.md create mode 100644 docs/docs/api/model/setting-top-entry.md diff --git a/docs/docs/api/model/node.md b/docs/docs/api/model/node.md index bbf8e559ff..c10af34660 100644 --- a/docs/docs/api/model/node.md +++ b/docs/docs/api/model/node.md @@ -254,6 +254,8 @@ sidebar_position: 1 `@type {IPublicModelSettingTopEntry}` +相关章节:[设置器顶层操作对象](./setting-top-entry) + 相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts) ### visible diff --git a/docs/docs/api/model/setting-field.md b/docs/docs/api/model/setting-field.md new file mode 100644 index 0000000000..abf99db375 --- /dev/null +++ b/docs/docs/api/model/setting-field.md @@ -0,0 +1,340 @@ +--- +title: SettingField +sidebar_position: 6 +--- +> **@types** [IPublicModelSettingField](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-field.ts)<br/> + +# 基本介绍 + +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<IPublicModelSettingField | IPublicTypeCustomView>}` + +相关类型:[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) \ No newline at end of file diff --git a/docs/docs/api/model/setting-top-entry.md b/docs/docs/api/model/setting-top-entry.md new file mode 100644 index 0000000000..0a925c3a9e --- /dev/null +++ b/docs/docs/api/model/setting-top-entry.md @@ -0,0 +1,74 @@ +--- +title: SettingTopEntry +sidebar_position: 6 +--- +> **@types** [IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)<br/> + +# 基本介绍 + +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; +``` \ No newline at end of file diff --git a/packages/types/src/shell/model/setting-field.ts b/packages/types/src/shell/model/setting-field.ts index a2dd4fd28a..a011fc21f0 100644 --- a/packages/types/src/shell/model/setting-field.ts +++ b/packages/types/src/shell/model/setting-field.ts @@ -8,6 +8,11 @@ export interface IBaseModelSettingField< Node > { + /** + * 获取设置属性的父设置属性 + */ + readonly parent: SettingTopEntry | SettingField; + /** * 获取设置属性的 isGroup */ @@ -31,12 +36,12 @@ export interface IBaseModelSettingField< /** * 获取设置属性的 path */ - get path(): any[]; + get path(): (string | number)[]; /** * 获取设置属性的 title */ - get title(): any; + get title(): string; /** * 获取设置属性的 setter @@ -60,11 +65,6 @@ export interface IBaseModelSettingField< */ get node(): Node | null; - /** - * 获取设置属性的父设置属性 - */ - readonly parent: SettingTopEntry | SettingField; - /** * 获取顶级设置属性 */ From a6e768f8e9cdcf3f75c999d60ca7c5cabf309d6f Mon Sep 17 00:00:00 2001 From: owenchen1004 <yoga981004@gmail.com> Date: Wed, 29 Mar 2023 09:47:25 +0800 Subject: [PATCH 079/469] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=92=8C=E6=9B=B4?= =?UTF-8?q?=E6=AD=A3docs=E4=B8=AD=E7=9A=84functionsetter=E7=94=A8=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../guide/appendix/setterDetails/function.md | 74 +++++++++++++++++++ docs/docs/guide/appendix/setters.md | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 docs/docs/guide/appendix/setterDetails/function.md diff --git a/docs/docs/guide/appendix/setterDetails/function.md b/docs/docs/guide/appendix/setterDetails/function.md new file mode 100644 index 0000000000..3135d8597e --- /dev/null +++ b/docs/docs/guide/appendix/setterDetails/function.md @@ -0,0 +1,74 @@ +--- +title: FunctionSetter +--- +## 简介 +可以将function绑定在物料上 + +## 设置器返回 + +设置器返回一个Function对象,调用function()运行Function对象得到运行结果。 + +如下是一个典型的使用案例: + +```javascript +export type TestProps = React.ComponentProps<typeof Test> & { + 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} 为扩展参数占位符,如果用户没有声明扩展参数,会移除对应的参数声明。 \ No newline at end of file diff --git a/docs/docs/guide/appendix/setters.md b/docs/docs/guide/appendix/setters.md index fe578eee68..d94b402865 100644 --- a/docs/docs/guide/appendix/setters.md +++ b/docs/docs/guide/appendix/setters.md @@ -14,7 +14,7 @@ sidebar_position: 4 | DateYearSetter || 日期型 - 年数据设置器 | | | [EventSetter](./setterDetails/event) | function | 事件绑定设置器 | ![](https://img.alicdn.com/imgextra/i4/O1CN01qxIYiO1ksVknhTpnW_!!6000000004739-2-tps-1202-1014.png) | | [IconSetter](./setterDetails/icon) | string | 图标设置器 | ![](https://img.alicdn.com/imgextra/i3/O1CN01zsOMxo1TXaBmjHCRc_!!6000000002392-2-tps-1172-579.png) | -| FunctionSetter | any | 函数型数据设置器 | ![](https://img.alicdn.com/imgextra/i4/O1CN01jLiJBo1ZIp7OmDLp0_!!6000000003172-2-tps-794-110.png) | +| [FunctionSetter](./setterDetails/function) | function | 函数型数据设置器 | ![](https://img.alicdn.com/imgextra/i4/O1CN01jLiJBo1ZIp7OmDLp0_!!6000000003172-2-tps-794-110.png) | | JsonSetter | object | json 型数据设置器 | ![](https://img.alicdn.com/imgextra/i2/O1CN01mQTFjY1YiBQzWYj64_!!6000000003092-2-tps-1076-1068.png) | | [MixedSetter](./setterDetails/mixed) | any | 混合型数据设置器 | ![](https://img.alicdn.com/imgextra/i1/O1CN01ZxomFY1JW4j7wIGuQ_!!6000000001035-2-tps-1552-480.png) | | [NumberSetter](./setterDetails/number) | number | 数值型数据设置器 | ![](https://img.alicdn.com/imgextra/i3/O1CN01dSfSgg1WS2EpbqJIO_!!6000000002786-2-tps-1152-328.png) | From b607b246d6681c778aa57ebf990997d4119167a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Wed, 29 Mar 2023 10:22:17 +0800 Subject: [PATCH 080/469] feat: add a new built-in solution icejs3 which is corresponding to the latest icejs framework --- modules/code-generator/package.json | 2 +- modules/code-generator/src/index.ts | 7 + .../src/plugins/common/esmodule.ts | 4 +- .../plugins/project/framework/icejs3/index.ts | 17 + .../framework/icejs3/plugins/appConfig.ts | 50 + .../framework/icejs3/plugins/buildConfig.ts | 165 ++ .../framework/icejs3/plugins/globalStyle.ts | 56 + .../framework/icejs3/plugins/layout.ts | 41 + .../framework/icejs3/plugins/packageJSON.ts | 119 ++ .../icejs3/template/files/README.md.ts | 12 + .../icejs3/template/files/browserslistrc.ts | 14 + .../icejs3/template/files/document.ts | 41 + .../icejs3/template/files/gitignore.ts | 36 + .../components/Footer/index.jsx.ts | 25 + .../components/Footer/index.style.ts | 26 + .../BasicLayout/components/Logo/index.jsx.ts | 27 + .../components/Logo/index.style.ts | 31 + .../components/PageNav/index.jsx.ts | 79 + .../src/layouts/BasicLayout/index.jsx.ts | 92 + .../src/layouts/BasicLayout/menuConfig.js.ts | 22 + .../icejs3/template/files/tsconfig.ts | 38 + .../icejs3/template/files/typings.ts | 20 + .../framework/icejs3/template/index.ts | 57 + .../framework/icejs3/template/static-files.ts | 33 + .../code-generator/src/solutions/icejs3.ts | 109 ++ modules/code-generator/src/utils/format.ts | 12 + modules/code-generator/src/utils/theme.ts | 20 + .../expected/demo-project/.browserslistrc | 3 + .../demo1/expected/demo-project/.gitignore | 25 + .../demo1/expected/demo-project/README.md | 1 + .../expected/demo-project/ice.config.mts | 90 + .../demo1/expected/demo-project/package.json | 44 + .../demo1/expected/demo-project/src/app.ts | 13 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/document.tsx | 29 + .../expected/demo-project/src/global.scss | 13 + .../demo1/expected/demo-project/src/i18n.js | 77 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 68 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 0 .../demo-project/src/pages/Test/index.jsx | 195 ++ .../demo-project/src/pages/layout.jsx | 10 + .../expected/demo-project/src/typings.d.ts | 9 + .../demo1/expected/demo-project/src/utils.js | 47 + .../test-cases/icejs3-app/demo1/schema.json5 | 276 +++ .../expected/demo-project/.browserslistrc | 3 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/README.md | 1 + .../expected/demo-project/ice.config.mts | 90 + .../expected/demo-project/package.json | 48 + .../expected/demo-project/src/app.ts | 13 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/document.tsx | 29 + .../expected/demo-project/src/global.scss | 6 + .../expected/demo-project/src/i18n.js | 77 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 68 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Aaaa/index.css | 0 .../demo-project/src/pages/Aaaa/index.jsx | 118 ++ .../demo-project/src/pages/layout.jsx | 10 + .../expected/demo-project/src/typings.d.ts | 9 + .../expected/demo-project/src/utils.js | 61 + .../demo2-utils-name-alias/schema.json5 | 123 ++ .../expected/demo-project/.browserslistrc | 3 + .../demo2/expected/demo-project/.gitignore | 25 + .../demo2/expected/demo-project/README.md | 1 + .../expected/demo-project/ice.config.mts | 90 + .../demo2/expected/demo-project/package.json | 42 + .../demo2/expected/demo-project/src/app.ts | 13 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/document.tsx | 29 + .../expected/demo-project/src/global.scss | 13 + .../demo2/expected/demo-project/src/i18n.js | 86 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 68 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 0 .../demo-project/src/pages/Test/index.jsx | 119 ++ .../demo-project/src/pages/layout.jsx | 10 + .../expected/demo-project/src/typings.d.ts | 9 + .../demo2/expected/demo-project/src/utils.js | 47 + .../test-cases/icejs3-app/demo2/schema.json5 | 256 +++ .../expected/demo-project/.browserslistrc | 3 + .../demo3/expected/demo-project/.gitignore | 25 + .../demo3/expected/demo-project/README.md | 1 + .../expected/demo-project/ice.config.mts | 90 + .../demo3/expected/demo-project/package.json | 42 + .../demo3/expected/demo-project/src/app.ts | 13 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/document.tsx | 29 + .../expected/demo-project/src/global.scss | 13 + .../demo3/expected/demo-project/src/i18n.js | 86 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 68 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 0 .../demo-project/src/pages/Test/index.jsx | 93 + .../demo-project/src/pages/layout.jsx | 10 + .../expected/demo-project/src/typings.d.ts | 9 + .../demo3/expected/demo-project/src/utils.js | 47 + .../test-cases/icejs3-app/demo3/schema.json5 | 159 ++ .../expected/demo-project/.browserslistrc | 3 + .../demo4/expected/demo-project/.gitignore | 25 + .../demo4/expected/demo-project/README.md | 1 + .../expected/demo-project/ice.config.mts | 90 + .../demo4/expected/demo-project/package.json | 45 + .../demo4/expected/demo-project/src/app.ts | 13 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/document.tsx | 29 + .../expected/demo-project/src/global.scss | 6 + .../demo4/expected/demo-project/src/i18n.js | 77 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 68 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 8 + .../demo-project/src/pages/Test/index.jsx | 292 +++ .../demo-project/src/pages/layout.jsx | 10 + .../expected/demo-project/src/typings.d.ts | 9 + .../demo4/expected/demo-project/src/utils.js | 47 + .../test-cases/icejs3-app/demo4/schema.json5 | 353 ++++ .../expected/demo-project/.browserslistrc | 3 + .../demo5/expected/demo-project/.gitignore | 25 + .../demo5/expected/demo-project/README.md | 1 + .../expected/demo-project/ice.config.mts | 90 + .../demo5/expected/demo-project/package.json | 46 + .../demo5/expected/demo-project/src/app.ts | 13 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/document.tsx | 29 + .../expected/demo-project/src/global.scss | 6 + .../demo5/expected/demo-project/src/i18n.js | 77 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 68 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 8 + .../demo-project/src/pages/Test/index.jsx | 389 ++++ .../demo-project/src/pages/layout.jsx | 10 + .../expected/demo-project/src/typings.d.ts | 9 + .../demo5/expected/demo-project/src/utils.js | 47 + .../test-cases/icejs3-app/demo5/schema.json5 | 677 +++++++ .../expected/demo-project/.browserslistrc | 3 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/README.md | 1 + .../expected/demo-project/ice.config.mts | 90 + .../expected/demo-project/package.json | 44 + .../expected/demo-project/src/app.ts | 13 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/document.tsx | 29 + .../expected/demo-project/src/global.scss | 13 + .../expected/demo-project/src/i18n.js | 77 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 68 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 0 .../demo-project/src/pages/Test/index.jsx | 195 ++ .../demo-project/src/pages/layout.jsx | 10 + .../expected/demo-project/src/typings.d.ts | 9 + .../expected/demo-project/src/utils.js | 47 + .../demo6-literal-condition/schema.json5 | 273 +++ .../expected/demo-project/.browserslistrc | 3 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/README.md | 1 + .../expected/demo-project/ice.config.mts | 90 + .../expected/demo-project/package.json | 45 + .../expected/demo-project/src/app.ts | 13 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/document.tsx | 29 + .../expected/demo-project/src/global.scss | 6 + .../expected/demo-project/src/i18n.js | 77 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 68 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 8 + .../demo-project/src/pages/Test/index.jsx | 1076 +++++++++++ .../demo-project/src/pages/layout.jsx | 10 + .../expected/demo-project/src/typings.d.ts | 9 + .../expected/demo-project/src/utils.js | 47 + .../demo7-literal-condition2/schema.json5 | 1703 +++++++++++++++++ .../expected/demo-project/.browserslistrc | 3 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/README.md | 1 + .../expected/demo-project/ice.config.mts | 90 + .../expected/demo-project/package.json | 44 + .../expected/demo-project/src/app.ts | 13 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/document.tsx | 29 + .../expected/demo-project/src/global.scss | 6 + .../expected/demo-project/src/i18n.js | 77 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 68 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Example/index.css | 0 .../demo-project/src/pages/Example/index.jsx | 116 ++ .../demo-project/src/pages/layout.jsx | 10 + .../expected/demo-project/src/typings.d.ts | 9 + .../expected/demo-project/src/utils.js | 47 + .../demo8-datasource-prop/schema.json5 | 65 + .../expected/demo-project/.browserslistrc | 3 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/README.md | 1 + .../expected/demo-project/ice.config.mts | 90 + .../expected/demo-project/package.json | 43 + .../expected/demo-project/src/app.ts | 13 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/document.tsx | 29 + .../expected/demo-project/src/global.scss | 6 + .../expected/demo-project/src/i18n.js | 77 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 68 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/$/index.css | 0 .../demo-project/src/pages/$/index.jsx | 123 ++ .../demo-project/src/pages/layout.jsx | 10 + .../expected/demo-project/src/typings.d.ts | 9 + .../expected/demo-project/src/utils.js | 47 + .../demo9-datasource-engine/schema.json5 | 59 + .../expected/demo-project/.browserslistrc | 3 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/README.md | 1 + .../expected/demo-project/ice.config.mts | 90 + .../expected/demo-project/package.json | 46 + .../expected/demo-project/src/app.ts | 13 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/document.tsx | 29 + .../expected/demo-project/src/global.scss | 6 + .../expected/demo-project/src/i18n.js | 77 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 68 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 8 + .../demo-project/src/pages/Test/index.jsx | 822 ++++++++ .../demo-project/src/pages/layout.jsx | 10 + .../expected/demo-project/src/typings.d.ts | 9 + .../expected/demo-project/src/utils.js | 47 + .../icejs3-app/demo_10-jsslot/schema.json5 | 1206 ++++++++++++ .../expected/demo-project/.browserslistrc | 3 + .../expected/demo-project/.gitignore | 25 + .../expected/demo-project/README.md | 1 + .../expected/demo-project/ice.config.mts | 90 + .../expected/demo-project/package.json | 46 + .../expected/demo-project/src/app.ts | 13 + .../expected/demo-project/src/constants.js | 3 + .../expected/demo-project/src/document.tsx | 29 + .../expected/demo-project/src/global.scss | 6 + .../expected/demo-project/src/i18n.js | 77 + .../BasicLayout/components/Footer/index.jsx | 14 + .../components/Footer/index.module.scss | 15 + .../BasicLayout/components/Logo/index.jsx | 16 + .../components/Logo/index.module.scss | 20 + .../BasicLayout/components/PageNav/index.jsx | 68 + .../src/layouts/BasicLayout/index.jsx | 81 + .../src/layouts/BasicLayout/menuConfig.js | 11 + .../demo-project/src/pages/Test/index.css | 8 + .../demo-project/src/pages/Test/index.jsx | 976 ++++++++++ .../demo-project/src/pages/layout.jsx | 10 + .../expected/demo-project/src/typings.d.ts | 9 + .../expected/demo-project/src/utils.js | 47 + .../icejs3-app/demo_11-jsslot-2/schema.json5 | 1457 ++++++++++++++ .../tests/public/solutions/icejs3-app.test.ts | 63 + 304 files changed, 19427 insertions(+), 3 deletions(-) create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/index.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/plugins/appConfig.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/plugins/buildConfig.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/plugins/globalStyle.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/plugins/layout.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/plugins/packageJSON.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/README.md.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/browserslistrc.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/document.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/gitignore.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/index.jsx.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/menuConfig.js.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/tsconfig.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/files/typings.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/index.ts create mode 100644 modules/code-generator/src/plugins/project/framework/icejs3/template/static-files.ts create mode 100644 modules/code-generator/src/solutions/icejs3.ts create mode 100644 modules/code-generator/src/utils/format.ts create mode 100644 modules/code-generator/src/utils/theme.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/.browserslistrc create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/.gitignore create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/README.md create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/ice.config.mts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/package.json create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/app.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/constants.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/document.tsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/global.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/i18n.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.css create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/layout.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/typings.d.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/utils.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/schema.json5 create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/.browserslistrc create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/.gitignore create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/README.md create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/ice.config.mts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/package.json create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/app.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/constants.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/document.tsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/global.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.css create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/layout.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/typings.d.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/utils.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/schema.json5 create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/.browserslistrc create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/.gitignore create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/README.md create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/ice.config.mts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/package.json create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/app.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/constants.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/document.tsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/global.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/i18n.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.css create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/layout.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/typings.d.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/utils.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/schema.json5 create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/.browserslistrc create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/.gitignore create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/README.md create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/ice.config.mts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/package.json create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/app.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/constants.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/document.tsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/global.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/i18n.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.css create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/layout.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/typings.d.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/utils.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/schema.json5 create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/.browserslistrc create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/.gitignore create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/README.md create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/ice.config.mts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/package.json create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/app.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/constants.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/document.tsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/global.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/i18n.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/Test/index.css create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/Test/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/layout.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/typings.d.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/utils.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/schema.json5 create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/.browserslistrc create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/.gitignore create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/README.md create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/ice.config.mts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/package.json create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/app.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/constants.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/document.tsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/global.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/i18n.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/Test/index.css create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/Test/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/layout.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/typings.d.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/utils.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/schema.json5 create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/.browserslistrc create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/.gitignore create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/README.md create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/ice.config.mts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/package.json create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/app.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/constants.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/document.tsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/global.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/i18n.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.css create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/layout.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/typings.d.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/utils.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/schema.json5 create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/.browserslistrc create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/.gitignore create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/README.md create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/ice.config.mts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/package.json create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/app.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/constants.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/document.tsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/global.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/i18n.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.css create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/layout.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/typings.d.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/utils.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/schema.json5 create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/.browserslistrc create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/.gitignore create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/README.md create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/ice.config.mts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/package.json create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/app.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/constants.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/document.tsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/global.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/i18n.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.css create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/layout.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/typings.d.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/utils.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/schema.json5 create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/.browserslistrc create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/.gitignore create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/README.md create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/ice.config.mts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/package.json create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/app.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/constants.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/document.tsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/global.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/i18n.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.css create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/layout.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/typings.d.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/utils.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/schema.json5 create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/.browserslistrc create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/.gitignore create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/README.md create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/ice.config.mts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/package.json create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/app.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/constants.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/document.tsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/global.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/i18n.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.css create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/layout.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/typings.d.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/utils.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/schema.json5 create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/.browserslistrc create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/.gitignore create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/README.md create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/ice.config.mts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/package.json create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/app.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/constants.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/document.tsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/global.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.css create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/layout.jsx create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/typings.d.ts create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/utils.js create mode 100644 modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/schema.json5 create mode 100644 modules/code-generator/tests/public/solutions/icejs3-app.test.ts diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index a7b795f38f..97d945469f 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-code-generator", - "version": "1.0.8", + "version": "1.1.0", "description": "出码引擎 for LowCode Engine", "license": "MIT", "main": "lib/index.js", diff --git a/modules/code-generator/src/index.ts b/modules/code-generator/src/index.ts index 742b2e6a8e..abe0805577 100644 --- a/modules/code-generator/src/index.ts +++ b/modules/code-generator/src/index.ts @@ -9,6 +9,7 @@ import { createModuleBuilder } from './generator/ModuleBuilder'; import { createDiskPublisher } from './publisher/disk'; import { createZipPublisher } from './publisher/zip'; import createIceJsProjectBuilder, { plugins as reactPlugins } from './solutions/icejs'; +import createIce3JsProjectBuilder, { plugins as icejs3Plugins } from './solutions/icejs3'; import createRaxAppProjectBuilder, { plugins as raxPlugins } from './solutions/rax-app'; // 引入说明 @@ -32,6 +33,7 @@ import * as CONSTANTS from './const'; // 引入内置解决方案模块 import icejs from './plugins/project/framework/icejs'; +import icejs3 from './plugins/project/framework/icejs3'; import rax from './plugins/project/framework/rax'; export default { @@ -39,10 +41,12 @@ export default { createModuleBuilder, solutions: { icejs: createIceJsProjectBuilder, + icejs3: createIce3JsProjectBuilder, rax: createRaxAppProjectBuilder, }, solutionParts: { icejs, + icejs3, rax, }, publishers: { @@ -74,6 +78,9 @@ export default { i18n, utils, }, + icejs3: { + ...icejs3Plugins, + }, }, postprocessor: { prettier, diff --git a/modules/code-generator/src/plugins/common/esmodule.ts b/modules/code-generator/src/plugins/common/esmodule.ts index 09c6aec599..53f3f9418b 100644 --- a/modules/code-generator/src/plugins/common/esmodule.ts +++ b/modules/code-generator/src/plugins/common/esmodule.ts @@ -16,7 +16,7 @@ import { IWithDependency, } from '../../types'; -import { isValidIdentifier, isValidComponentName } from '../../utils/validate'; +import { isValidIdentifier } from '../../utils/validate'; // TODO: main 这个信息到底怎么用,是不是外部包不需要使用? const DEP_MAIN_BLOCKLIST = ['lib', 'lib/index', 'es', 'es/index', 'main']; @@ -261,7 +261,7 @@ function buildPackageImport( if (!isValidIdentifier(name)) { throw new CodeGeneratorError(`Invalid Identifier [${name}]`); } - if (info.nodeIdentifier && !isValidComponentName(info.nodeIdentifier)) { + if (info.nodeIdentifier && !isValidIdentifier(info.nodeIdentifier)) { throw new CodeGeneratorError(`Invalid Identifier [${info.nodeIdentifier}]`); } }); diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/index.ts b/modules/code-generator/src/plugins/project/framework/icejs3/index.ts new file mode 100644 index 0000000000..37fa7a9e39 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/index.ts @@ -0,0 +1,17 @@ +import template from './template'; +import globalStyle from './plugins/globalStyle'; +import packageJSON from './plugins/packageJSON'; +import layout from './plugins/layout'; +import appConfig from './plugins/appConfig'; +import buildConfig from './plugins/buildConfig'; + +export default { + template, + plugins: { + appConfig, + buildConfig, + globalStyle, + packageJSON, + layout, + }, +}; diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/plugins/appConfig.ts b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/appConfig.ts new file mode 100644 index 0000000000..6ec5384a5d --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/appConfig.ts @@ -0,0 +1,50 @@ +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, +} from '../../../../../types'; +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +export interface AppConfigPluginConfig { + +} + +function getContent() { + return `import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +}));`; +} + +const pluginFactory: BuilderComponentPluginFactory<AppConfigPluginConfig> = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.TS, + name: COMMON_CHUNK_NAME.FileMainContent, + content: getContent(), + linkAfter: [], + }); + + return next; + }; + + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/plugins/buildConfig.ts b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/buildConfig.ts new file mode 100644 index 0000000000..e5eee83d5b --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/buildConfig.ts @@ -0,0 +1,165 @@ +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, +} from '../../../../../types'; +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; +import { format } from '../../../../../utils/format'; +import { getThemeInfo } from '../../../../../utils/theme'; + +export interface BuildConfigPluginConfig { + + /** 包名 */ + themePackage?: string; +} + +function getContent(cfg?: BuildConfigPluginConfig, routesContent?: string) { + return ` +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + } + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = \` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + \`; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + ${routesContent} + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion(${cfg?.themePackage ? `{ + importStyle: 'sass', + themePackage: '${getThemeInfo(cfg.themePackage).name}', + }` : `{ + importStyle: true, + }`}), + locales(), + plugin(), + ] +})); + `; +} + +function getRoutesContent(navData: any, needShell = true) { + const routes = [ + 'routes: {', + ' defineRoutes: route => {', + ]; + function _getRoutes(nav: any, _routes: string[] = []) { + const { slug, children } = nav; + if (children && children.length > 0) { + children.forEach((_nav: any) => _getRoutes(_nav, _routes)); + } else if (slug) { + _routes.push(`route('/${slug}', '${slug}/index.jsx');`); + } + } + if (needShell) { + routes.push(" route('/', 'layout.jsx', () => {"); + } + navData?.forEach((nav: any) => { + _getRoutes(nav, routes); + }); + if (needShell) { + routes.push(' });'); + } + routes.push(' }'); // end of defineRoutes + routes.push(' },'); // end of routes + return routes.join('\n'); +} + +const pluginFactory: BuilderComponentPluginFactory<BuildConfigPluginConfig> = (cfg?) => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const { navConfig } = next.contextData; + const routesContent = navConfig?.data ? getRoutesContent(navConfig.data, true) : ''; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.MTS, + name: COMMON_CHUNK_NAME.FileMainContent, + content: format(getContent(cfg, routesContent)), + linkAfter: [], + }); + + return next; + }; + + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/plugins/globalStyle.ts b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/globalStyle.ts new file mode 100644 index 0000000000..3daaeecdc0 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/globalStyle.ts @@ -0,0 +1,56 @@ +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IProjectInfo, +} from '../../../../../types'; + +const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IProjectInfo; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.SCSS, + name: COMMON_CHUNK_NAME.StyleDepsImport, + content: ` + // 引入默认全局样式 + @import '@alifd/next/reset.scss'; + `, + linkAfter: [], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.SCSS, + name: COMMON_CHUNK_NAME.StyleCssContent, + content: ` + body { + -webkit-font-smoothing: antialiased; + } + `, + linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport], + }); + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.SCSS, + name: COMMON_CHUNK_NAME.StyleCssContent, + content: ir.css || '', + linkAfter: [COMMON_CHUNK_NAME.StyleDepsImport], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/plugins/layout.ts b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/layout.ts new file mode 100644 index 0000000000..a67f227019 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/layout.ts @@ -0,0 +1,41 @@ +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, +} from '../../../../../types'; +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + next.chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.FileMainContent, + content: ` + import { Outlet } from 'ice'; + import BasicLayout from '@/layouts/BasicLayout'; + + export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + );; + } + `, + linkAfter: [], + }); + + return next; + }; + + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/plugins/packageJSON.ts b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/packageJSON.ts new file mode 100644 index 0000000000..11248a0b5d --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/packageJSON.ts @@ -0,0 +1,119 @@ +import { PackageJSON } from '@alilc/lowcode-types'; + +import { COMMON_CHUNK_NAME } from '../../../../../const/generator'; + +import { + BuilderComponentPlugin, + BuilderComponentPluginFactory, + ChunkType, + FileType, + ICodeStruct, + IProjectInfo, +} from '../../../../../types'; +import { buildDataSourceDependencies } from '../../../../../utils/dataSource'; + +interface IIceJs3PackageJSON extends PackageJSON { + originTemplate: string; +} + +export type IceJs3PackageJsonPluginConfig = { + + /** + * 数据源配置 + */ + datasourceConfig?: { + + /** 数据源引擎的版本 */ + engineVersion?: string; + + /** 数据源引擎的包名 */ + enginePackage?: string; + + /** 数据源 handlers 的版本 */ + handlersVersion?: { + [key: string]: string; + }; + + /** 数据源 handlers 的包名 */ + handlersPackages?: { + [key: string]: string; + }; + }; + + /** 包名 */ + packageName?: string; + + /** 版本 */ + packageVersion?: string; +}; + +const pluginFactory: BuilderComponentPluginFactory<IceJs3PackageJsonPluginConfig> = (cfg) => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IProjectInfo; + + const packageJson: IIceJs3PackageJSON = { + name: cfg?.packageName || 'icejs3-demo-app', + version: cfg?.packageVersion || '0.1.5', + description: 'icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。', + dependencies: { + moment: '^2.24.0', + react: '^18.2.0', + 'react-dom': '^18.2.0', + 'react-router': '^6.9.0', + 'react-router-dom': '^6.9.0', + 'intl-messageformat': '^9.3.6', + '@alifd/next': '1.26.15', + '@ice/runtime': '^1.0.0', + // 数据源相关的依赖: + ...buildDataSourceDependencies(ir, cfg?.datasourceConfig), + }, + devDependencies: { + '@ice/app': '^3.0.0', + '@types/react': '^18.0.0', + '@types/react-dom': '^18.0.0', + '@types/node': '^18.11.17', + '@ice/plugin-fusion': '^1.0.1', + '@ice/plugin-moment-locales': '^1.0.0', + eslint: '^6.0.1', + stylelint: '^13.2.0', + }, + scripts: { + start: 'ice start', + build: 'ice build', + lint: 'npm run eslint && npm run stylelint', + eslint: 'eslint --cache --ext .js,.jsx ./', + stylelint: 'stylelint ./**/*.scss', + }, + engines: { + node: '>=14.0.0', + }, + repository: { + type: 'git', + url: 'http://gitlab.xxx.com/msd/leak-scan/tree/master', + }, + private: true, + originTemplate: '@alifd/scaffold-lite-js', + }; + + ir.packages.forEach((packageInfo) => { + packageJson.dependencies[packageInfo.package] = packageInfo.version; + }); + + next.chunks.push({ + type: ChunkType.JSON, + fileType: FileType.JSON, + name: COMMON_CHUNK_NAME.FileMainContent, + content: packageJson, + linkAfter: [], + }); + + return next; + }; + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/README.md.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/README.md.ts new file mode 100644 index 0000000000..e73ab2b82c --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/README.md.ts @@ -0,0 +1,12 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'README', + 'md', + 'This project is generated by lowcode-code-generator & lowcode-solution-icejs3.', + ); + + return [[], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/browserslistrc.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/browserslistrc.ts new file mode 100644 index 0000000000..a3a346e3ff --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/browserslistrc.ts @@ -0,0 +1,14 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + '.browserslistrc', + '', + `defaults +ios_saf 9 + `, + ); + + return [[], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/document.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/document.ts new file mode 100644 index 0000000000..17978b20dc --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/document.ts @@ -0,0 +1,41 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +/* eslint-disable max-len */ +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'document', + 'tsx', + `import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +}`, + ); + + return [['src'], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/gitignore.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/gitignore.ts new file mode 100644 index 0000000000..5c6eb3f13b --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/gitignore.ts @@ -0,0 +1,36 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + '.gitignore', + '', + ` +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + `, + ); + + return [[], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts new file mode 100644 index 0000000000..9647a76439 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Footer/index.jsx.ts @@ -0,0 +1,25 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'index', + 'jsx', + ` +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + `, + ); + + return [['src', 'layouts', 'BasicLayout', 'components', 'Footer'], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts new file mode 100644 index 0000000000..941be0d263 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Footer/index.style.ts @@ -0,0 +1,26 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'index', + 'module.scss', + ` +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + `, + ); + + return [['src', 'layouts', 'BasicLayout', 'components', 'Footer'], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts new file mode 100644 index 0000000000..9c078c92c2 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.jsx.ts @@ -0,0 +1,27 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'index', + 'jsx', + ` +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + `, + ); + + return [['src', 'layouts', 'BasicLayout', 'components', 'Logo'], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts new file mode 100644 index 0000000000..5ac92b550f --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts @@ -0,0 +1,31 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'index', + 'module.scss', + ` +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + `, + ); + + return [['src', 'layouts', 'BasicLayout', 'components', 'Logo'], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts new file mode 100644 index 0000000000..1713057566 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/PageNav/index.jsx.ts @@ -0,0 +1,79 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'index', + 'jsx', + `import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + `, + ); + + return [['src', 'layouts', 'BasicLayout', 'components', 'PageNav'], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/index.jsx.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/index.jsx.ts new file mode 100644 index 0000000000..9c7318dab0 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/index.jsx.ts @@ -0,0 +1,92 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'index', + 'jsx', + ` +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + `, + ); + + return [['src', 'layouts', 'BasicLayout'], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/menuConfig.js.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/menuConfig.js.ts new file mode 100644 index 0000000000..636539b657 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/menuConfig.js.ts @@ -0,0 +1,22 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'menuConfig', + 'js', + ` +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + `, + ); + + return [['src', 'layouts', 'BasicLayout'], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/tsconfig.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/tsconfig.ts new file mode 100644 index 0000000000..f58639db20 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/tsconfig.ts @@ -0,0 +1,38 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'tsconfig', + 'json', + ` +{ + "compilerOptions": { + "baseUrl": "./", + "module": "ESNext", + "target": "ESNext", + "lib": ["DOM", "ESNext", "DOM.Iterable"], + "jsx": "react-jsx", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": false, + "importHelpers": true, + "strictNullChecks": true, + "suppressImplicitAnyIndexErrors": true, + "skipLibCheck": true, + "paths": { + "@/*": ["./src/*"], + "ice": [".ice"] + } + }, + "include": ["src", ".ice"], + "exclude": ["build"] +} + `, + ); + + return [[], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/typings.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/typings.ts new file mode 100644 index 0000000000..c8cbe92545 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/typings.ts @@ -0,0 +1,20 @@ +import { ResultFile } from '@alilc/lowcode-types'; +import { createResultFile } from '../../../../../../utils/resultHelper'; + +export default function getFile(): [string[], ResultFile] { + const file = createResultFile( + 'typings.d', + 'ts', + `/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + `, + ); + + return [['src'], file]; +} diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/index.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/index.ts new file mode 100644 index 0000000000..e29f931386 --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/index.ts @@ -0,0 +1,57 @@ +import { IProjectTemplate } from '../../../../../types'; +import { generateStaticFiles } from './static-files'; + +const icejs3Template: IProjectTemplate = { + slots: { + components: { + path: ['src', 'components'], + fileName: 'index', + }, + pages: { + path: ['src', 'pages'], + fileName: 'index', + }, + entry: { + path: ['src'], + fileName: 'app', + }, + constants: { + path: ['src'], + fileName: 'constants', + }, + utils: { + path: ['src'], + fileName: 'utils', + }, + i18n: { + path: ['src'], + fileName: 'i18n', + }, + globalStyle: { + path: ['src'], + fileName: 'global', + }, + packageJSON: { + path: [], + fileName: 'package', + }, + appConfig: { + path: ['src'], + fileName: 'app', + }, + buildConfig: { + path: [], + fileName: 'ice.config', + }, + layout: { + path: ['src', 'pages'], + fileName: 'layout', + }, + }, + + generateTemplate() { + return generateStaticFiles(); + }, +}; + +export default icejs3Template; diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/static-files.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/static-files.ts new file mode 100644 index 0000000000..8f3794b61a --- /dev/null +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/static-files.ts @@ -0,0 +1,33 @@ +import { ResultDir } from '@alilc/lowcode-types'; +import { createResultDir } from '../../../../../utils/resultHelper'; +import { runFileGenerator } from '../../../../../utils/templateHelper'; + +import file1 from './files/gitignore'; +import file2 from './files/README.md'; +import file3 from './files/browserslistrc'; +import file4 from './files/typings'; +import file5 from './files/document'; +import file6 from './files/src/layouts/BasicLayout/components/Footer/index.jsx'; +import file7 from './files/src/layouts/BasicLayout/components/Footer/index.style'; +import file8 from './files/src/layouts/BasicLayout/components/Logo/index.jsx'; +import file9 from './files/src/layouts/BasicLayout/components/Logo/index.style'; +import file10 from './files/src/layouts/BasicLayout/components/PageNav/index.jsx'; +import file11 from './files/src/layouts/BasicLayout/index.jsx'; +import file12 from './files/src/layouts/BasicLayout/menuConfig.js'; + +export function generateStaticFiles(root = createResultDir('.')): ResultDir { + runFileGenerator(root, file1); + runFileGenerator(root, file2); + runFileGenerator(root, file3); + runFileGenerator(root, file4); + runFileGenerator(root, file5); + runFileGenerator(root, file6); + runFileGenerator(root, file7); + runFileGenerator(root, file8); + runFileGenerator(root, file9); + runFileGenerator(root, file10); + runFileGenerator(root, file11); + runFileGenerator(root, file12); + + return root; +} diff --git a/modules/code-generator/src/solutions/icejs3.ts b/modules/code-generator/src/solutions/icejs3.ts new file mode 100644 index 0000000000..26128a9eb9 --- /dev/null +++ b/modules/code-generator/src/solutions/icejs3.ts @@ -0,0 +1,109 @@ +import { IProjectBuilder, IProjectBuilderOptions } from '../types'; + +import { createProjectBuilder } from '../generator/ProjectBuilder'; + +import esmodule from '../plugins/common/esmodule'; +import containerClass from '../plugins/component/react/containerClass'; +import containerInitState from '../plugins/component/react/containerInitState'; +import containerInjectContext from '../plugins/component/react/containerInjectContext'; +import containerInjectUtils from '../plugins/component/react/containerInjectUtils'; +import containerInjectDataSourceEngine from '../plugins/component/react/containerInjectDataSourceEngine'; +import containerInjectConstants from '../plugins/component/react/containerInjectConstants'; +import containerInjectI18n from '../plugins/component/react/containerInjectI18n'; +import containerLifeCycle from '../plugins/component/react/containerLifeCycle'; +import containerMethod from '../plugins/component/react/containerMethod'; +import jsx from '../plugins/component/react/jsx'; +import reactCommonDeps from '../plugins/component/react/reactCommonDeps'; +import css from '../plugins/component/style/css'; +import constants from '../plugins/project/constants'; +import i18n from '../plugins/project/i18n'; +import utils from '../plugins/project/utils'; + +import icejs3 from '../plugins/project/framework/icejs3'; + +import { prettier } from '../postprocessor'; + +export type IceJs3ProjectBuilderOptions = IProjectBuilderOptions; + +export default function createIceJsProjectBuilder( + options?: IceJs3ProjectBuilderOptions, +): IProjectBuilder { + return createProjectBuilder({ + inStrictMode: options?.inStrictMode, + extraContextData: { ...options }, + template: icejs3.template, + plugins: { + components: [ + reactCommonDeps(), + esmodule({ + fileType: 'jsx', + }), + containerClass(), + containerInjectContext(), + containerInjectUtils(), + containerInjectDataSourceEngine(), + containerInjectI18n(), + containerInitState(), + containerLifeCycle(), + containerMethod(), + jsx({ + nodeTypeMapping: { + Div: 'div', + Component: 'div', + Page: 'div', + Block: 'div', + }, + }), + css(), + ], + pages: [ + reactCommonDeps(), + esmodule({ + fileType: 'jsx', + }), + containerClass(), + containerInjectContext(), + containerInjectUtils(), + containerInjectDataSourceEngine(), + containerInjectI18n(), + containerInjectConstants(), + containerInitState(), + containerLifeCycle(), + containerMethod(), + jsx({ + nodeTypeMapping: { + Div: 'div', + Component: 'div', + Page: 'div', + Block: 'div', + Box: 'div', + }, + }), + css(), + ], + constants: [constants()], + utils: [esmodule(), utils('react')], + i18n: [i18n()], + globalStyle: [icejs3.plugins.globalStyle()], + packageJSON: [icejs3.plugins.packageJSON()], + buildConfig: [icejs3.plugins.buildConfig()], + appConfig: [icejs3.plugins.appConfig()], + layout: [icejs3.plugins.layout()], + }, + postProcessors: [prettier()], + customizeBuilderOptions: options?.customizeBuilderOptions, + }); +} + +export const plugins = { + containerClass, + containerInitState, + containerInjectContext, + containerInjectUtils, + containerInjectI18n, + containerInjectDataSourceEngine, + containerLifeCycle, + containerMethod, + jsx, + commonDeps: reactCommonDeps, +}; diff --git a/modules/code-generator/src/utils/format.ts b/modules/code-generator/src/utils/format.ts new file mode 100644 index 0000000000..7c865e8f34 --- /dev/null +++ b/modules/code-generator/src/utils/format.ts @@ -0,0 +1,12 @@ +import prettier from 'prettier'; +import parserBabel from 'prettier/parser-babel'; + +export function format(content: string, options = {}) { + return prettier.format(content, { + parser: 'babel', + plugins: [parserBabel], + singleQuote: true, + jsxSingleQuote: false, + ...options, + }); +} diff --git a/modules/code-generator/src/utils/theme.ts b/modules/code-generator/src/utils/theme.ts new file mode 100644 index 0000000000..590cf711cf --- /dev/null +++ b/modules/code-generator/src/utils/theme.ts @@ -0,0 +1,20 @@ +/** + * 获取主题信息 + * @param theme theme 形如 @alife/theme-97 或者 @alife/theme-97@^1.0.0 + */ + +export interface ThemeInfo { + name: string; + version?: string; +} + +export function getThemeInfo(theme: string): ThemeInfo { + const sepIdx = theme.indexOf('@', 1); + if (sepIdx === -1) { + return { name: theme }; + } + return { + name: theme.slice(0, sepIdx), + version: theme.slice(sepIdx + 1), + }; +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/.browserslistrc b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/.browserslistrc new file mode 100644 index 0000000000..55a130413d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/.browserslistrc @@ -0,0 +1,3 @@ +defaults +ios_saf 9 + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/.gitignore b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/.gitignore new file mode 100644 index 0000000000..4ec178818e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/.gitignore @@ -0,0 +1,25 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/README.md b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/README.md new file mode 100644 index 0000000000..6d9dd75215 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/README.md @@ -0,0 +1 @@ +This project is generated by lowcode-code-generator & lowcode-solution-icejs3. \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/ice.config.mts new file mode 100644 index 0000000000..fe77c9b6cd --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/ice.config.mts @@ -0,0 +1,90 @@ +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + }, + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = ` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + `; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion({ + importStyle: true, + }), + locales(), + plugin(), + ], +})); + diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/package.json new file mode 100644 index 0000000000..54a1e4e121 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/package.json @@ -0,0 +1,44 @@ +{ + "name": "icejs3-demo-app", + "version": "0.1.5", + "description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。", + "dependencies": { + "moment": "^2.24.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router": "^6.9.0", + "react-router-dom": "^6.9.0", + "intl-messageformat": "^9.3.6", + "@alifd/next": "1.19.18", + "@ice/runtime": "^1.0.0", + "@alilc/lowcode-datasource-engine": "^1.0.0", + "@alilc/lowcode-datasource-url-params-handler": "^1.0.0", + "@alilc/lowcode-datasource-fetch-handler": "^1.0.0" + }, + "devDependencies": { + "@ice/app": "^3.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/node": "^18.11.17", + "@ice/plugin-fusion": "^1.0.1", + "@ice/plugin-moment-locales": "^1.0.0", + "eslint": "^6.0.1", + "stylelint": "^13.2.0" + }, + "scripts": { + "start": "ice start", + "build": "ice build", + "lint": "npm run eslint && npm run stylelint", + "eslint": "eslint --cache --ext .js,.jsx ./", + "stylelint": "stylelint ./**/*.scss" + }, + "engines": { + "node": ">=14.0.0" + }, + "repository": { + "type": "git", + "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" + }, + "private": true, + "originTemplate": "@alifd/scaffold-lite-js" +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/app.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/app.ts new file mode 100644 index 0000000000..6d5856292d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/app.ts @@ -0,0 +1,13 @@ +import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +})); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/constants.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/constants.js new file mode 100644 index 0000000000..91198f9044 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/constants.js @@ -0,0 +1,3 @@ +const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' }; + +export default __$$constants; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/document.tsx new file mode 100644 index 0000000000..286be9f8ca --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/document.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/global.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/global.scss new file mode 100644 index 0000000000..ed7204b4a3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/global.scss @@ -0,0 +1,13 @@ +// 引入默认全局样式 +@import '@alifd/next/reset.scss'; + +body { + -webkit-font-smoothing: antialiased; +} + +body { + font-size: 12px; +} +.table { + width: 100px; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/i18n.js new file mode 100644 index 0000000000..adbbe673dc --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/i18n.js @@ -0,0 +1,77 @@ +const i18nConfig = {}; + +let locale = + typeof navigator === 'object' && typeof navigator.language === 'string' + ? navigator.language + : 'zh-CN'; + +const getLocale = () => locale; + +const setLocale = (target) => { + locale = target; +}; + +const isEmptyVariables = (variables) => + (Array.isArray(variables) && variables.length === 0) || + (typeof variables === 'object' && + (!variables || Object.keys(variables).length === 0)); + +// 按低代码规范里面的要求进行变量替换 +const format = (msg, variables) => + typeof msg === 'string' + ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + : msg; + +const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { + const msg = + i18nConfig[locale]?.[id] ?? + i18nConfig[locale.replace('-', '_')]?.[id] ?? + defaultMessage; + if (msg == null) { + console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); + return fallback === undefined ? `${id}` : fallback; + } + + return format(msg, variables); +}; + +const i18n = (id, params) => { + return i18nFormat({ id }, params); +}; + +// 将国际化的一些方法注入到目标对象&上下文中 +const _inject2 = (target) => { + target.i18n = i18n; + target.getLocale = getLocale; + target.setLocale = (locale) => { + setLocale(locale); + target.forceUpdate(); + }; + target._i18nText = (t) => { + // 优先取直接传过来的语料 + const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]; + if (localMsg != null) { + return format(localMsg, t.params); + } + + // 其次用项目级别的 + const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params); + if (projectMsg != null) { + return projectMsg; + } + + // 兜底用 use 指定的或默认语言的 + return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params); + }; + + // 注入到上下文中去 + if (target._context && target._context !== target) { + Object.assign(target._context, { + i18n, + getLocale, + setLocale: target.setLocale, + }); + } +}; + +export { getLocale, setLocale, i18n, i18nFormat, _inject2 }; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx new file mode 100644 index 0000000000..cc70d53bea --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx @@ -0,0 +1,14 @@ + +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss new file mode 100644 index 0000000000..81e77fda5f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss @@ -0,0 +1,15 @@ + +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx new file mode 100644 index 0000000000..265bfdaa07 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss new file mode 100644 index 0000000000..1ab56d3945 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -0,0 +1,20 @@ + +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx new file mode 100644 index 0000000000..911998b0d3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/index.jsx new file mode 100644 index 0000000000..18db44df5e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/index.jsx @@ -0,0 +1,81 @@ + +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/menuConfig.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/menuConfig.js new file mode 100644 index 0000000000..5332202be4 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/menuConfig.js @@ -0,0 +1,11 @@ + +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.css b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.jsx new file mode 100644 index 0000000000..070020b746 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.jsx @@ -0,0 +1,195 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:react 框架的导出名和各种组件名除外。 +import React from 'react'; + +import { Form, Input, NumberPicker, Select, Button } from '@alifd/next'; + +import { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler'; + +import { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowcode-datasource-fetch-handler'; + +import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime'; + +import utils, { RefsManager } from '../../utils'; + +import * as __$$i18n from '../../i18n'; + +import __$$constants from '../../constants'; + +import './index.css'; + +class Test$$Page extends React.Component { + _context = this; + + _dataSourceConfig = this._defineDataSourceConfig(); + _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, { + runtimeConfig: true, + requestHandlersMap: { + urlParams: __$$createUrlParamsRequestHandler(window.location.search), + fetch: __$$createFetchRequestHandler(), + }, + }); + + get dataSourceMap() { + return this._dataSourceEngine.dataSourceMap || {}; + } + + reloadDataSource = async () => { + await this._dataSourceEngine.reloadDataSource(); + }; + + get constants() { + return __$$constants || {}; + } + + constructor(props, context) { + super(props); + + this.utils = utils; + + this._refsManager = new RefsManager(); + + __$$i18n._inject2(this); + + this.state = { text: 'outter' }; + } + + $ = (refName) => { + return this._refsManager.get(refName); + }; + + $$ = (refName) => { + return this._refsManager.getAll(refName); + }; + + _defineDataSourceConfig() { + const _this = this; + return { + list: [ + { + id: 'urlParams', + type: 'urlParams', + isInit: function () { + return undefined; + }.bind(_this), + options: function () { + return undefined; + }.bind(_this), + }, + { + id: 'user', + type: 'fetch', + options: function () { + return { + method: 'GET', + uri: 'https://shs.xxx.com/mock/1458/demo/user', + isSync: true, + }; + }.bind(_this), + dataHandler: function (response) { + if (!response.data.success) { + throw new Error(response.data.message); + } + return response.data.data; + }, + isInit: function () { + return undefined; + }.bind(_this), + }, + { + id: 'orders', + type: 'fetch', + options: function () { + return { + method: 'GET', + uri: 'https://shs.xxx.com/mock/1458/demo/orders', + isSync: true, + }; + }.bind(_this), + dataHandler: function (response) { + if (!response.data.success) { + throw new Error(response.data.message); + } + return response.data.data.result; + }, + isInit: function () { + return undefined; + }.bind(_this), + }, + ], + dataHandler: function (dataMap) { + console.info('All datasources loaded:', dataMap); + }, + }; + } + + componentDidMount() { + this._dataSourceEngine.reloadDataSource(); + + console.log('componentDidMount'); + } + + render() { + const __$$context = this._context || this; + const { state } = __$$context; + return ( + <div ref={this._refsManager.linkRef('outterView')} autoLoading={true}> + <Form + labelCol={__$$eval(() => this.state.colNum)} + style={{}} + ref={this._refsManager.linkRef('testForm')} + > + <Form.Item label="姓名:" name="name" initValue="李雷"> + <Input placeholder="请输入" size="medium" style={{ width: 320 }} /> + </Form.Item> + <Form.Item label="年龄:" name="age" initValue="22"> + <NumberPicker size="medium" type="normal" /> + </Form.Item> + <Form.Item label="职业:" name="profession"> + <Select + dataSource={[ + { label: '教师', value: 't' }, + { label: '医生', value: 'd' }, + { label: '歌手', value: 's' }, + ]} + /> + </Form.Item> + <div style={{ textAlign: 'center' }}> + <Button.Group> + {__$$evalArray(() => ['a', 'b', 'c']).map((item, index) => + ((__$$context) => + !!__$$eval(() => index >= 1) && ( + <Button type="primary" style={{ margin: '0 5px 0 5px' }}> + {__$$eval(() => item)} + </Button> + ))(__$$createChildContext(__$$context, { item, index })) + )} + </Button.Group> + </div> + </Form> + </div> + ); + } +} + +export default Test$$Page; + +function __$$eval(expr) { + try { + return expr(); + } catch (error) {} +} + +function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; +} + +function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/layout.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/layout.jsx new file mode 100644 index 0000000000..50fbb2d1f1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/layout.jsx @@ -0,0 +1,10 @@ +import { Outlet } from 'ice'; +import BasicLayout from '@/layouts/BasicLayout'; + +export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + ); +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/typings.d.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/typings.d.ts new file mode 100644 index 0000000000..a9f8de7ceb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/typings.d.ts @@ -0,0 +1,9 @@ +/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/utils.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/utils.js new file mode 100644 index 0000000000..1190717924 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/utils.js @@ -0,0 +1,47 @@ +import { createRef } from 'react'; + +export class RefsManager { + constructor() { + this.refInsStore = {}; + } + + clearNullRefs() { + Object.keys(this.refInsStore).forEach((refName) => { + const filteredInsList = this.refInsStore[refName].filter( + (insRef) => !!insRef.current + ); + if (filteredInsList.length > 0) { + this.refInsStore[refName] = filteredInsList; + } else { + delete this.refInsStore[refName]; + } + }); + } + + get(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName][0].current; + } + + return null; + } + + getAll(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName].map((i) => i.current); + } + + return []; + } + + linkRef(refName) { + const refIns = createRef(); + this.refInsStore[refName] = this.refInsStore[refName] || []; + this.refInsStore[refName].push(refIns); + return refIns; + } +} + +export default {}; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/schema.json5 new file mode 100644 index 0000000000..76c52fb5e8 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/schema.json5 @@ -0,0 +1,276 @@ +{ + "version": "1.0.0", + "componentsMap": [ + { + "componentName": "Button", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Button" + }, + { + "componentName": "Button.Group", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Button", + "subName": "Group" + }, + { + "componentName": "Input", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Input" + }, + { + "componentName": "Form", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Form" + }, + { + "componentName": "Form.Item", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Form", + "subName": "Item" + }, + { + "componentName": "NumberPicker", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "NumberPicker" + }, + { + "componentName": "Select", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Select" + } + ], + "componentsTree": [ + { + "componentName": "Page", + "id": "node$1", + "meta": { + "title": "测试", + "router": "/" + }, + "props": { + "ref": "outterView", + "autoLoading": true + }, + "fileName": "test", + "state": { + "text": "outter" + }, + "lifeCycles": { + "componentDidMount": { + "type": "JSFunction", + "value": "function() { console.log('componentDidMount'); }" + } + }, + dataSource: { + list: [ + { + id: 'urlParams', + type: 'urlParams', + }, + // 示例数据源:https://shs.xxx.com/mock/1458/demo/user + { + id: 'user', + type: 'fetch', + options: { + method: 'GET', + uri: 'https://shs.xxx.com/mock/1458/demo/user', + isSync: true, + }, + dataHandler: { + type: 'JSExpression', + value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}', + }, + }, + // 示例数据源:https://shs.xxx.com/mock/1458/demo/orders + { + id: 'orders', + type: 'fetch', + options: { + method: 'GET', + uri: "https://shs.xxx.com/mock/1458/demo/orders", + isSync: true, + }, + dataHandler: { + type: 'JSExpression', + value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}', + }, + }, + ], + dataHandler: { + type: 'JSExpression', + value: 'function (dataMap) {\n console.info("All datasources loaded:", dataMap);\n}', + }, + }, + "children": [ + { + "componentName": "Form", + "id": "node$2", + "props": { + "labelCol": { + "type": "JSExpression", + "value": "this.state.colNum" + }, + "style": {}, + "ref": "testForm" + }, + "children": [ + { + "componentName": "Form.Item", + "id": "node$3", + "props": { + "label": "姓名:", + "name": "name", + "initValue": "李雷" + }, + "children": [ + { + "componentName": "Input", + "id": "node$4", + "props": { + "placeholder": "请输入", + "size": "medium", + "style": { + "width": 320 + } + } + } + ] + }, + { + "componentName": "Form.Item", + "id": "node$5", + "props": { + "label": "年龄:", + "name": "age", + "initValue": "22" + }, + "children": [ + { + "componentName": "NumberPicker", + "id": "node$6", + "props": { + "size": "medium", + "type": "normal" + } + } + ] + }, + { + "componentName": "Form.Item", + "id": "node$7", + "props": { + "label": "职业:", + "name": "profession" + }, + "children": [ + { + "componentName": "Select", + "id": "node$8", + "props": { + "dataSource": [ + { + "label": "教师", + "value": "t" + }, + { + "label": "医生", + "value": "d" + }, + { + "label": "歌手", + "value": "s" + } + ] + } + } + ] + }, + { + "componentName": "Div", + "id": "node$9", + "props": { + "style": { + "textAlign": "center" + } + }, + "children": [ + { + "componentName": "Button.Group", + "id": "node$a", + "props": {}, + "children": [ + { + "componentName": "Button", + "id": "node$b", + "condition": { + "type": "JSExpression", + "value": "this.index >= 1" + }, + "loop": ["a", "b", "c"], + "props": { + "type": "primary", + "style": { + "margin": "0 5px 0 5px" + }, + }, + "children": [ + { + "type": "JSExpression", + "value": "this.item" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ], + "constants": { + "ENV": "prod", + "DOMAIN": "xxx.xxx.com" + }, + "css": "body {font-size: 12px;} .table { width: 100px;}", + "config": { + "sdkVersion": "1.0.3", + "historyMode": "hash", + "targetRootID": "J_Container", + "layout": { + "componentName": "BasicLayout", + "props": { + "logo": "...", + "name": "测试网站" + } + }, + "theme": { + "package": "@alife/theme-fusion", + "version": "^0.1.0", + "primary": "#ff9966" + } + }, + "meta": { + "name": "demo应用", + "git_group": "appGroup", + "project_name": "app_demo", + "description": "这是一个测试应用", + "spma": "spa23d", + "creator": "月飞" + } +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/.browserslistrc b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/.browserslistrc new file mode 100644 index 0000000000..55a130413d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/.browserslistrc @@ -0,0 +1,3 @@ +defaults +ios_saf 9 + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/.gitignore b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/.gitignore new file mode 100644 index 0000000000..4ec178818e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/.gitignore @@ -0,0 +1,25 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/README.md b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/README.md new file mode 100644 index 0000000000..6d9dd75215 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/README.md @@ -0,0 +1 @@ +This project is generated by lowcode-code-generator & lowcode-solution-icejs3. \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/ice.config.mts new file mode 100644 index 0000000000..fe77c9b6cd --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/ice.config.mts @@ -0,0 +1,90 @@ +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + }, + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = ` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + `; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion({ + importStyle: true, + }), + locales(), + plugin(), + ], +})); + diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/package.json new file mode 100644 index 0000000000..e234f0da02 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/package.json @@ -0,0 +1,48 @@ +{ + "name": "icejs3-demo-app", + "version": "0.1.5", + "description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。", + "dependencies": { + "moment": "^2.24.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router": "^6.9.0", + "react-router-dom": "^6.9.0", + "intl-messageformat": "^9.3.6", + "@alifd/next": "1.26.15", + "@ice/runtime": "^1.0.0", + "@alilc/lowcode-datasource-engine": "^1.0.0", + "@alilc/lowcode-datasource-url-params-handler": "^1.0.0", + "@alilc/b6-page": "^0.1.0", + "@alilc/b6-text": "^0.1.0", + "@alilc/b6-compact-legao-builtin": "1.x", + "antd": "3.x", + "@alilc/b6-util-mocks": "1.x" + }, + "devDependencies": { + "@ice/app": "^3.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/node": "^18.11.17", + "@ice/plugin-fusion": "^1.0.1", + "@ice/plugin-moment-locales": "^1.0.0", + "eslint": "^6.0.1", + "stylelint": "^13.2.0" + }, + "scripts": { + "start": "ice start", + "build": "ice build", + "lint": "npm run eslint && npm run stylelint", + "eslint": "eslint --cache --ext .js,.jsx ./", + "stylelint": "stylelint ./**/*.scss" + }, + "engines": { + "node": ">=14.0.0" + }, + "repository": { + "type": "git", + "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" + }, + "private": true, + "originTemplate": "@alifd/scaffold-lite-js" +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/app.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/app.ts new file mode 100644 index 0000000000..6d5856292d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/app.ts @@ -0,0 +1,13 @@ +import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +})); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/constants.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/constants.js new file mode 100644 index 0000000000..ea766c9da3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/constants.js @@ -0,0 +1,3 @@ +const __$$constants = {}; + +export default __$$constants; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/document.tsx new file mode 100644 index 0000000000..286be9f8ca --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/document.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/global.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/global.scss new file mode 100644 index 0000000000..82ca3eac73 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/global.scss @@ -0,0 +1,6 @@ +// 引入默认全局样式 +@import '@alifd/next/reset.scss'; + +body { + -webkit-font-smoothing: antialiased; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js new file mode 100644 index 0000000000..adbbe673dc --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js @@ -0,0 +1,77 @@ +const i18nConfig = {}; + +let locale = + typeof navigator === 'object' && typeof navigator.language === 'string' + ? navigator.language + : 'zh-CN'; + +const getLocale = () => locale; + +const setLocale = (target) => { + locale = target; +}; + +const isEmptyVariables = (variables) => + (Array.isArray(variables) && variables.length === 0) || + (typeof variables === 'object' && + (!variables || Object.keys(variables).length === 0)); + +// 按低代码规范里面的要求进行变量替换 +const format = (msg, variables) => + typeof msg === 'string' + ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + : msg; + +const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { + const msg = + i18nConfig[locale]?.[id] ?? + i18nConfig[locale.replace('-', '_')]?.[id] ?? + defaultMessage; + if (msg == null) { + console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); + return fallback === undefined ? `${id}` : fallback; + } + + return format(msg, variables); +}; + +const i18n = (id, params) => { + return i18nFormat({ id }, params); +}; + +// 将国际化的一些方法注入到目标对象&上下文中 +const _inject2 = (target) => { + target.i18n = i18n; + target.getLocale = getLocale; + target.setLocale = (locale) => { + setLocale(locale); + target.forceUpdate(); + }; + target._i18nText = (t) => { + // 优先取直接传过来的语料 + const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]; + if (localMsg != null) { + return format(localMsg, t.params); + } + + // 其次用项目级别的 + const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params); + if (projectMsg != null) { + return projectMsg; + } + + // 兜底用 use 指定的或默认语言的 + return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params); + }; + + // 注入到上下文中去 + if (target._context && target._context !== target) { + Object.assign(target._context, { + i18n, + getLocale, + setLocale: target.setLocale, + }); + } +}; + +export { getLocale, setLocale, i18n, i18nFormat, _inject2 }; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx new file mode 100644 index 0000000000..cc70d53bea --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx @@ -0,0 +1,14 @@ + +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss new file mode 100644 index 0000000000..81e77fda5f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss @@ -0,0 +1,15 @@ + +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx new file mode 100644 index 0000000000..265bfdaa07 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss new file mode 100644 index 0000000000..1ab56d3945 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -0,0 +1,20 @@ + +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx new file mode 100644 index 0000000000..911998b0d3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/index.jsx new file mode 100644 index 0000000000..18db44df5e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/index.jsx @@ -0,0 +1,81 @@ + +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/menuConfig.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/menuConfig.js new file mode 100644 index 0000000000..5332202be4 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/menuConfig.js @@ -0,0 +1,11 @@ + +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.css b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx new file mode 100644 index 0000000000..2945a9d8f5 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/Aaaa/index.jsx @@ -0,0 +1,118 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:react 框架的导出名和各种组件名除外。 +import React from 'react'; + +import { Page } from '@alilc/b6-page'; + +import { Text } from '@alilc/b6-text'; + +import { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler'; + +import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime'; + +import utils from '../../utils'; + +import * as __$$i18n from '../../i18n'; + +import __$$constants from '../../constants'; + +import './index.css'; + +class Aaaa$$Page extends React.Component { + _context = this; + + _dataSourceConfig = this._defineDataSourceConfig(); + _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, { + runtimeConfig: true, + requestHandlersMap: { + urlParams: __$$createUrlParamsRequestHandler(window.location.search), + }, + }); + + get dataSourceMap() { + return this._dataSourceEngine.dataSourceMap || {}; + } + + reloadDataSource = async () => { + await this._dataSourceEngine.reloadDataSource(); + }; + + get constants() { + return __$$constants || {}; + } + + constructor(props, context) { + super(props); + + this.utils = utils; + + __$$i18n._inject2(this); + + this.state = {}; + } + + $ = () => null; + + $$ = () => []; + + _defineDataSourceConfig() { + const _this = this; + return { + list: [ + { + id: 'urlParams', + type: 'urlParams', + description: 'URL参数', + options: function () { + return { + uri: '', + }; + }.bind(_this), + isInit: function () { + return undefined; + }.bind(_this), + }, + ], + }; + } + + componentDidMount() { + this._dataSourceEngine.reloadDataSource(); + } + + render() { + const __$$context = this._context || this; + const { state } = __$$context; + return ( + <div title="" backgroundColor="#fff" textColor="#333" style={{}}> + <Text + content="欢迎使用 BuildSuccess!sadsad" + style={{}} + fieldId="text_kp6ci11t" + /> + </div> + ); + } +} + +export default Aaaa$$Page; + +function __$$eval(expr) { + try { + return expr(); + } catch (error) {} +} + +function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; +} + +function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/layout.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/layout.jsx new file mode 100644 index 0000000000..50fbb2d1f1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/pages/layout.jsx @@ -0,0 +1,10 @@ +import { Outlet } from 'ice'; +import BasicLayout from '@/layouts/BasicLayout'; + +export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + ); +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/typings.d.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/typings.d.ts new file mode 100644 index 0000000000..a9f8de7ceb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/typings.d.ts @@ -0,0 +1,9 @@ +/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/utils.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/utils.js new file mode 100644 index 0000000000..868d471106 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/utils.js @@ -0,0 +1,61 @@ +import legaoBuiltin from '@alilc/b6-compact-legao-builtin'; + +import { message, Modal as modal } from 'antd'; + +import { mocks } from '@alilc/b6-util-mocks'; + +import { createRef } from 'react'; + +export class RefsManager { + constructor() { + this.refInsStore = {}; + } + + clearNullRefs() { + Object.keys(this.refInsStore).forEach((refName) => { + const filteredInsList = this.refInsStore[refName].filter( + (insRef) => !!insRef.current + ); + if (filteredInsList.length > 0) { + this.refInsStore[refName] = filteredInsList; + } else { + delete this.refInsStore[refName]; + } + }); + } + + get(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName][0].current; + } + + return null; + } + + getAll(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName].map((i) => i.current); + } + + return []; + } + + linkRef(refName) { + const refIns = createRef(); + this.refInsStore[refName] = this.refInsStore[refName] || []; + this.refInsStore[refName].push(refIns); + return refIns; + } +} + +export default { + legaoBuiltin, + + message, + + mocks, + + modal, +}; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/schema.json5 new file mode 100644 index 0000000000..76e8248cbb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/schema.json5 @@ -0,0 +1,123 @@ +{ + version: '1.0.0', + componentsMap: [ + { + package: '@alilc/b6-page', + version: '^0.1.0', + componentName: 'Page', + destructuring: true, + exportName: 'Page', + }, + { + package: '@alilc/b6-text', + version: '^0.1.0', + componentName: 'Text', + destructuring: true, + exportName: 'Text', + }, + ], + componentsTree: [ + { + componentName: 'Page', + id: 'node_ockp6ci0hm1', + props: { + title: '', + backgroundColor: '#fff', + textColor: '#333', + style: {}, + }, + fileName: 'aaaa', + dataSource: { + list: [ + { + id: 'urlParams', + type: 'urlParams', + description: 'URL参数', + options: { + uri: '', + }, + }, + ], + }, + children: [ + { + componentName: 'Text', + id: 'node_ockp6ci0hm2', + props: { + content: '欢迎使用 BuildSuccess!sadsad', + style: {}, + fieldId: 'text_kp6ci11t', + }, + }, + ], + meta: { + router: '/aaaa', + }, + methodsModule: { + type: 'JSModule', + compiled: '"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n value: true\n});\nexports.helloPage = helloPage;\n\n/**\n * Private, and can be re-used functions\n * Actions panel help documentation:\n * @see https://yuque.antfin.com/docs/share/89ca7965-6387-4e3a-9964-81929ed48f1e\n */\nfunction printLog(obj) {\n console.info(obj);\n}\n/**\n * page function\n */\n\n\nfunction helloPage() {\n console.log(\'hello page\');\n}', + source: "/**\n * Private, and can be re-used functions\n * Actions panel help documentation:\n * @see https://yuque.antfin.com/docs/share/89ca7965-6387-4e3a-9964-81929ed48f1e\n */\nfunction printLog(obj) {\n console.info(obj);\n}\n\n/**\n * page function\n */\nexport function helloPage() {\n console.log('hello page');\n}", + }, + }, + ], + i18n: {}, + utils: [ + { + name: 'legaoBuiltin', + type: 'npm', + content: { + exportName: 'legaoBuiltin', + package: '@alilc/b6-compact-legao-builtin', + version: '1.x', + }, + }, + { + name: 'message', + type: 'npm', + content: { + package: 'antd', + version: '3.x', + destructuring: true, + exportName: 'message', + }, + }, + { + name: 'mocks', + type: 'npm', + content: { + package: '@alilc/b6-util-mocks', + version: '1.x', + exportName: 'mocks', + destructuring: true, + }, + }, + { + name: 'modal', + type: 'npm', + content: { + package: 'antd', + version: '3.x', + destructuring: true, + exportName: 'Modal', + }, + }, + ], + constants: {}, + dataSource: { + list: [], + }, + config: { + sdkVersion: '1.0.3', + historyMode: 'hash', + targetRootID: 'root', + miniAppBuildType: 'runtime', + }, + meta: { + name: 'jinyuan-test2', + git_group: 'b6', + project_name: 'jinyuan-test2', + description: '瑾源测试', + spma: 'spmademo', + creator: '张三', + }, +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/.browserslistrc b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/.browserslistrc new file mode 100644 index 0000000000..55a130413d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/.browserslistrc @@ -0,0 +1,3 @@ +defaults +ios_saf 9 + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/.gitignore b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/.gitignore new file mode 100644 index 0000000000..4ec178818e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/.gitignore @@ -0,0 +1,25 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/README.md b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/README.md new file mode 100644 index 0000000000..6d9dd75215 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/README.md @@ -0,0 +1 @@ +This project is generated by lowcode-code-generator & lowcode-solution-icejs3. \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/ice.config.mts new file mode 100644 index 0000000000..fe77c9b6cd --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/ice.config.mts @@ -0,0 +1,90 @@ +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + }, + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = ` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + `; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion({ + importStyle: true, + }), + locales(), + plugin(), + ], +})); + diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/package.json new file mode 100644 index 0000000000..63717e3193 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/package.json @@ -0,0 +1,42 @@ +{ + "name": "icejs3-demo-app", + "version": "0.1.5", + "description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。", + "dependencies": { + "moment": "^2.24.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router": "^6.9.0", + "react-router-dom": "^6.9.0", + "intl-messageformat": "^9.3.6", + "@alifd/next": "1.19.18", + "@ice/runtime": "^1.0.0", + "@alilc/lowcode-datasource-engine": "^1.0.0" + }, + "devDependencies": { + "@ice/app": "^3.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/node": "^18.11.17", + "@ice/plugin-fusion": "^1.0.1", + "@ice/plugin-moment-locales": "^1.0.0", + "eslint": "^6.0.1", + "stylelint": "^13.2.0" + }, + "scripts": { + "start": "ice start", + "build": "ice build", + "lint": "npm run eslint && npm run stylelint", + "eslint": "eslint --cache --ext .js,.jsx ./", + "stylelint": "stylelint ./**/*.scss" + }, + "engines": { + "node": ">=14.0.0" + }, + "repository": { + "type": "git", + "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" + }, + "private": true, + "originTemplate": "@alifd/scaffold-lite-js" +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/app.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/app.ts new file mode 100644 index 0000000000..6d5856292d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/app.ts @@ -0,0 +1,13 @@ +import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +})); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/constants.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/constants.js new file mode 100644 index 0000000000..91198f9044 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/constants.js @@ -0,0 +1,3 @@ +const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' }; + +export default __$$constants; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/document.tsx new file mode 100644 index 0000000000..286be9f8ca --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/document.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/global.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/global.scss new file mode 100644 index 0000000000..ed7204b4a3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/global.scss @@ -0,0 +1,13 @@ +// 引入默认全局样式 +@import '@alifd/next/reset.scss'; + +body { + -webkit-font-smoothing: antialiased; +} + +body { + font-size: 12px; +} +.table { + width: 100px; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/i18n.js new file mode 100644 index 0000000000..2fa87027f5 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/i18n.js @@ -0,0 +1,86 @@ +const i18nConfig = { + 'zh-CN': { + 'i18n-jwg27yo4': '你好', + 'i18n-jwg27yo3': '中国', + }, + 'en-US': { + 'i18n-jwg27yo4': 'Hello', + 'i18n-jwg27yo3': 'China', + }, +}; + +let locale = + typeof navigator === 'object' && typeof navigator.language === 'string' + ? navigator.language + : 'zh-CN'; + +const getLocale = () => locale; + +const setLocale = (target) => { + locale = target; +}; + +const isEmptyVariables = (variables) => + (Array.isArray(variables) && variables.length === 0) || + (typeof variables === 'object' && + (!variables || Object.keys(variables).length === 0)); + +// 按低代码规范里面的要求进行变量替换 +const format = (msg, variables) => + typeof msg === 'string' + ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + : msg; + +const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { + const msg = + i18nConfig[locale]?.[id] ?? + i18nConfig[locale.replace('-', '_')]?.[id] ?? + defaultMessage; + if (msg == null) { + console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); + return fallback === undefined ? `${id}` : fallback; + } + + return format(msg, variables); +}; + +const i18n = (id, params) => { + return i18nFormat({ id }, params); +}; + +// 将国际化的一些方法注入到目标对象&上下文中 +const _inject2 = (target) => { + target.i18n = i18n; + target.getLocale = getLocale; + target.setLocale = (locale) => { + setLocale(locale); + target.forceUpdate(); + }; + target._i18nText = (t) => { + // 优先取直接传过来的语料 + const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]; + if (localMsg != null) { + return format(localMsg, t.params); + } + + // 其次用项目级别的 + const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params); + if (projectMsg != null) { + return projectMsg; + } + + // 兜底用 use 指定的或默认语言的 + return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params); + }; + + // 注入到上下文中去 + if (target._context && target._context !== target) { + Object.assign(target._context, { + i18n, + getLocale, + setLocale: target.setLocale, + }); + } +}; + +export { getLocale, setLocale, i18n, i18nFormat, _inject2 }; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx new file mode 100644 index 0000000000..cc70d53bea --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx @@ -0,0 +1,14 @@ + +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss new file mode 100644 index 0000000000..81e77fda5f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss @@ -0,0 +1,15 @@ + +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx new file mode 100644 index 0000000000..265bfdaa07 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss new file mode 100644 index 0000000000..1ab56d3945 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -0,0 +1,20 @@ + +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx new file mode 100644 index 0000000000..911998b0d3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/index.jsx new file mode 100644 index 0000000000..18db44df5e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/index.jsx @@ -0,0 +1,81 @@ + +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js new file mode 100644 index 0000000000..5332202be4 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js @@ -0,0 +1,11 @@ + +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.css b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.jsx new file mode 100644 index 0000000000..6cb430b1b8 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.jsx @@ -0,0 +1,119 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:react 框架的导出名和各种组件名除外。 +import React from 'react'; + +import { Form, Input, NumberPicker, Select, Button } from '@alifd/next'; + +import utils, { RefsManager } from '../../utils'; + +import * as __$$i18n from '../../i18n'; + +import __$$constants from '../../constants'; + +import './index.css'; + +class Test$$Page extends React.Component { + _context = this; + + get constants() { + return __$$constants || {}; + } + + constructor(props, context) { + super(props); + + this.utils = utils; + + this._refsManager = new RefsManager(); + + __$$i18n._inject2(this); + + this.state = { text: 'outter' }; + } + + $ = (refName) => { + return this._refsManager.get(refName); + }; + + $$ = (refName) => { + return this._refsManager.getAll(refName); + }; + + componentDidMount() { + console.log('componentDidMount'); + } + + render() { + const __$$context = this._context || this; + const { state } = __$$context; + return ( + <div ref={this._refsManager.linkRef('outterView')} autoLoading={true}> + <Form + labelCol={__$$eval(() => this.state.colNum)} + style={{}} + ref={this._refsManager.linkRef('testForm')} + > + <Form.Item + label={__$$eval(() => this.i18n('i18n-jwg27yo4'))} + name="name" + initValue="李雷" + > + <Input placeholder="请输入" size="medium" style={{ width: 320 }} /> + </Form.Item> + <Form.Item label="年龄:" name="age" initValue="22"> + <NumberPicker size="medium" type="normal" /> + </Form.Item> + <Form.Item label="职业:" name="profession"> + <Select + dataSource={[ + { label: '教师', value: 't' }, + { label: '医生', value: 'd' }, + { label: '歌手', value: 's' }, + ]} + /> + </Form.Item> + <div style={{ textAlign: 'center' }}> + <Button.Group> + <Button + type="primary" + style={{ margin: '0 5px 0 5px' }} + htmlType="submit" + > + 提交 + </Button> + <Button + type="normal" + style={{ margin: '0 5px 0 5px' }} + htmlType="reset" + > + 重置 + </Button> + </Button.Group> + </div> + </Form> + </div> + ); + } +} + +export default Test$$Page; + +function __$$eval(expr) { + try { + return expr(); + } catch (error) {} +} + +function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; +} + +function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/layout.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/layout.jsx new file mode 100644 index 0000000000..50fbb2d1f1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/layout.jsx @@ -0,0 +1,10 @@ +import { Outlet } from 'ice'; +import BasicLayout from '@/layouts/BasicLayout'; + +export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + ); +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/typings.d.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/typings.d.ts new file mode 100644 index 0000000000..a9f8de7ceb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/typings.d.ts @@ -0,0 +1,9 @@ +/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/utils.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/utils.js new file mode 100644 index 0000000000..1190717924 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/utils.js @@ -0,0 +1,47 @@ +import { createRef } from 'react'; + +export class RefsManager { + constructor() { + this.refInsStore = {}; + } + + clearNullRefs() { + Object.keys(this.refInsStore).forEach((refName) => { + const filteredInsList = this.refInsStore[refName].filter( + (insRef) => !!insRef.current + ); + if (filteredInsList.length > 0) { + this.refInsStore[refName] = filteredInsList; + } else { + delete this.refInsStore[refName]; + } + }); + } + + get(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName][0].current; + } + + return null; + } + + getAll(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName].map((i) => i.current); + } + + return []; + } + + linkRef(refName) { + const refIns = createRef(); + this.refInsStore[refName] = this.refInsStore[refName] || []; + this.refInsStore[refName].push(refIns); + return refIns; + } +} + +export default {}; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/schema.json5 new file mode 100644 index 0000000000..2228212067 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/schema.json5 @@ -0,0 +1,256 @@ +{ + "version": "1.0.0", + "componentsMap": [ + { + "componentName": "Button", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Button" + }, + { + "componentName": "Button.Group", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Button", + "subName": "Group" + }, + { + "componentName": "Input", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Input" + }, + { + "componentName": "Form", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Form" + }, + { + "componentName": "Form.Item", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Form", + "subName": "Item" + }, + { + "componentName": "NumberPicker", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "NumberPicker" + }, + { + "componentName": "Select", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Select" + } + ], + "componentsTree": [ + { + "componentName": "Page", + "id": "node$1", + "meta": { + "title": "测试", + "router": "/" + }, + "props": { + "ref": "outterView", + "autoLoading": true + }, + "fileName": "test", + "state": { + "text": "outter" + }, + "lifeCycles": { + "componentDidMount": { + "type": "JSFunction", + "value": "function() { console.log('componentDidMount'); }" + } + }, + "children": [ + { + "componentName": "Form", + "id": "node$2", + "props": { + "labelCol": { + "type": "JSExpression", + "value": "this.state.colNum" + }, + "style": {}, + "ref": "testForm" + }, + "children": [ + { + "componentName": "Form.Item", + "id": "node$3", + "props": { + "label": { + type: 'JSExpression', + value: 'this.i18n("i18n-jwg27yo4")', + }, + "name": "name", + "initValue": "李雷" + }, + "children": [ + { + "componentName": "Input", + "id": "node$4", + "props": { + "placeholder": "请输入", + "size": "medium", + "style": { + "width": 320 + } + } + } + ] + }, + { + "componentName": "Form.Item", + "id": "node$5", + "props": { + "label": "年龄:", + "name": "age", + "initValue": "22" + }, + "children": [ + { + "componentName": "NumberPicker", + "id": "node$6", + "props": { + "size": "medium", + "type": "normal" + } + } + ] + }, + { + "componentName": "Form.Item", + "id": "node$7", + "props": { + "label": "职业:", + "name": "profession" + }, + "children": [ + { + "componentName": "Select", + "id": "node$8", + "props": { + "dataSource": [ + { + "label": "教师", + "value": "t" + }, + { + "label": "医生", + "value": "d" + }, + { + "label": "歌手", + "value": "s" + } + ] + } + } + ] + }, + { + "componentName": "Div", + "id": "node$9", + "props": { + "style": { + "textAlign": "center" + } + }, + "children": [ + { + "componentName": "Button.Group", + "id": "node$a", + "props": {}, + "children": [ + { + "componentName": "Button", + "id": "node$b", + "props": { + "type": "primary", + "style": { + "margin": "0 5px 0 5px" + }, + "htmlType": "submit" + }, + "children": [ + "提交" + ] + }, + { + "componentName": "Button", + "id": "node$d", + "props": { + "type": "normal", + "style": { + "margin": "0 5px 0 5px" + }, + "htmlType": "reset" + }, + "children": [ + "重置" + ] + } + ] + } + ] + } + ] + } + ] + } + ], + "constants": { + "ENV": "prod", + "DOMAIN": "xxx.xxx.com" + }, + "i18n": { + "zh-CN": { + "i18n-jwg27yo4": "你好", + "i18n-jwg27yo3": "中国" + }, + "en-US": { + "i18n-jwg27yo4": "Hello", + "i18n-jwg27yo3": "China" + } + }, + "css": "body {font-size: 12px;} .table { width: 100px;}", + "config": { + "sdkVersion": "1.0.3", + "historyMode": "hash", + "targetRootID": "J_Container", + "layout": { + "componentName": "BasicLayout", + "props": { + "logo": "...", + "name": "测试网站" + } + }, + "theme": { + "package": "@alife/theme-fusion", + "version": "^0.1.0", + "primary": "#ff9966" + } + }, + "meta": { + "name": "demo应用", + "git_group": "appGroup", + "project_name": "app_demo", + "description": "这是一个测试应用", + "spma": "spa23d", + "creator": "月飞" + } +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/.browserslistrc b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/.browserslistrc new file mode 100644 index 0000000000..55a130413d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/.browserslistrc @@ -0,0 +1,3 @@ +defaults +ios_saf 9 + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/.gitignore b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/.gitignore new file mode 100644 index 0000000000..4ec178818e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/.gitignore @@ -0,0 +1,25 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/README.md b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/README.md new file mode 100644 index 0000000000..6d9dd75215 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/README.md @@ -0,0 +1 @@ +This project is generated by lowcode-code-generator & lowcode-solution-icejs3. \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/ice.config.mts new file mode 100644 index 0000000000..fe77c9b6cd --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/ice.config.mts @@ -0,0 +1,90 @@ +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + }, + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = ` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + `; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion({ + importStyle: true, + }), + locales(), + plugin(), + ], +})); + diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/package.json new file mode 100644 index 0000000000..63717e3193 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/package.json @@ -0,0 +1,42 @@ +{ + "name": "icejs3-demo-app", + "version": "0.1.5", + "description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。", + "dependencies": { + "moment": "^2.24.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router": "^6.9.0", + "react-router-dom": "^6.9.0", + "intl-messageformat": "^9.3.6", + "@alifd/next": "1.19.18", + "@ice/runtime": "^1.0.0", + "@alilc/lowcode-datasource-engine": "^1.0.0" + }, + "devDependencies": { + "@ice/app": "^3.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/node": "^18.11.17", + "@ice/plugin-fusion": "^1.0.1", + "@ice/plugin-moment-locales": "^1.0.0", + "eslint": "^6.0.1", + "stylelint": "^13.2.0" + }, + "scripts": { + "start": "ice start", + "build": "ice build", + "lint": "npm run eslint && npm run stylelint", + "eslint": "eslint --cache --ext .js,.jsx ./", + "stylelint": "stylelint ./**/*.scss" + }, + "engines": { + "node": ">=14.0.0" + }, + "repository": { + "type": "git", + "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" + }, + "private": true, + "originTemplate": "@alifd/scaffold-lite-js" +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/app.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/app.ts new file mode 100644 index 0000000000..6d5856292d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/app.ts @@ -0,0 +1,13 @@ +import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +})); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/constants.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/constants.js new file mode 100644 index 0000000000..91198f9044 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/constants.js @@ -0,0 +1,3 @@ +const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' }; + +export default __$$constants; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/document.tsx new file mode 100644 index 0000000000..286be9f8ca --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/document.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/global.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/global.scss new file mode 100644 index 0000000000..ed7204b4a3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/global.scss @@ -0,0 +1,13 @@ +// 引入默认全局样式 +@import '@alifd/next/reset.scss'; + +body { + -webkit-font-smoothing: antialiased; +} + +body { + font-size: 12px; +} +.table { + width: 100px; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/i18n.js new file mode 100644 index 0000000000..2fa87027f5 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/i18n.js @@ -0,0 +1,86 @@ +const i18nConfig = { + 'zh-CN': { + 'i18n-jwg27yo4': '你好', + 'i18n-jwg27yo3': '中国', + }, + 'en-US': { + 'i18n-jwg27yo4': 'Hello', + 'i18n-jwg27yo3': 'China', + }, +}; + +let locale = + typeof navigator === 'object' && typeof navigator.language === 'string' + ? navigator.language + : 'zh-CN'; + +const getLocale = () => locale; + +const setLocale = (target) => { + locale = target; +}; + +const isEmptyVariables = (variables) => + (Array.isArray(variables) && variables.length === 0) || + (typeof variables === 'object' && + (!variables || Object.keys(variables).length === 0)); + +// 按低代码规范里面的要求进行变量替换 +const format = (msg, variables) => + typeof msg === 'string' + ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + : msg; + +const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { + const msg = + i18nConfig[locale]?.[id] ?? + i18nConfig[locale.replace('-', '_')]?.[id] ?? + defaultMessage; + if (msg == null) { + console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); + return fallback === undefined ? `${id}` : fallback; + } + + return format(msg, variables); +}; + +const i18n = (id, params) => { + return i18nFormat({ id }, params); +}; + +// 将国际化的一些方法注入到目标对象&上下文中 +const _inject2 = (target) => { + target.i18n = i18n; + target.getLocale = getLocale; + target.setLocale = (locale) => { + setLocale(locale); + target.forceUpdate(); + }; + target._i18nText = (t) => { + // 优先取直接传过来的语料 + const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]; + if (localMsg != null) { + return format(localMsg, t.params); + } + + // 其次用项目级别的 + const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params); + if (projectMsg != null) { + return projectMsg; + } + + // 兜底用 use 指定的或默认语言的 + return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params); + }; + + // 注入到上下文中去 + if (target._context && target._context !== target) { + Object.assign(target._context, { + i18n, + getLocale, + setLocale: target.setLocale, + }); + } +}; + +export { getLocale, setLocale, i18n, i18nFormat, _inject2 }; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx new file mode 100644 index 0000000000..cc70d53bea --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx @@ -0,0 +1,14 @@ + +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss new file mode 100644 index 0000000000..81e77fda5f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss @@ -0,0 +1,15 @@ + +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx new file mode 100644 index 0000000000..265bfdaa07 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss new file mode 100644 index 0000000000..1ab56d3945 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -0,0 +1,20 @@ + +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx new file mode 100644 index 0000000000..911998b0d3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/index.jsx new file mode 100644 index 0000000000..18db44df5e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/index.jsx @@ -0,0 +1,81 @@ + +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/menuConfig.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/menuConfig.js new file mode 100644 index 0000000000..5332202be4 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/menuConfig.js @@ -0,0 +1,11 @@ + +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.css b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.jsx new file mode 100644 index 0000000000..18c5e0a57a --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.jsx @@ -0,0 +1,93 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:react 框架的导出名和各种组件名除外。 +import React from 'react'; + +import Super, { + Button, + Input as CustomInput, + Form, + NumberPicker, + Select, + SearchTable as SearchTableExport, +} from '@alifd/next'; + +import SuperOther from '@alifd/next'; + +import utils from '../../utils'; + +import * as __$$i18n from '../../i18n'; + +import __$$constants from '../../constants'; + +import './index.css'; + +const SuperSub = Super.Sub; + +const SelectOption = Select.Option; + +const SearchTable = SearchTableExport.default; + +class Test$$Page extends React.Component { + _context = this; + + get constants() { + return __$$constants || {}; + } + + constructor(props, context) { + super(props); + + this.utils = utils; + + __$$i18n._inject2(this); + + this.state = {}; + } + + $ = () => null; + + $$ = () => []; + + componentDidMount() {} + + render() { + const __$$context = this._context || this; + const { state } = __$$context; + return ( + <div> + <Super title={__$$eval(() => this.state.title)} /> + <SuperSub /> + <SuperOther /> + <Button /> + <Button.Group /> + <CustomInput /> + <Form.Item /> + <NumberPicker /> + <SelectOption /> + <SearchTable /> + </div> + ); + } +} + +export default Test$$Page; + +function __$$eval(expr) { + try { + return expr(); + } catch (error) {} +} + +function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; +} + +function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/layout.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/layout.jsx new file mode 100644 index 0000000000..50fbb2d1f1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/layout.jsx @@ -0,0 +1,10 @@ +import { Outlet } from 'ice'; +import BasicLayout from '@/layouts/BasicLayout'; + +export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + ); +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/typings.d.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/typings.d.ts new file mode 100644 index 0000000000..a9f8de7ceb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/typings.d.ts @@ -0,0 +1,9 @@ +/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/utils.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/utils.js new file mode 100644 index 0000000000..1190717924 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/utils.js @@ -0,0 +1,47 @@ +import { createRef } from 'react'; + +export class RefsManager { + constructor() { + this.refInsStore = {}; + } + + clearNullRefs() { + Object.keys(this.refInsStore).forEach((refName) => { + const filteredInsList = this.refInsStore[refName].filter( + (insRef) => !!insRef.current + ); + if (filteredInsList.length > 0) { + this.refInsStore[refName] = filteredInsList; + } else { + delete this.refInsStore[refName]; + } + }); + } + + get(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName][0].current; + } + + return null; + } + + getAll(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName].map((i) => i.current); + } + + return []; + } + + linkRef(refName) { + const refIns = createRef(); + this.refInsStore[refName] = this.refInsStore[refName] || []; + this.refInsStore[refName].push(refIns); + return refIns; + } +} + +export default {}; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/schema.json5 new file mode 100644 index 0000000000..173b793e13 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/schema.json5 @@ -0,0 +1,159 @@ +{ + "version": "1.0.0", + "componentsMap": [ + { + "componentName": "Super", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": false, + "exportName": "Super" + }, + { + "componentName": "SuperOther", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": false, + "exportName": "Super" + }, + { + "componentName": "SuperSub", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": false, + "exportName": "Super", + "subName": "Sub", + }, + { + "componentName": "Button", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Button" + }, + { + "componentName": "SearchTable", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "SearchTable", + "subName": "default", + }, + { + "componentName": "Button.Group", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Button", + "subName": "Group" + }, + { + "componentName": "CustomInput", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Input" + }, + { + "componentName": "Form", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Form" + }, + { + "componentName": "Form.Item", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Form", + "subName": "Item" + }, + { + "componentName": "NumberPicker", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "NumberPicker" + }, + { + "componentName": "SelectOption", + "package": "@alifd/next", + "version": "1.19.18", + "destructuring": true, + "exportName": "Select", + "subName": "Option" + } + ], + "componentsTree": [ + { + "componentName": "Page", + "id": "node$1", + "meta": { + "title": "测试", + "router": "/" + }, + "fileName": "test", + "children": [ + { + "componentName": "Super", + "props": { + "title": { + "type":"variable", + "value":"标题", + "variable":"this.state.title" + } + } + }, + { "componentName": "SuperSub" }, + { "componentName": "SuperOther" }, + { "componentName": "Button" }, + { "componentName": "Button.Group" }, + { "componentName": "CustomInput" }, + { "componentName": "Form.Item" }, + { "componentName": "NumberPicker" }, + { "componentName": "SelectOption" }, + { "componentName": "SearchTable" }, + ] + } + ], + "constants": { + "ENV": "prod", + "DOMAIN": "xxx.xxx.com" + }, + "i18n": { + "zh-CN": { + "i18n-jwg27yo4": "你好", + "i18n-jwg27yo3": "中国" + }, + "en-US": { + "i18n-jwg27yo4": "Hello", + "i18n-jwg27yo3": "China" + } + }, + "css": "body {font-size: 12px;} .table { width: 100px;}", + "config": { + "sdkVersion": "1.0.3", + "historyMode": "hash", + "targetRootID": "J_Container", + "layout": { + "componentName": "BasicLayout", + "props": { + "logo": "...", + "name": "测试网站" + } + }, + "theme": { + "package": "@alife/theme-fusion", + "version": "^0.1.0", + "primary": "#ff9966" + } + }, + "meta": { + "name": "demo应用", + "git_group": "appGroup", + "project_name": "app_demo", + "description": "这是一个测试应用", + "spma": "spa23d", + "creator": "月飞" + } +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/.browserslistrc b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/.browserslistrc new file mode 100644 index 0000000000..55a130413d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/.browserslistrc @@ -0,0 +1,3 @@ +defaults +ios_saf 9 + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/.gitignore b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/.gitignore new file mode 100644 index 0000000000..4ec178818e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/.gitignore @@ -0,0 +1,25 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/README.md b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/README.md new file mode 100644 index 0000000000..6d9dd75215 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/README.md @@ -0,0 +1 @@ +This project is generated by lowcode-code-generator & lowcode-solution-icejs3. \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/ice.config.mts new file mode 100644 index 0000000000..fe77c9b6cd --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/ice.config.mts @@ -0,0 +1,90 @@ +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + }, + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = ` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + `; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion({ + importStyle: true, + }), + locales(), + plugin(), + ], +})); + diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/package.json new file mode 100644 index 0000000000..43f4440856 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/package.json @@ -0,0 +1,45 @@ +{ + "name": "icejs3-demo-app", + "version": "0.1.5", + "description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。", + "dependencies": { + "moment": "^2.24.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router": "^6.9.0", + "react-router-dom": "^6.9.0", + "intl-messageformat": "^9.3.6", + "@alifd/next": "1.26.15", + "@ice/runtime": "^1.0.0", + "@alilc/lowcode-datasource-engine": "^1.0.0", + "@alilc/lowcode-datasource-fetch-handler": "^1.0.0", + "@alife/container": "^1.0.0", + "@alife/mc-assets-1935": "0.1.9" + }, + "devDependencies": { + "@ice/app": "^3.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/node": "^18.11.17", + "@ice/plugin-fusion": "^1.0.1", + "@ice/plugin-moment-locales": "^1.0.0", + "eslint": "^6.0.1", + "stylelint": "^13.2.0" + }, + "scripts": { + "start": "ice start", + "build": "ice build", + "lint": "npm run eslint && npm run stylelint", + "eslint": "eslint --cache --ext .js,.jsx ./", + "stylelint": "stylelint ./**/*.scss" + }, + "engines": { + "node": ">=14.0.0" + }, + "repository": { + "type": "git", + "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" + }, + "private": true, + "originTemplate": "@alifd/scaffold-lite-js" +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/app.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/app.ts new file mode 100644 index 0000000000..6d5856292d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/app.ts @@ -0,0 +1,13 @@ +import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +})); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/constants.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/constants.js new file mode 100644 index 0000000000..ea766c9da3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/constants.js @@ -0,0 +1,3 @@ +const __$$constants = {}; + +export default __$$constants; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/document.tsx new file mode 100644 index 0000000000..286be9f8ca --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/document.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/global.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/global.scss new file mode 100644 index 0000000000..82ca3eac73 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/global.scss @@ -0,0 +1,6 @@ +// 引入默认全局样式 +@import '@alifd/next/reset.scss'; + +body { + -webkit-font-smoothing: antialiased; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/i18n.js new file mode 100644 index 0000000000..adbbe673dc --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/i18n.js @@ -0,0 +1,77 @@ +const i18nConfig = {}; + +let locale = + typeof navigator === 'object' && typeof navigator.language === 'string' + ? navigator.language + : 'zh-CN'; + +const getLocale = () => locale; + +const setLocale = (target) => { + locale = target; +}; + +const isEmptyVariables = (variables) => + (Array.isArray(variables) && variables.length === 0) || + (typeof variables === 'object' && + (!variables || Object.keys(variables).length === 0)); + +// 按低代码规范里面的要求进行变量替换 +const format = (msg, variables) => + typeof msg === 'string' + ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + : msg; + +const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { + const msg = + i18nConfig[locale]?.[id] ?? + i18nConfig[locale.replace('-', '_')]?.[id] ?? + defaultMessage; + if (msg == null) { + console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); + return fallback === undefined ? `${id}` : fallback; + } + + return format(msg, variables); +}; + +const i18n = (id, params) => { + return i18nFormat({ id }, params); +}; + +// 将国际化的一些方法注入到目标对象&上下文中 +const _inject2 = (target) => { + target.i18n = i18n; + target.getLocale = getLocale; + target.setLocale = (locale) => { + setLocale(locale); + target.forceUpdate(); + }; + target._i18nText = (t) => { + // 优先取直接传过来的语料 + const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]; + if (localMsg != null) { + return format(localMsg, t.params); + } + + // 其次用项目级别的 + const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params); + if (projectMsg != null) { + return projectMsg; + } + + // 兜底用 use 指定的或默认语言的 + return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params); + }; + + // 注入到上下文中去 + if (target._context && target._context !== target) { + Object.assign(target._context, { + i18n, + getLocale, + setLocale: target.setLocale, + }); + } +}; + +export { getLocale, setLocale, i18n, i18nFormat, _inject2 }; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx new file mode 100644 index 0000000000..cc70d53bea --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx @@ -0,0 +1,14 @@ + +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss new file mode 100644 index 0000000000..81e77fda5f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss @@ -0,0 +1,15 @@ + +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx new file mode 100644 index 0000000000..265bfdaa07 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss new file mode 100644 index 0000000000..1ab56d3945 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -0,0 +1,20 @@ + +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx new file mode 100644 index 0000000000..911998b0d3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/index.jsx new file mode 100644 index 0000000000..18db44df5e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/index.jsx @@ -0,0 +1,81 @@ + +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/menuConfig.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/menuConfig.js new file mode 100644 index 0000000000..5332202be4 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/menuConfig.js @@ -0,0 +1,11 @@ + +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/Test/index.css b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/Test/index.css new file mode 100644 index 0000000000..066114aeeb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/Test/index.css @@ -0,0 +1,8 @@ +body { + font-size: 12px; +} + +.botton { + width: 100px; + color: #ff00ff; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/Test/index.jsx new file mode 100644 index 0000000000..6400d7445b --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/Test/index.jsx @@ -0,0 +1,292 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:react 框架的导出名和各种组件名除外。 +import React from 'react'; + +import { + Page as NextPage, + Block as NextBlock, + P as NextP, + Text as NextText, +} from '@alife/container/lib/index.js'; + +import { AliSearchTable as AliSearchTableExport } from '@alife/mc-assets-1935/build/lowcode/index.js'; + +import { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowcode-datasource-fetch-handler'; + +import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime'; + +import utils, { RefsManager } from '../../utils'; + +import * as __$$i18n from '../../i18n'; + +import __$$constants from '../../constants'; + +import './index.css'; + +const NextBlockCell = NextBlock.Cell; + +const AliSearchTable = AliSearchTableExport.default; + +class Test$$Page extends React.Component { + _context = this; + + _dataSourceConfig = this._defineDataSourceConfig(); + _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, { + runtimeConfig: true, + requestHandlersMap: { fetch: __$$createFetchRequestHandler() }, + }); + + get dataSourceMap() { + return this._dataSourceEngine.dataSourceMap || {}; + } + + reloadDataSource = async () => { + await this._dataSourceEngine.reloadDataSource(); + }; + + get constants() { + return __$$constants || {}; + } + + constructor(props, context) { + super(props); + + this.utils = utils; + + this._refsManager = new RefsManager(); + + __$$i18n._inject2(this); + + this.state = { text: 'outter', isShowDialog: false }; + } + + $ = (refName) => { + return this._refsManager.get(refName); + }; + + $$ = (refName) => { + return this._refsManager.getAll(refName); + }; + + _defineDataSourceConfig() { + const _this = this; + return { + list: [ + { + type: 'fetch', + isInit: function () { + return true; + }.bind(_this), + options: function () { + return { + params: {}, + method: 'GET', + isCors: true, + timeout: 5000, + headers: {}, + uri: 'https://mocks.xxx.com/mock/jjpin/user/list', + }; + }.bind(_this), + id: 'users', + }, + ], + }; + } + + componentWillUnmount() { + console.log('will umount'); + } + + componentDidUpdate(prevProps, prevState, snapshot) { + console.log(this.state); + } + + testFunc() { + console.log('test func'); + } + + onClick() { + this.setState({ + isShowDialog: true, + }); + } + + closeDialog() { + this.setState({ + isShowDialog: false, + }); + } + + onSearch(values) { + console.log('search form:', values); + console.log(this.dataSourceMap); + this.dataSourceMap['users'].load(values); + } + + onClear() { + console.log('form reset'); + this.setState({ + isShowDialog: true, + }); + } + + onPageChange(page, pageSize) { + console.log(`page: ${page}, pageSize: ${pageSize}`); + } + + componentDidMount() { + this._dataSourceEngine.reloadDataSource(); + + console.log('did mount'); + } + + render() { + const __$$context = this._context || this; + const { state } = __$$context; + return ( + <div + ref={this._refsManager.linkRef('outterView')} + style={{ height: '100%' }} + > + <NextPage + columns={12} + placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }} + placeholder="页面主体内容:拖拽Block布局组件到这里" + header={ + <NextP + wrap={true} + type="body2" + verAlign="middle" + textSpacing={true} + align="left" + flex={true} + > + <NextText type="h5">员工列表</NextText> + </NextP> + } + headerTest={[]} + headerProps={{ background: 'surface' }} + footer={null} + minHeight="100vh" + > + <NextBlock + prefix="next-" + placeholderStyle={{ height: '100%' }} + noPadding={false} + noBorder={false} + background="surface" + colSpan={12} + rowSpan={1} + childTotalColumns="1fr" + > + <NextBlockCell + title="" + primaryKey="732" + prefix="next-" + placeholderStyle={{ height: '100%' }} + colSpan={1} + rowSpan={1} + > + <NextP + wrap={true} + type="body2" + textSpacing={true} + verAlign="center" + align="flex-start" + flex={true} + > + <AliSearchTable + dataSource={__$$eval(() => this.state.users.data)} + rowKey="workid" + columns={[ + { title: '花名', dataIndex: 'cname' }, + { title: 'user_id', dataIndex: 'workid' }, + { title: '部门', dataIndex: 'dep' }, + ]} + searchItems={[ + { label: '姓名', name: 'cname' }, + { label: '部门', name: 'dep' }, + ]} + onSearch={function () { + return this.onSearch.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + onClear={function () { + return this.onClear.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + pagination={{ + defaultPageSize: '', + onPageChange: function () { + return this.onPageChange.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this), + showSizeChanger: true, + }} + /> + </NextP> + </NextBlockCell> + </NextBlock> + </NextPage> + <NextPage + columns={12} + headerDivider={true} + placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }} + placeholder="页面主体内容:拖拽Block布局组件到这里" + header={null} + headerProps={{ background: 'surface' }} + footer={null} + minHeight="100vh" + > + <NextBlock + prefix="next-" + placeholderStyle={{ height: '100%' }} + noPadding={false} + noBorder={false} + background="surface" + colSpan={12} + rowSpan={1} + childTotalColumns={1} + > + <NextBlockCell + title="" + primaryKey="472" + prefix="next-" + placeholderStyle={{ height: '100%' }} + colSpan={1} + rowSpan={1} + /> + </NextBlock> + </NextPage> + </div> + ); + } +} + +export default Test$$Page; + +function __$$eval(expr) { + try { + return expr(); + } catch (error) {} +} + +function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; +} + +function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/layout.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/layout.jsx new file mode 100644 index 0000000000..50fbb2d1f1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/pages/layout.jsx @@ -0,0 +1,10 @@ +import { Outlet } from 'ice'; +import BasicLayout from '@/layouts/BasicLayout'; + +export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + ); +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/typings.d.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/typings.d.ts new file mode 100644 index 0000000000..a9f8de7ceb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/typings.d.ts @@ -0,0 +1,9 @@ +/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/utils.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/utils.js new file mode 100644 index 0000000000..1190717924 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/utils.js @@ -0,0 +1,47 @@ +import { createRef } from 'react'; + +export class RefsManager { + constructor() { + this.refInsStore = {}; + } + + clearNullRefs() { + Object.keys(this.refInsStore).forEach((refName) => { + const filteredInsList = this.refInsStore[refName].filter( + (insRef) => !!insRef.current + ); + if (filteredInsList.length > 0) { + this.refInsStore[refName] = filteredInsList; + } else { + delete this.refInsStore[refName]; + } + }); + } + + get(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName][0].current; + } + + return null; + } + + getAll(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName].map((i) => i.current); + } + + return []; + } + + linkRef(refName) { + const refIns = createRef(); + this.refInsStore[refName] = this.refInsStore[refName] || []; + this.refInsStore[refName].push(refIns); + return refIns; + } +} + +export default {}; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/schema.json5 new file mode 100644 index 0000000000..ca97204e9c --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/schema.json5 @@ -0,0 +1,353 @@ +{ + "version": "1.0.0", + "componentsMap": [ + { + "package": "@alife/mc-assets-1935", + "version": "0.1.9", + "exportName": "AliSearchTable", + "main": "build/lowcode/index.js", + "subName": "default", + "destructuring": true, + "componentName": "AliSearchTable" + }, + { + "package": "@alife/container", + "version": "^1.0.0", + "exportName": "P", + "main": "lib/index.js", + "destructuring": true, + "subName": "", + "componentName": "NextP" + }, + { + "package": "@alife/container", + "version": "^1.0.0", + "exportName": "Block", + "main": "lib/index.js", + "destructuring": true, + "subName": "Cell", + "componentName": "NextBlockCell" + }, + { + "package": "@alife/container", + "version": "^1.0.0", + "exportName": "Block", + "main": "lib/index.js", + "destructuring": true, + "subName": "", + "componentName": "NextBlock" + }, + { + "package": "@alife/container", + "version": "^1.0.0", + "exportName": "Text", + "main": "lib/index.js", + "destructuring": true, + "subName": "", + "componentName": "NextText" + }, + { + "package": "@alife/container", + "version": "^1.0.0", + "exportName": "Page", + "main": "lib/index.js", + "destructuring": true, + "subName": "", + "componentName": "NextPage" + } + ], + "componentsTree": [ + { + "componentName": "Page", + "id": "node_dockcviv8fo1", + "props": { + "ref": "outterView", + "style": { + "height": "100%" + } + }, + "fileName": "test", + "dataSource": { + "list": [ + { + "type": "fetch", + "isInit": true, + "options": { + "params": {}, + "method": "GET", + "isCors": true, + "timeout": 5000, + "headers": {}, + "uri": "https://mocks.xxx.com/mock/jjpin/user/list" + }, + "id": "users" + } + ] + }, + "css": "body {\n font-size: 12px;\n}\n\n.botton {\n width: 100px;\n color: #ff00ff\n}", + "lifeCycles": { + "componentDidMount": { + "type": "JSFunction", + "value": "function() {\n console.log('did mount');\n }" + }, + "componentWillUnmount": { + "type": "JSFunction", + "value": "function() {\n console.log('will umount');\n }" + }, + "componentDidUpdate": { + "type": "JSFunction", + "value": "function(prevProps, prevState, snapshot) {\n console.log(this.state);\n }" + } + }, + "methods": { + "testFunc": { + "type": "JSFunction", + "value": "function() {\n console.log('test func');\n }" + }, + "onClick": { + "type": "JSFunction", + "value": "function() {\n this.setState({\n isShowDialog: true\n })\n }" + }, + "closeDialog": { + "type": "JSFunction", + "value": "function() {\n this.setState({\n isShowDialog: false\n })\n }" + }, + "onSearch": { + "type": "JSFunction", + "value": "function(values) {\n console.log('search form:', values)\n console.log(this.dataSourceMap);\n this.dataSourceMap['users'].load(values)\n }" + }, + "onClear": { + "type": "JSFunction", + "value": "function() {\n console.log('form reset')\n this.setState({\n isShowDialog: true\n })\n }" + }, + "onPageChange": { + "type": "JSFunction", + "value": "function(page, pageSize) {\n console.log(`page: ${page}, pageSize: ${pageSize}`)\n }" + } + }, + "state": { + "text": "outter", + "isShowDialog": false + }, + "children": [ + { + "componentName": "NextPage", + "id": "node_ockkgjwi8z1", + "props": { + "columns": 12, + "placeholderStyle": { + "gridRowEnd": "span 1", + "gridColumnEnd": "span 12" + }, + "placeholder": "页面主体内容:拖拽Block布局组件到这里", + "header": { + "type": "JSSlot", + "value": [ + { + "componentName": "NextP", + "id": "node_ockkgjwi8zn", + "props": { + "wrap": true, + "type": "body2", + "verAlign": "middle", + "textSpacing": true, + "align": "left", + "flex": true + }, + "children": [ + { + "componentName": "NextText", + "id": "node_ockkgjwi8zo", + "props": { + "type": "h5", + "children": "员工列表" + } + } + ] + } + ], + "title": "header" + }, + "headerTest": { + "type": "JSSlot", + "value": [], + "title": "header" + }, + "headerProps": { + "background": "surface" + }, + "footer": { + "type": "JSSlot", + "title": "footer" + }, + "minHeight": "100vh" + }, + "children": [ + { + "componentName": "NextBlock", + "id": "node_ockkgjwi8z2", + "props": { + "prefix": "next-", + "placeholderStyle": { + "height": "100%" + }, + "noPadding": false, + "noBorder": false, + "background": "surface", + "colSpan": 12, + "rowSpan": 1, + "childTotalColumns": "1fr" + }, + "title": "分区", + "children": [ + { + "componentName": "NextBlockCell", + "id": "node_ockkgjwi8z3", + "props": { + "title": "", + "primaryKey": "732", + "prefix": "next-", + "placeholderStyle": { + "height": "100%" + }, + "colSpan": 1, + "rowSpan": 1 + }, + "children": [ + { + "componentName": "NextP", + "id": "node_ockkgjwi8zu", + "props": { + "wrap": true, + "type": "body2", + "textSpacing": true, + "verAlign": "center", + "align": "flex-start", + "flex": true + }, + "children": [ + { + "componentName": "AliSearchTable", + "id": "node_ockkgjwi8zv", + "props": { + "dataSource": { + "type": "JSExpression", + "value": "this.state.users.data" + }, + "rowKey": "workid", + "columns": [ + { + "title": "花名", + "dataIndex": "cname" + }, + { + "title": "user_id", + "dataIndex": "workid" + }, + { + "title": "部门", + "dataIndex": "dep" + } + ], + "searchItems": [ + { + "label": "姓名", + "name": "cname" + }, + { + "label": "部门", + "name": "dep" + } + ], + "onSearch": { + "type": "JSFunction", + "value": "function(){ return this.onSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }" + }, + "onClear": { + "type": "JSFunction", + "value": "function(){ return this.onClear.apply(this,Array.prototype.slice.call(arguments).concat([])) }" + }, + "pagination": { + "defaultPageSize": "", + "onPageChange": { + "type": "JSFunction", + "value": "function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }" + }, + "showSizeChanger": true + } + } + } + ] + } + ] + } + ] + } + ] + }, + { + "componentName": "NextPage", + "id": "node_ockm4jxd6313", + "props": { + "columns": 12, + "headerDivider": true, + "placeholderStyle": { + "gridRowEnd": "span 1", + "gridColumnEnd": "span 12" + }, + "placeholder": "页面主体内容:拖拽Block布局组件到这里", + "header": { + "type": "JSSlot", + "title": "header" + }, + "headerProps": { + "background": "surface" + }, + "footer": { + "type": "JSSlot", + "title": "footer" + }, + "minHeight": "100vh" + }, + "title": "页面", + "children": [ + { + "componentName": "NextBlock", + "id": "node_ockm4jxd6314", + "props": { + "prefix": "next-", + "placeholderStyle": { + "height": "100%" + }, + "noPadding": false, + "noBorder": false, + "background": "surface", + "colSpan": 12, + "rowSpan": 1, + "childTotalColumns": 1 + }, + "title": "区块", + "children": [ + { + "componentName": "NextBlockCell", + "id": "node_ockm4jxd6315", + "props": { + "title": "", + "primaryKey": "472", + "prefix": "next-", + "placeholderStyle": { + "height": "100%" + }, + "colSpan": 1, + "rowSpan": 1 + } + } + ] + } + ] + } + ] + } + ], + "i18n": {} +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/.browserslistrc b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/.browserslistrc new file mode 100644 index 0000000000..55a130413d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/.browserslistrc @@ -0,0 +1,3 @@ +defaults +ios_saf 9 + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/.gitignore b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/.gitignore new file mode 100644 index 0000000000..4ec178818e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/.gitignore @@ -0,0 +1,25 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/README.md b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/README.md new file mode 100644 index 0000000000..6d9dd75215 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/README.md @@ -0,0 +1 @@ +This project is generated by lowcode-code-generator & lowcode-solution-icejs3. \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/ice.config.mts new file mode 100644 index 0000000000..fe77c9b6cd --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/ice.config.mts @@ -0,0 +1,90 @@ +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + }, + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = ` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + `; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion({ + importStyle: true, + }), + locales(), + plugin(), + ], +})); + diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/package.json new file mode 100644 index 0000000000..a62526e762 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/package.json @@ -0,0 +1,46 @@ +{ + "name": "icejs3-demo-app", + "version": "0.1.5", + "description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。", + "dependencies": { + "moment": "^2.24.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router": "^6.9.0", + "react-router-dom": "^6.9.0", + "intl-messageformat": "^9.3.6", + "@alifd/next": "1.26.15", + "@ice/runtime": "^1.0.0", + "@alilc/lowcode-datasource-engine": "^1.0.0", + "undefined": "*", + "@alife/container": "0.3.7", + "@alilc/antd-lowcode": "0.5.4", + "@alife/mc-assets-1935": "0.1.16" + }, + "devDependencies": { + "@ice/app": "^3.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/node": "^18.11.17", + "@ice/plugin-fusion": "^1.0.1", + "@ice/plugin-moment-locales": "^1.0.0", + "eslint": "^6.0.1", + "stylelint": "^13.2.0" + }, + "scripts": { + "start": "ice start", + "build": "ice build", + "lint": "npm run eslint && npm run stylelint", + "eslint": "eslint --cache --ext .js,.jsx ./", + "stylelint": "stylelint ./**/*.scss" + }, + "engines": { + "node": ">=14.0.0" + }, + "repository": { + "type": "git", + "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" + }, + "private": true, + "originTemplate": "@alifd/scaffold-lite-js" +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/app.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/app.ts new file mode 100644 index 0000000000..6d5856292d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/app.ts @@ -0,0 +1,13 @@ +import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +})); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/constants.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/constants.js new file mode 100644 index 0000000000..ea766c9da3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/constants.js @@ -0,0 +1,3 @@ +const __$$constants = {}; + +export default __$$constants; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/document.tsx new file mode 100644 index 0000000000..286be9f8ca --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/document.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/global.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/global.scss new file mode 100644 index 0000000000..82ca3eac73 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/global.scss @@ -0,0 +1,6 @@ +// 引入默认全局样式 +@import '@alifd/next/reset.scss'; + +body { + -webkit-font-smoothing: antialiased; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/i18n.js new file mode 100644 index 0000000000..adbbe673dc --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/i18n.js @@ -0,0 +1,77 @@ +const i18nConfig = {}; + +let locale = + typeof navigator === 'object' && typeof navigator.language === 'string' + ? navigator.language + : 'zh-CN'; + +const getLocale = () => locale; + +const setLocale = (target) => { + locale = target; +}; + +const isEmptyVariables = (variables) => + (Array.isArray(variables) && variables.length === 0) || + (typeof variables === 'object' && + (!variables || Object.keys(variables).length === 0)); + +// 按低代码规范里面的要求进行变量替换 +const format = (msg, variables) => + typeof msg === 'string' + ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + : msg; + +const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { + const msg = + i18nConfig[locale]?.[id] ?? + i18nConfig[locale.replace('-', '_')]?.[id] ?? + defaultMessage; + if (msg == null) { + console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); + return fallback === undefined ? `${id}` : fallback; + } + + return format(msg, variables); +}; + +const i18n = (id, params) => { + return i18nFormat({ id }, params); +}; + +// 将国际化的一些方法注入到目标对象&上下文中 +const _inject2 = (target) => { + target.i18n = i18n; + target.getLocale = getLocale; + target.setLocale = (locale) => { + setLocale(locale); + target.forceUpdate(); + }; + target._i18nText = (t) => { + // 优先取直接传过来的语料 + const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]; + if (localMsg != null) { + return format(localMsg, t.params); + } + + // 其次用项目级别的 + const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params); + if (projectMsg != null) { + return projectMsg; + } + + // 兜底用 use 指定的或默认语言的 + return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params); + }; + + // 注入到上下文中去 + if (target._context && target._context !== target) { + Object.assign(target._context, { + i18n, + getLocale, + setLocale: target.setLocale, + }); + } +}; + +export { getLocale, setLocale, i18n, i18nFormat, _inject2 }; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx new file mode 100644 index 0000000000..cc70d53bea --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx @@ -0,0 +1,14 @@ + +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss new file mode 100644 index 0000000000..81e77fda5f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss @@ -0,0 +1,15 @@ + +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx new file mode 100644 index 0000000000..265bfdaa07 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss new file mode 100644 index 0000000000..1ab56d3945 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -0,0 +1,20 @@ + +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx new file mode 100644 index 0000000000..911998b0d3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/index.jsx new file mode 100644 index 0000000000..18db44df5e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/index.jsx @@ -0,0 +1,81 @@ + +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/menuConfig.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/menuConfig.js new file mode 100644 index 0000000000..5332202be4 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/menuConfig.js @@ -0,0 +1,11 @@ + +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/Test/index.css b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/Test/index.css new file mode 100644 index 0000000000..066114aeeb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/Test/index.css @@ -0,0 +1,8 @@ +body { + font-size: 12px; +} + +.botton { + width: 100px; + color: #ff00ff; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/Test/index.jsx new file mode 100644 index 0000000000..7427f164d9 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/Test/index.jsx @@ -0,0 +1,389 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:react 框架的导出名和各种组件名除外。 +import React from 'react'; + +import { + Page as NextPage, + Block as NextBlock, + P as NextP, +} from '@alife/container/lib/index.js'; + +import { + Card, + Space, + Typography, + Select, + Button, + Modal, + Form, + InputNumber, + Input, +} from '@alilc/antd-lowcode/dist/antd-lowcode.esm.js'; + +import { AliAutoSearchTable } from '@alife/mc-assets-1935/build/lowcode/index.js'; + +import utils, { RefsManager } from '../../utils'; + +import * as __$$i18n from '../../i18n'; + +import __$$constants from '../../constants'; + +import './index.css'; + +const NextBlockCell = NextBlock.Cell; + +const AliAutoSearchTableDefault = AliAutoSearchTable.default; + +class Test$$Page extends React.Component { + _context = this; + + get constants() { + return __$$constants || {}; + } + + constructor(props, context) { + super(props); + + this.utils = utils; + + this._refsManager = new RefsManager(); + + __$$i18n._inject2(this); + + this.state = { + name: 'nongzhou', + gateways: [], + selectedGateway: null, + records: [], + modalVisible: false, + }; + } + + $ = (refName) => { + return this._refsManager.get(refName); + }; + + $$ = (refName) => { + return this._refsManager.getAll(refName); + }; + + componentWillUnmount() { + /* ... */ + } + + componentDidUpdate() { + /* ... */ + } + + onChange() { + /* ... */ + } + + getActions() { + /* ... */ + } + + onCreateOrder() { + /* ... */ + } + + onCancelModal() { + /* ... */ + } + + onConfirmCreateOrder() { + /* ... */ + } + + componentDidMount() {} + + render() { + const __$$context = this._context || this; + const { state } = __$$context; + return ( + <div + ref={this._refsManager.linkRef('outterView')} + style={{ height: '100%' }} + > + <NextPage + columns={12} + headerDivider={true} + placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }} + placeholder="页面主体内容:拖拽Block布局组件到这里" + header={null} + headerProps={{ background: 'surface' }} + footer={null} + minHeight="100vh" + style={{ cursor: 'pointer' }} + > + <NextBlock + prefix="next-" + placeholderStyle={{ height: '100%' }} + noPadding={false} + noBorder={false} + background="surface" + layoutmode="O" + colSpan={12} + rowSpan={1} + childTotalColumns={12} + > + <NextBlockCell + title="" + prefix="next-" + placeholderStyle={{ height: '100%' }} + layoutmode="O" + childTotalColumns={12} + isAutoContainer={true} + colSpan={12} + rowSpan={1} + > + <NextP + wrap={false} + type="body2" + verAlign="middle" + textSpacing={true} + align="left" + full={true} + flex={true} + > + <Card title=""> + <Space size={0} align="center" direction="horizontal"> + <Typography.Text>所在网关:</Typography.Text> + <Select + style={{ + marginTop: '16px', + marginRight: '16px', + marginBottom: '16px', + marginLeft: '16px', + width: '400px', + display: 'inline-block', + }} + options={__$$eval(() => this.state.gateways)} + mode="single" + defaultValue={['auto-edd-uniproxy']} + labelInValue={true} + showSearch={true} + allowClear={false} + placeholder="请选取网关" + showArrow={true} + loading={false} + tokenSeparators={[]} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onChange', + relatedEventName: 'onChange', + }, + ], + eventList: [ + { name: 'onBlur', disabled: false }, + { name: 'onChange', disabled: true }, + { name: 'onDeselect', disabled: false }, + { name: 'onFocus', disabled: false }, + { name: 'onInputKeyDown', disabled: false }, + { name: 'onMouseEnter', disabled: false }, + { name: 'onMouseLeave', disabled: false }, + { name: 'onPopupScroll', disabled: false }, + { name: 'onSearch', disabled: false }, + { name: 'onSelect', disabled: false }, + { name: 'onDropdownVisibleChange', disabled: false }, + ], + }} + onChange={function () { + this.onChange.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + /> + </Space> + <Button + type="primary" + style={{ + display: 'block', + marginTop: '20px', + marginBottom: '20px', + }} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onCreateOrder', + }, + ], + eventList: [{ name: 'onClick', disabled: true }], + }} + onClick={function () { + this.onCreateOrder.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + 创建发布单 + </Button> + <Modal + title="创建发布单" + visible={__$$eval(() => this.state.modalVisible)} + footer="" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onCancel', + relatedEventName: 'onCancelModal', + }, + ], + eventList: [ + { name: 'onCancel', disabled: true }, + { name: 'onOk', disabled: false }, + ], + }} + onCancel={function () { + this.onCancelModal.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + zIndex={2000} + > + <Form + labelCol={{ span: 6 }} + wrapperCol={{ span: 14 }} + onFinish={function () { + this.onConfirmCreateOrder.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + name="basic" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onFinish', + relatedEventName: 'onConfirmCreateOrder', + }, + ], + eventList: [ + { name: 'onFinish', disabled: true }, + { name: 'onFinishFailed', disabled: false }, + { name: 'onFieldsChange', disabled: false }, + { name: 'onValuesChange', disabled: false }, + ], + }} + > + <Form.Item label="发布批次"> + <InputNumber value={3} min={1} /> + </Form.Item> + <Form.Item label="批次间隔时间"> + <InputNumber value={3} /> + </Form.Item> + <Form.Item label="备注 "> + <Input.TextArea rows={3} placeholder="请输入" /> + </Form.Item> + <Form.Item + wrapperCol={{ offset: 6 }} + style={{ + flexDirection: 'row', + alignItems: 'flex-end', + justifyContent: 'center', + display: 'flex', + }} + labelAlign="right" + > + <Button type="primary" htmlType="submit"> + 提交 + </Button> + <Button + style={{ marginLeft: 20 }} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onCancelModal', + }, + ], + eventList: [{ name: 'onClick', disabled: true }], + }} + onClick={function () { + this.onCancelModal.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + 取消 + </Button> + </Form.Item> + </Form> + </Modal> + <AliAutoSearchTableDefault + rowKey="key" + dataSource={__$$eval(() => this.state.records)} + columns={[ + { + title: '发布名称', + dataIndex: 'order_name', + key: 'name', + }, + { + title: '类型', + dataIndex: 'order_type_desc', + key: 'age', + }, + { + title: '发布状态', + dataIndex: 'order_status_desc', + key: 'address', + }, + { title: '发布人', dataIndex: 'creator_name' }, + { title: '当前批次/总批次', dataIndex: 'cur_batch_no' }, + { + title: '发布机器/总机器', + dataIndex: 'pubblish_ip_finish_num', + }, + { title: '发布时间', dataIndex: 'publish_id' }, + ]} + actions={__$$eval(() => this.actions || [])} + getActions={function () { + return this.getActions.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + /> + </Card> + </NextP> + </NextBlockCell> + </NextBlock> + </NextPage> + </div> + ); + } +} + +export default Test$$Page; + +function __$$eval(expr) { + try { + return expr(); + } catch (error) {} +} + +function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; +} + +function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/layout.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/layout.jsx new file mode 100644 index 0000000000..50fbb2d1f1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/pages/layout.jsx @@ -0,0 +1,10 @@ +import { Outlet } from 'ice'; +import BasicLayout from '@/layouts/BasicLayout'; + +export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + ); +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/typings.d.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/typings.d.ts new file mode 100644 index 0000000000..a9f8de7ceb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/typings.d.ts @@ -0,0 +1,9 @@ +/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/utils.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/utils.js new file mode 100644 index 0000000000..1190717924 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/utils.js @@ -0,0 +1,47 @@ +import { createRef } from 'react'; + +export class RefsManager { + constructor() { + this.refInsStore = {}; + } + + clearNullRefs() { + Object.keys(this.refInsStore).forEach((refName) => { + const filteredInsList = this.refInsStore[refName].filter( + (insRef) => !!insRef.current + ); + if (filteredInsList.length > 0) { + this.refInsStore[refName] = filteredInsList; + } else { + delete this.refInsStore[refName]; + } + }); + } + + get(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName][0].current; + } + + return null; + } + + getAll(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName].map((i) => i.current); + } + + return []; + } + + linkRef(refName) { + const refIns = createRef(); + this.refInsStore[refName] = this.refInsStore[refName] || []; + this.refInsStore[refName].push(refIns); + return refIns; + } +} + +export default {}; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/schema.json5 new file mode 100644 index 0000000000..b59b97e763 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/schema.json5 @@ -0,0 +1,677 @@ +{ + version: '1.0.0', + componentsMap: [ + { + package: '@alilc/antd-lowcode', + version: '0.5.4', + exportName: 'Typography', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + subName: 'Text', + componentName: 'Typography.Text', + }, + { + package: '@alilc/antd-lowcode', + version: '0.5.4', + exportName: 'Select', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Select', + }, + { + package: '@alilc/antd-lowcode', + version: '0.5.4', + exportName: 'Space', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Space', + }, + { + package: '@alilc/antd-lowcode', + version: '0.5.4', + exportName: 'Button', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Button', + }, + { + package: '@alilc/antd-lowcode', + version: '0.5.4', + exportName: 'InputNumber', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'InputNumber', + }, + { + package: '@alilc/antd-lowcode', + version: '0.5.4', + exportName: 'Form', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + subName: 'Item', + componentName: 'Form.Item', + }, + { + package: '@alilc/antd-lowcode', + version: '0.5.4', + exportName: 'Input', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + subName: 'TextArea', + componentName: 'Input.TextArea', + }, + { + package: '@alilc/antd-lowcode', + version: '0.5.4', + exportName: 'Form', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Form', + }, + { + package: '@alilc/antd-lowcode', + version: '0.5.4', + exportName: 'Modal', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Modal', + }, + { + package: '@alife/mc-assets-1935', + version: '0.1.16', + exportName: 'AliAutoSearchTable', + main: 'build/lowcode/index.js', + destructuring: true, + subName: 'default', + componentName: 'AliAutoSearchTableDefault', + }, + { + package: '@alilc/antd-lowcode', + version: '0.5.4', + exportName: 'Card', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Card', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'P', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextP', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Block', + main: 'lib/index.js', + destructuring: true, + subName: 'Cell', + componentName: 'NextBlockCell', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Block', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextBlock', + }, + { + devMode: 'lowcode', + componentName: 'Slot', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Page', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextPage', + }, + { + devMode: 'lowcode', + componentName: 'Page', + }, + ], + componentsTree: [ + { + componentName: 'Page', + id: 'node_dockcviv8fo1', + props: { + ref: 'outterView', + style: { + height: '100%', + }, + }, + fileName: 'test', + dataSource: { + list: [], + }, + css: 'body {\n font-size: 12px;\n}\n\n.botton {\n width: 100px;\n color: #ff00ff\n}', + lifeCycles: { + componentDidMount: { + type: 'JSFunction', + value: 'function() { /* ... */ }', + }, + componentWillUnmount: { + type: 'JSFunction', + value: 'function() { /* ... */ }', + }, + componentDidUpdate: { + type: 'JSFunction', + value: 'function() { /* ... */ }', + }, + }, + methods: { + onChange: { + type: 'JSFunction', + value: 'function() { /* ... */ }', + }, + getActions: { + type: 'JSFunction', + value: 'function() { /* ... */ }', + }, + onCreateOrder: { + type: 'JSFunction', + value: 'function() { /* ... */ }', + }, + onCancelModal: { + type: 'JSFunction', + value: 'function() { /* ... */ }', + }, + onConfirmCreateOrder: { + type: 'JSFunction', + value: 'function() { /* ... */ }', + }, + }, + state: { + name: 'nongzhou', + gateways: [], + selectedGateway: null, + records: [], + modalVisible: false, + }, + children: [ + { + componentName: 'NextPage', + id: 'node_ocknqx3esma', + props: { + columns: 12, + headerDivider: true, + placeholderStyle: { + gridRowEnd: 'span 1', + gridColumnEnd: 'span 12', + }, + placeholder: '页面主体内容:拖拽Block布局组件到这里', + header: { + type: 'JSSlot', + title: 'header', + }, + headerProps: { + background: 'surface', + }, + footer: { + type: 'JSSlot', + title: 'footer', + }, + minHeight: '100vh', + style: { + cursor: 'pointer', + }, + }, + title: '页面', + children: [ + { + componentName: 'NextBlock', + id: 'node_ocknqx3esmb', + props: { + prefix: 'next-', + placeholderStyle: { + height: '100%', + }, + noPadding: false, + noBorder: false, + background: 'surface', + layoutmode: 'O', + colSpan: 12, + rowSpan: 1, + childTotalColumns: 12, + }, + title: '区块', + children: [ + { + componentName: 'NextBlockCell', + id: 'node_ocknqx3esmc', + props: { + title: '', + prefix: 'next-', + placeholderStyle: { + height: '100%', + }, + layoutmode: 'O', + childTotalColumns: 12, + isAutoContainer: true, + colSpan: 12, + rowSpan: 1, + }, + children: [ + { + componentName: 'NextP', + id: 'node_ocknqx3esm1j', + props: { + wrap: false, + type: 'body2', + verAlign: 'middle', + textSpacing: true, + align: 'left', + full: true, + flex: true, + }, + title: '段落', + children: [ + { + componentName: 'Card', + id: 'node_ocknqx3esm1k', + props: { + title: '', + }, + children: [ + { + componentName: 'Space', + id: 'node_ocknqx3esm1n', + props: { + size: 0, + align: 'center', + direction: 'horizontal', + }, + children: [ + { + componentName: 'Typography.Text', + id: 'node_ocknqx3esm1l', + props: { + children: '所在网关:', + }, + }, + { + componentName: 'Select', + id: 'node_ocknqx3esm1m', + props: { + style: { + marginTop: '16px', + marginRight: '16px', + marginBottom: '16px', + marginLeft: '16px', + width: '400px', + display: 'inline-block', + }, + options: { + type: 'JSExpression', + value: 'this.state.gateways', + }, + mode: 'single', + defaultValue: ['auto-edd-uniproxy'], + labelInValue: true, + showSearch: true, + allowClear: false, + placeholder: '请选取网关', + showArrow: true, + loading: false, + tokenSeparators: [], + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onChange', + relatedEventName: 'onChange', + }, + ], + eventList: [ + { + name: 'onBlur', + disabled: false, + }, + { + name: 'onChange', + disabled: true, + }, + { + name: 'onDeselect', + disabled: false, + }, + { + name: 'onFocus', + disabled: false, + }, + { + name: 'onInputKeyDown', + disabled: false, + }, + { + name: 'onMouseEnter', + disabled: false, + }, + { + name: 'onMouseLeave', + disabled: false, + }, + { + name: 'onPopupScroll', + disabled: false, + }, + { + name: 'onSearch', + disabled: false, + }, + { + name: 'onSelect', + disabled: false, + }, + { + name: 'onDropdownVisibleChange', + disabled: false, + }, + ], + }, + onChange: { + type: 'JSFunction', + value: 'function(){this.onChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + { + componentName: 'Button', + id: 'node_ockntwgdsn7', + props: { + type: 'primary', + children: '创建发布单', + style: { + display: 'block', + marginTop: '20px', + marginBottom: '20px', + }, + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onCreateOrder', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.onCreateOrder.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + { + componentName: 'Modal', + id: 'node_ockntx4eo9p', + props: { + title: '创建发布单', + visible: { + type: 'JSExpression', + value: 'this.state.modalVisible', + }, + footer: '', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onCancel', + relatedEventName: 'onCancelModal', + }, + ], + eventList: [ + { + name: 'onCancel', + disabled: true, + }, + { + name: 'onOk', + disabled: false, + }, + ], + }, + onCancel: { + type: 'JSFunction', + value: 'function(){this.onCancelModal.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + zIndex: 2000, + }, + hidden: true, + children: [ + { + componentName: 'Form', + id: 'node_ockntx4eo9s', + props: { + labelCol: { + span: 6, + }, + wrapperCol: { + span: 14, + }, + onFinish: { + type: 'JSFunction', + value: 'function(){this.onConfirmCreateOrder.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + name: 'basic', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onFinish', + relatedEventName: 'onConfirmCreateOrder', + }, + ], + eventList: [ + { + name: 'onFinish', + disabled: true, + }, + { + name: 'onFinishFailed', + disabled: false, + }, + { + name: 'onFieldsChange', + disabled: false, + }, + { + name: 'onValuesChange', + disabled: false, + }, + ], + }, + }, + children: [ + { + componentName: 'Form.Item', + id: 'node_ockntx4eo91k', + props: { + label: '发布批次', + }, + children: [ + { + componentName: 'InputNumber', + id: 'node_ockntx4eo91l', + props: { + value: 3, + min: 1, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockntx4eo91r', + props: { + label: '批次间隔时间', + }, + children: [ + { + componentName: 'InputNumber', + id: 'node_ockntx4eo91s', + props: { + value: 3, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockntx4eo91y', + props: { + label: '备注 ', + }, + children: [ + { + componentName: 'Input.TextArea', + id: 'node_ockntx4eo91z', + props: { + rows: 3, + placeholder: '请输入', + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockntx4eo9v', + props: { + wrapperCol: { + offset: 6, + }, + style: { + flexDirection: 'row', + alignItems: 'flex-end', + justifyContent: 'center', + display: 'flex', + }, + labelAlign: 'right', + }, + children: [ + { + componentName: 'Button', + id: 'node_ockntx4eo9w', + props: { + type: 'primary', + children: '提交', + htmlType: 'submit', + }, + }, + { + componentName: 'Button', + id: 'node_ockntx4eo9x', + props: { + style: { + marginLeft: 20, + }, + children: '取消', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onCancelModal', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.onCancelModal.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + ], + }, + ], + }, + { + componentName: 'AliAutoSearchTableDefault', + id: 'node_ocknqx3esm1q', + props: { + rowKey: 'key', + dataSource: { + type: 'JSExpression', + value: 'this.state.records', + }, + columns: [ + { + title: '发布名称', + dataIndex: 'order_name', + key: 'name', + }, + { + title: '类型', + dataIndex: 'order_type_desc', + key: 'age', + }, + { + title: '发布状态', + dataIndex: 'order_status_desc', + key: 'address', + }, + { + title: '发布人', + dataIndex: 'creator_name', + }, + { + title: '当前批次/总批次', + dataIndex: 'cur_batch_no', + }, + { + title: '发布机器/总机器', + dataIndex: 'pubblish_ip_finish_num', + }, + { + title: '发布时间', + dataIndex: 'publish_id', + }, + ], + actions: { + type: 'JSExpression', + value: 'this.actions || []', + }, + getActions: { + type: 'JSFunction', + value: 'function(){ return this.getActions.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + i18n: {}, +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/.browserslistrc b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/.browserslistrc new file mode 100644 index 0000000000..55a130413d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/.browserslistrc @@ -0,0 +1,3 @@ +defaults +ios_saf 9 + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/.gitignore b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/.gitignore new file mode 100644 index 0000000000..4ec178818e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/.gitignore @@ -0,0 +1,25 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/README.md b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/README.md new file mode 100644 index 0000000000..6d9dd75215 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/README.md @@ -0,0 +1 @@ +This project is generated by lowcode-code-generator & lowcode-solution-icejs3. \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/ice.config.mts new file mode 100644 index 0000000000..fe77c9b6cd --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/ice.config.mts @@ -0,0 +1,90 @@ +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + }, + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = ` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + `; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion({ + importStyle: true, + }), + locales(), + plugin(), + ], +})); + diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/package.json new file mode 100644 index 0000000000..54a1e4e121 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/package.json @@ -0,0 +1,44 @@ +{ + "name": "icejs3-demo-app", + "version": "0.1.5", + "description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。", + "dependencies": { + "moment": "^2.24.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router": "^6.9.0", + "react-router-dom": "^6.9.0", + "intl-messageformat": "^9.3.6", + "@alifd/next": "1.19.18", + "@ice/runtime": "^1.0.0", + "@alilc/lowcode-datasource-engine": "^1.0.0", + "@alilc/lowcode-datasource-url-params-handler": "^1.0.0", + "@alilc/lowcode-datasource-fetch-handler": "^1.0.0" + }, + "devDependencies": { + "@ice/app": "^3.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/node": "^18.11.17", + "@ice/plugin-fusion": "^1.0.1", + "@ice/plugin-moment-locales": "^1.0.0", + "eslint": "^6.0.1", + "stylelint": "^13.2.0" + }, + "scripts": { + "start": "ice start", + "build": "ice build", + "lint": "npm run eslint && npm run stylelint", + "eslint": "eslint --cache --ext .js,.jsx ./", + "stylelint": "stylelint ./**/*.scss" + }, + "engines": { + "node": ">=14.0.0" + }, + "repository": { + "type": "git", + "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" + }, + "private": true, + "originTemplate": "@alifd/scaffold-lite-js" +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/app.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/app.ts new file mode 100644 index 0000000000..6d5856292d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/app.ts @@ -0,0 +1,13 @@ +import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +})); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/constants.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/constants.js new file mode 100644 index 0000000000..91198f9044 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/constants.js @@ -0,0 +1,3 @@ +const __$$constants = { ENV: 'prod', DOMAIN: 'xxx.xxx.com' }; + +export default __$$constants; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/document.tsx new file mode 100644 index 0000000000..286be9f8ca --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/document.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/global.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/global.scss new file mode 100644 index 0000000000..ed7204b4a3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/global.scss @@ -0,0 +1,13 @@ +// 引入默认全局样式 +@import '@alifd/next/reset.scss'; + +body { + -webkit-font-smoothing: antialiased; +} + +body { + font-size: 12px; +} +.table { + width: 100px; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/i18n.js new file mode 100644 index 0000000000..adbbe673dc --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/i18n.js @@ -0,0 +1,77 @@ +const i18nConfig = {}; + +let locale = + typeof navigator === 'object' && typeof navigator.language === 'string' + ? navigator.language + : 'zh-CN'; + +const getLocale = () => locale; + +const setLocale = (target) => { + locale = target; +}; + +const isEmptyVariables = (variables) => + (Array.isArray(variables) && variables.length === 0) || + (typeof variables === 'object' && + (!variables || Object.keys(variables).length === 0)); + +// 按低代码规范里面的要求进行变量替换 +const format = (msg, variables) => + typeof msg === 'string' + ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + : msg; + +const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { + const msg = + i18nConfig[locale]?.[id] ?? + i18nConfig[locale.replace('-', '_')]?.[id] ?? + defaultMessage; + if (msg == null) { + console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); + return fallback === undefined ? `${id}` : fallback; + } + + return format(msg, variables); +}; + +const i18n = (id, params) => { + return i18nFormat({ id }, params); +}; + +// 将国际化的一些方法注入到目标对象&上下文中 +const _inject2 = (target) => { + target.i18n = i18n; + target.getLocale = getLocale; + target.setLocale = (locale) => { + setLocale(locale); + target.forceUpdate(); + }; + target._i18nText = (t) => { + // 优先取直接传过来的语料 + const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]; + if (localMsg != null) { + return format(localMsg, t.params); + } + + // 其次用项目级别的 + const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params); + if (projectMsg != null) { + return projectMsg; + } + + // 兜底用 use 指定的或默认语言的 + return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params); + }; + + // 注入到上下文中去 + if (target._context && target._context !== target) { + Object.assign(target._context, { + i18n, + getLocale, + setLocale: target.setLocale, + }); + } +}; + +export { getLocale, setLocale, i18n, i18nFormat, _inject2 }; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx new file mode 100644 index 0000000000..cc70d53bea --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx @@ -0,0 +1,14 @@ + +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss new file mode 100644 index 0000000000..81e77fda5f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss @@ -0,0 +1,15 @@ + +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx new file mode 100644 index 0000000000..265bfdaa07 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss new file mode 100644 index 0000000000..1ab56d3945 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -0,0 +1,20 @@ + +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx new file mode 100644 index 0000000000..911998b0d3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/index.jsx new file mode 100644 index 0000000000..18db44df5e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/index.jsx @@ -0,0 +1,81 @@ + +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/menuConfig.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/menuConfig.js new file mode 100644 index 0000000000..5332202be4 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/menuConfig.js @@ -0,0 +1,11 @@ + +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.css b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx new file mode 100644 index 0000000000..c27cce1532 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx @@ -0,0 +1,195 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:react 框架的导出名和各种组件名除外。 +import React from 'react'; + +import { Form, Input, NumberPicker, Select, Button } from '@alifd/next'; + +import { createUrlParamsHandler as __$$createUrlParamsRequestHandler } from '@alilc/lowcode-datasource-url-params-handler'; + +import { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowcode-datasource-fetch-handler'; + +import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime'; + +import utils, { RefsManager } from '../../utils'; + +import * as __$$i18n from '../../i18n'; + +import __$$constants from '../../constants'; + +import './index.css'; + +class Test$$Page extends React.Component { + _context = this; + + _dataSourceConfig = this._defineDataSourceConfig(); + _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, { + runtimeConfig: true, + requestHandlersMap: { + urlParams: __$$createUrlParamsRequestHandler(window.location.search), + fetch: __$$createFetchRequestHandler(), + }, + }); + + get dataSourceMap() { + return this._dataSourceEngine.dataSourceMap || {}; + } + + reloadDataSource = async () => { + await this._dataSourceEngine.reloadDataSource(); + }; + + get constants() { + return __$$constants || {}; + } + + constructor(props, context) { + super(props); + + this.utils = utils; + + this._refsManager = new RefsManager(); + + __$$i18n._inject2(this); + + this.state = { text: 'outter' }; + } + + $ = (refName) => { + return this._refsManager.get(refName); + }; + + $$ = (refName) => { + return this._refsManager.getAll(refName); + }; + + _defineDataSourceConfig() { + const _this = this; + return { + list: [ + { + id: 'urlParams', + type: 'urlParams', + isInit: function () { + return undefined; + }.bind(_this), + options: function () { + return undefined; + }.bind(_this), + }, + { + id: 'user', + type: 'fetch', + options: function () { + return { + method: 'GET', + uri: 'https://shs.xxx.com/mock/1458/demo/user', + isSync: true, + }; + }.bind(_this), + dataHandler: function (response) { + if (!response.data.success) { + throw new Error(response.data.message); + } + return response.data.data; + }, + isInit: function () { + return undefined; + }.bind(_this), + }, + { + id: 'orders', + type: 'fetch', + options: function () { + return { + method: 'GET', + uri: 'https://shs.xxx.com/mock/1458/demo/orders', + isSync: true, + }; + }.bind(_this), + dataHandler: function (response) { + if (!response.data.success) { + throw new Error(response.data.message); + } + return response.data.data.result; + }, + isInit: function () { + return undefined; + }.bind(_this), + }, + ], + dataHandler: function (dataMap) { + console.info('All datasources loaded:', dataMap); + }, + }; + } + + componentDidMount() { + this._dataSourceEngine.reloadDataSource(); + + console.log('componentDidMount'); + } + + render() { + const __$$context = this._context || this; + const { state } = __$$context; + return ( + <div ref={this._refsManager.linkRef('outterView')} autoLoading={true}> + <Form + labelCol={__$$eval(() => this.state.colNum)} + style={{}} + ref={this._refsManager.linkRef('testForm')} + > + <Form.Item label="姓名:" name="name" initValue="李雷"> + <Input placeholder="请输入" size="medium" style={{ width: 320 }} /> + </Form.Item> + <Form.Item label="年龄:" name="age" initValue="22"> + <NumberPicker size="medium" type="normal" /> + </Form.Item> + <Form.Item label="职业:" name="profession"> + <Select + dataSource={[ + { label: '教师', value: 't' }, + { label: '医生', value: 'd' }, + { label: '歌手', value: 's' }, + ]} + /> + </Form.Item> + <div style={{ textAlign: 'center' }}> + <Button.Group> + {__$$evalArray(() => ['a', 'b', 'c']).map((item, index) => + ((__$$context) => + !!false && ( + <Button type="primary" style={{ margin: '0 5px 0 5px' }}> + {__$$eval(() => item)} + </Button> + ))(__$$createChildContext(__$$context, { item, index })) + )} + </Button.Group> + </div> + </Form> + </div> + ); + } +} + +export default Test$$Page; + +function __$$eval(expr) { + try { + return expr(); + } catch (error) {} +} + +function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; +} + +function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/layout.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/layout.jsx new file mode 100644 index 0000000000..50fbb2d1f1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/layout.jsx @@ -0,0 +1,10 @@ +import { Outlet } from 'ice'; +import BasicLayout from '@/layouts/BasicLayout'; + +export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + ); +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/typings.d.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/typings.d.ts new file mode 100644 index 0000000000..a9f8de7ceb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/typings.d.ts @@ -0,0 +1,9 @@ +/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/utils.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/utils.js new file mode 100644 index 0000000000..1190717924 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/utils.js @@ -0,0 +1,47 @@ +import { createRef } from 'react'; + +export class RefsManager { + constructor() { + this.refInsStore = {}; + } + + clearNullRefs() { + Object.keys(this.refInsStore).forEach((refName) => { + const filteredInsList = this.refInsStore[refName].filter( + (insRef) => !!insRef.current + ); + if (filteredInsList.length > 0) { + this.refInsStore[refName] = filteredInsList; + } else { + delete this.refInsStore[refName]; + } + }); + } + + get(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName][0].current; + } + + return null; + } + + getAll(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName].map((i) => i.current); + } + + return []; + } + + linkRef(refName) { + const refIns = createRef(); + this.refInsStore[refName] = this.refInsStore[refName] || []; + this.refInsStore[refName].push(refIns); + return refIns; + } +} + +export default {}; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/schema.json5 new file mode 100644 index 0000000000..5b6776c1ee --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/schema.json5 @@ -0,0 +1,273 @@ +{ + version: '1.0.0', + componentsMap: [ + { + componentName: 'Button', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'Button', + }, + { + componentName: 'Button.Group', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'Button', + subName: 'Group', + }, + { + componentName: 'Input', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'Input', + }, + { + componentName: 'Form', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'Form', + }, + { + componentName: 'Form.Item', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'Form', + subName: 'Item', + }, + { + componentName: 'NumberPicker', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'NumberPicker', + }, + { + componentName: 'Select', + package: '@alifd/next', + version: '1.19.18', + destructuring: true, + exportName: 'Select', + }, + ], + componentsTree: [ + { + componentName: 'Page', + id: 'node$1', + meta: { + title: '测试', + router: '/', + }, + props: { + ref: 'outterView', + autoLoading: true, + }, + fileName: 'test', + state: { + text: 'outter', + }, + lifeCycles: { + componentDidMount: { + type: 'JSFunction', + value: "function() { console.log('componentDidMount'); }", + }, + }, + dataSource: { + list: [ + { + id: 'urlParams', + type: 'urlParams', + }, + // 示例数据源:https://shs.xxx.com/mock/1458/demo/user + { + id: 'user', + type: 'fetch', + options: { + method: 'GET', + uri: 'https://shs.xxx.com/mock/1458/demo/user', + isSync: true, + }, + dataHandler: { + type: 'JSFunction', + value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data;\n}', + }, + }, + // 示例数据源:https://shs.xxx.com/mock/1458/demo/orders + { + id: 'orders', + type: 'fetch', + options: { + method: 'GET', + uri: 'https://shs.xxx.com/mock/1458/demo/orders', + isSync: true, + }, + dataHandler: { + type: 'JSFunction', + value: 'function (response) {\nif (!response.data.success){\n throw new Error(response.data.message);\n }\n return response.data.data.result;\n}', + }, + }, + ], + dataHandler: { + type: 'JSFunction', + value: 'function (dataMap) {\n console.info("All datasources loaded:", dataMap);\n}', + }, + }, + children: [ + { + componentName: 'Form', + id: 'node$2', + props: { + labelCol: { + type: 'JSExpression', + value: 'this.state.colNum', + }, + style: {}, + ref: 'testForm', + }, + children: [ + { + componentName: 'Form.Item', + id: 'node$3', + props: { + label: '姓名:', + name: 'name', + initValue: '李雷', + }, + children: [ + { + componentName: 'Input', + id: 'node$4', + props: { + placeholder: '请输入', + size: 'medium', + style: { + width: 320, + }, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node$5', + props: { + label: '年龄:', + name: 'age', + initValue: '22', + }, + children: [ + { + componentName: 'NumberPicker', + id: 'node$6', + props: { + size: 'medium', + type: 'normal', + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node$7', + props: { + label: '职业:', + name: 'profession', + }, + children: [ + { + componentName: 'Select', + id: 'node$8', + props: { + dataSource: [ + { + label: '教师', + value: 't', + }, + { + label: '医生', + value: 'd', + }, + { + label: '歌手', + value: 's', + }, + ], + }, + }, + ], + }, + { + componentName: 'Div', + id: 'node$9', + props: { + style: { + textAlign: 'center', + }, + }, + children: [ + { + componentName: 'Button.Group', + id: 'node$a', + props: {}, + children: [ + { + componentName: 'Button', + id: 'node$b', + condition: false, + loop: ['a', 'b', 'c'], + props: { + type: 'primary', + style: { + margin: '0 5px 0 5px', + }, + }, + children: [ + { + type: 'JSExpression', + value: 'this.item', + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + constants: { + ENV: 'prod', + DOMAIN: 'xxx.xxx.com', + }, + css: 'body {font-size: 12px;} .table { width: 100px;}', + config: { + sdkVersion: '1.0.3', + historyMode: 'hash', + targetRootID: 'J_Container', + layout: { + componentName: 'BasicLayout', + props: { + logo: '...', + name: '测试网站', + }, + }, + theme: { + package: '@alife/theme-fusion', + version: '^0.1.0', + primary: '#ff9966', + }, + }, + meta: { + name: 'demo应用', + git_group: 'appGroup', + project_name: 'app_demo', + description: '这是一个测试应用', + spma: 'spa23d', + creator: '月飞', + }, +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/.browserslistrc b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/.browserslistrc new file mode 100644 index 0000000000..55a130413d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/.browserslistrc @@ -0,0 +1,3 @@ +defaults +ios_saf 9 + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/.gitignore b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/.gitignore new file mode 100644 index 0000000000..4ec178818e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/.gitignore @@ -0,0 +1,25 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/README.md b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/README.md new file mode 100644 index 0000000000..6d9dd75215 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/README.md @@ -0,0 +1 @@ +This project is generated by lowcode-code-generator & lowcode-solution-icejs3. \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/ice.config.mts new file mode 100644 index 0000000000..fe77c9b6cd --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/ice.config.mts @@ -0,0 +1,90 @@ +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + }, + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = ` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + `; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion({ + importStyle: true, + }), + locales(), + plugin(), + ], +})); + diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/package.json new file mode 100644 index 0000000000..399ff4333b --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/package.json @@ -0,0 +1,45 @@ +{ + "name": "icejs3-demo-app", + "version": "0.1.5", + "description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。", + "dependencies": { + "moment": "^2.24.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router": "^6.9.0", + "react-router-dom": "^6.9.0", + "intl-messageformat": "^9.3.6", + "@alifd/next": "1.26.15", + "@ice/runtime": "^1.0.0", + "@alilc/lowcode-datasource-engine": "^1.0.0", + "undefined": "*", + "@alilc/antd-lowcode": "0.8.0", + "@alife/container": "0.3.7" + }, + "devDependencies": { + "@ice/app": "^3.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/node": "^18.11.17", + "@ice/plugin-fusion": "^1.0.1", + "@ice/plugin-moment-locales": "^1.0.0", + "eslint": "^6.0.1", + "stylelint": "^13.2.0" + }, + "scripts": { + "start": "ice start", + "build": "ice build", + "lint": "npm run eslint && npm run stylelint", + "eslint": "eslint --cache --ext .js,.jsx ./", + "stylelint": "stylelint ./**/*.scss" + }, + "engines": { + "node": ">=14.0.0" + }, + "repository": { + "type": "git", + "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" + }, + "private": true, + "originTemplate": "@alifd/scaffold-lite-js" +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/app.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/app.ts new file mode 100644 index 0000000000..6d5856292d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/app.ts @@ -0,0 +1,13 @@ +import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +})); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/constants.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/constants.js new file mode 100644 index 0000000000..ea766c9da3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/constants.js @@ -0,0 +1,3 @@ +const __$$constants = {}; + +export default __$$constants; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/document.tsx new file mode 100644 index 0000000000..286be9f8ca --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/document.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/global.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/global.scss new file mode 100644 index 0000000000..82ca3eac73 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/global.scss @@ -0,0 +1,6 @@ +// 引入默认全局样式 +@import '@alifd/next/reset.scss'; + +body { + -webkit-font-smoothing: antialiased; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/i18n.js new file mode 100644 index 0000000000..adbbe673dc --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/i18n.js @@ -0,0 +1,77 @@ +const i18nConfig = {}; + +let locale = + typeof navigator === 'object' && typeof navigator.language === 'string' + ? navigator.language + : 'zh-CN'; + +const getLocale = () => locale; + +const setLocale = (target) => { + locale = target; +}; + +const isEmptyVariables = (variables) => + (Array.isArray(variables) && variables.length === 0) || + (typeof variables === 'object' && + (!variables || Object.keys(variables).length === 0)); + +// 按低代码规范里面的要求进行变量替换 +const format = (msg, variables) => + typeof msg === 'string' + ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + : msg; + +const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { + const msg = + i18nConfig[locale]?.[id] ?? + i18nConfig[locale.replace('-', '_')]?.[id] ?? + defaultMessage; + if (msg == null) { + console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); + return fallback === undefined ? `${id}` : fallback; + } + + return format(msg, variables); +}; + +const i18n = (id, params) => { + return i18nFormat({ id }, params); +}; + +// 将国际化的一些方法注入到目标对象&上下文中 +const _inject2 = (target) => { + target.i18n = i18n; + target.getLocale = getLocale; + target.setLocale = (locale) => { + setLocale(locale); + target.forceUpdate(); + }; + target._i18nText = (t) => { + // 优先取直接传过来的语料 + const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]; + if (localMsg != null) { + return format(localMsg, t.params); + } + + // 其次用项目级别的 + const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params); + if (projectMsg != null) { + return projectMsg; + } + + // 兜底用 use 指定的或默认语言的 + return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params); + }; + + // 注入到上下文中去 + if (target._context && target._context !== target) { + Object.assign(target._context, { + i18n, + getLocale, + setLocale: target.setLocale, + }); + } +}; + +export { getLocale, setLocale, i18n, i18nFormat, _inject2 }; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx new file mode 100644 index 0000000000..cc70d53bea --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx @@ -0,0 +1,14 @@ + +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss new file mode 100644 index 0000000000..81e77fda5f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss @@ -0,0 +1,15 @@ + +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx new file mode 100644 index 0000000000..265bfdaa07 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss new file mode 100644 index 0000000000..1ab56d3945 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -0,0 +1,20 @@ + +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx new file mode 100644 index 0000000000..911998b0d3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/index.jsx new file mode 100644 index 0000000000..18db44df5e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/index.jsx @@ -0,0 +1,81 @@ + +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js new file mode 100644 index 0000000000..5332202be4 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js @@ -0,0 +1,11 @@ + +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.css b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.css new file mode 100644 index 0000000000..066114aeeb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.css @@ -0,0 +1,8 @@ +body { + font-size: 12px; +} + +.botton { + width: 100px; + color: #ff00ff; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.jsx new file mode 100644 index 0000000000..9e93a3ff6f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/Test/index.jsx @@ -0,0 +1,1076 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:react 框架的导出名和各种组件名除外。 +import React from 'react'; + +import { + Modal, + Steps, + Form, + Input, + Checkbox, + Select, + DatePicker, + InputNumber, + Button, +} from '@alilc/antd-lowcode/dist/antd-lowcode.esm.js'; + +import { + Text as NextText, + Page as NextPage, + Block as NextBlock, + P as NextP, +} from '@alife/container/lib/index.js'; + +import utils, { RefsManager } from '../../utils'; + +import * as __$$i18n from '../../i18n'; + +import __$$constants from '../../constants'; + +import './index.css'; + +const NextBlockCell = NextBlock.Cell; + +class Test$$Page extends React.Component { + _context = this; + + get constants() { + return __$$constants || {}; + } + + constructor(props, context) { + super(props); + + this.utils = utils; + + this._refsManager = new RefsManager(); + + __$$i18n._inject2(this); + + this.state = { + books: [], + currentStep: 0, + isModifyDialogVisible: false, + isModifyStatus: false, + secondCommitText: '完成并提交', + thirdAuditText: '审核中', + thirdButtonText: '修改', + customerProjectInfo: { + id: null, + systemProjectName: null, + projectVersionTypeArray: null, + projectVersionType: null, + versionLine: 2, + expectedTime: null, + expectedNum: null, + projectModal: null, + displayWidth: null, + displayHeight: null, + displayInch: null, + displayDpi: null, + mainSoc: null, + cpuCoreNum: null, + instructions: null, + osVersion: null, + status: null, + }, + versionLinesArray: [ + { label: 'AmapAuto 485', value: 1 }, + { label: 'AmapAuto 505', value: 2 }, + ], + projectModalsArray: [ + { label: '车机', value: 1 }, + { label: '车镜', value: 2 }, + { label: '记录仪', value: 3 }, + { label: '其他', value: 4 }, + ], + osVersionsArray: [ + { label: '安卓5', value: 1 }, + { label: '安卓6', value: 2 }, + { label: '安卓7', value: 3 }, + { label: '安卓8', value: 4 }, + { label: '安卓9', value: 5 }, + { label: '安卓10', value: 6 }, + ], + instructionsArray: [ + { label: 'ARM64-V8', value: 'ARM64-V8' }, + { label: 'ARM32-V7', value: 'ARM32-V7' }, + { label: 'X86', value: 'X86' }, + { label: 'X64', value: 'X64' }, + ], + }; + } + + $ = (refName) => { + return this._refsManager.get(refName); + }; + + $$ = (refName) => { + return this._refsManager.getAll(refName); + }; + + componentDidUpdate(prevProps, prevState, snapshot) {} + + componentWillUnmount() {} + + __jp__init() { + /*...*/ + } + + __jp__initRouter() { + /*...*/ + } + + __jp__initDataSource() { + /*...*/ + } + + __jp__initEnv() { + /*...*/ + } + + __jp__initUtils() { + /*...*/ + } + + onFinishFirst() { + /*...*/ + } + + onClickPreSecond() { + /*...*/ + } + + onFinishSecond() { + /*...*/ + } + + onClickModifyThird() { + /*...*/ + } + + onOkModifyDialogThird() { + //第三步 修改 对话框 确定 + + this.setState({ + currentStep: 0, + isModifyDialogVisible: false, + }); + } + + onCancelModifyDialogThird() { + //第三步 修改 对话框 取消 + + this.setState({ + isModifyDialogVisible: false, + }); + } + + onFinishFailed() {} + + onClickPreThird() { + // 第三步 上一步 + this.setState({ + currentStep: 1, + }); + } + + onClickFirstBack() { + // 第一步 返回按钮 + this.$router.push('/myProjectList'); + } + + onClickSecondBack() { + // 第二步 返回按钮 + this.$router.push('/myProjectList'); + } + + onClickThirdBack() { + // 第三步 返回按钮 + this.$router.push('/myProjectList'); + } + + onValuesChange(_, values) { + this.setState({ + customerProjectInfo: { + ...this.state.customerProjectInfo, + ...values, + }, + }); + } + + componentDidMount() {} + + render() { + const __$$context = this._context || this; + const { state } = __$$context; + return ( + <div + ref={this._refsManager.linkRef('outterView')} + style={{ height: '100%' }} + > + <Modal + title="是否修改" + visible={__$$eval(() => this.state.isModifyDialogVisible)} + okText="确认" + okType="" + forceRender={false} + cancelText="取消" + zIndex={2000} + destroyOnClose={false} + confirmLoading={false} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onOk', + relatedEventName: 'onOkModifyDialogThird', + }, + { + type: 'componentEvent', + name: 'onCancel', + relatedEventName: 'onCancelModifyDialogThird', + }, + ], + eventList: [ + { name: 'onCancel', disabled: true }, + { name: 'onOk', disabled: true }, + ], + }} + onOk={function () { + this.onOkModifyDialogThird.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + onCancel={function () { + this.onCancelModifyDialogThird.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + <NextText + type="inherit" + style={{ + fontStyle: 'normal', + textAlign: 'left', + display: 'block', + fontFamily: 'arial, helvetica, microsoft yahei', + fontWeight: 'normal', + }} + > + 修改将撤回此前填写的信息 + </NextText> + </Modal> + <NextPage + columns={12} + headerDivider={true} + placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }} + placeholder="页面主体内容:拖拽Block布局组件到这里" + header={null} + headerProps={{ background: 'surface' }} + footer={null} + minHeight="100vh" + style={{}} + > + <NextBlock + prefix="next-" + placeholderStyle={{ height: '100%' }} + noPadding={false} + noBorder={false} + background="surface" + layoutmode="O" + colSpan={12} + rowSpan={1} + childTotalColumns={12} + > + <NextBlockCell + title="" + prefix="next-" + placeholderStyle={{ height: '100%' }} + layoutmode="O" + childTotalColumns={12} + isAutoContainer={true} + colSpan={12} + rowSpan={1} + > + <NextP + wrap={false} + type="body2" + verAlign="middle" + textSpacing={true} + align="left" + flex={true} + style={{ marginBottom: '24px' }} + > + <Steps current={__$$eval(() => this.state.currentStep)}> + <Steps.Step title="版本申请" description="" /> + <Steps.Step title="机器配置" subTitle="" description="" /> + <Steps.Step title="项目审批" description="" /> + </Steps> + </NextP> + {!!__$$eval(() => this.state.currentStep === 0) && ( + <NextP + wrap={false} + type="body2" + verAlign="middle" + textSpacing={true} + align="left" + full={true} + flex={true} + style={{ display: 'flex', justifyContent: 'center' }} + > + <Form + labelCol={{ span: 10 }} + wrapperCol={{ span: 10 }} + onFinish={function () { + this.onFinishFirst.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + name="basic" + style={{ + display: 'flex', + flexDirection: 'column', + width: '600px', + justifyContent: 'center', + }} + layout="vertical" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onFinish', + relatedEventName: 'onFinishFirst', + }, + { + type: 'componentEvent', + name: 'onValuesChange', + relatedEventName: 'onValuesChange', + }, + ], + eventList: [ + { name: 'onFinish', disabled: true }, + { name: 'onFinishFailed', disabled: false }, + { name: 'onFieldsChange', disabled: false }, + { name: 'onValuesChange', disabled: true }, + ], + }} + initialValues={__$$eval( + () => this.state.customerProjectInfo + )} + onValuesChange={function () { + this.onValuesChange.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + {!!false && ( + <Form.Item + label="" + style={{ width: '600px' }} + colon={false} + name="id" + > + <Input + placeholder="" + style={{ width: '600px' }} + bordered={false} + disabled={true} + /> + </Form.Item> + )} + <Form.Item + label="版本类型选择" + name="projectVersionTypeArray" + initialValue="" + labelAlign="left" + colon={false} + required={true} + style={{ flexDirection: 'column', width: '600px' }} + requiredobj={{ + required: true, + message: '请选择版本类型', + }} + > + <Checkbox.Group + options={[ + { label: '基础版本', value: '3' }, + { label: 'AR导航', value: '1' }, + { label: '货车导航', value: '2' }, + { label: 'UI定制', value: '4', disabled: false }, + ]} + style={{ width: '600px' }} + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + /> + </Form.Item> + <Form.Item + label="版本线选择" + labelAlign="left" + colon={false} + required={true} + style={{ width: '600px' }} + name="versionLine" + requiredobj={{ required: true, message: '请选择版本线' }} + extra="" + > + <Select + style={{ width: '600px' }} + options={__$$eval(() => this.state.versionLinesArray)} + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + placeholder="请选择版本线" + /> + </Form.Item> + <Form.Item + label="项目名称" + colon={false} + required={true} + style={{ display: 'flex' }} + labelAlign="left" + extra="" + name="systemProjectName" + requiredobj={{ + required: true, + message: '请按格式填写项目名称', + }} + typeobj={{ + type: 'string', + message: + '请输入项目名称,格式:公司简称-产品名称-版本类型', + }} + lenobj={{ + max: 100, + message: '项目名称不能超过100个字符', + }} + > + <Input + placeholder="公司简称-产品名称-版本类型" + style={{ width: '600px' }} + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + /> + </Form.Item> + <Form.Item + label="预期交付时间" + style={{ width: '600px' }} + colon={false} + required={true} + name="expectedTime" + labelAlign="left" + requiredobj={{ + required: true, + message: '请填写预期交付时间', + }} + > + <DatePicker + style={{ width: '600px' }} + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + /> + </Form.Item> + <Form.Item + label="预期出货量" + style={{ width: '600px' }} + required={true} + requiredobj={{ + required: true, + message: '请填写预期出货量', + }} + name="expectedNum" + labelAlign="left" + colon={false} + > + <InputNumber + value={3} + style={{ width: '600px' }} + placeholder="单位(台)使用该版本的机器数量+预计出货量,请如实填写" + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + min={0} + size="middle" + /> + </Form.Item> + <Form.Item + wrapperCol={{ offset: '' }} + style={{ + flexDirection: 'row', + alignItems: 'baseline', + justifyContent: 'space-between', + width: '600px', + display: 'block', + }} + labelAlign="left" + colon={false} + > + <Button + style={{ margin: '0px' }} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onClickFirstBack', + }, + ], + eventList: [{ name: 'onClick', disabled: true }], + }} + onClick={function () { + this.onClickFirstBack.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + 返回 + </Button> + <Button + type="primary" + htmlType="submit" + style={{ + boxShadow: 'rgba(31, 56, 88, 0.2) 0px 0px 0px 0px', + float: 'right', + }} + __events={{ + eventDataList: [], + eventList: [{ name: 'onClick', disabled: false }], + }} + > + 下一步 + </Button> + </Form.Item> + </Form> + </NextP> + )} + {!!__$$eval(() => this.state.currentStep === 1) && ( + <NextP + wrap={false} + type="body2" + verAlign="middle" + textSpacing={true} + align="left" + full={true} + flex={true} + style={{ display: 'flex', justifyContent: 'center' }} + > + <Form + labelCol={{ span: 10 }} + wrapperCol={{ span: 10 }} + onFinish={function () { + this.onFinishSecond.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + name="basic" + style={{ + display: 'flex', + flexDirection: 'column', + width: '600px', + justifyContent: 'center', + height: '800px', + }} + layout="vertical" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onFinish', + relatedEventName: 'onFinishSecond', + }, + { + type: 'componentEvent', + name: 'onValuesChange', + relatedEventName: 'onValuesChange', + }, + ], + eventList: [ + { name: 'onFinish', disabled: true }, + { name: 'onFinishFailed', disabled: false }, + { name: 'onFieldsChange', disabled: false }, + { name: 'onValuesChange', disabled: true }, + ], + }} + initialValues={__$$eval( + () => this.state.customerProjectInfo + )} + onValuesChange={function () { + this.onValuesChange.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + <Form.Item + label="设备类型选择" + labelAlign="left" + colon={false} + required={true} + style={{ width: '600px' }} + name="projectModal" + requiredobj={{ + required: true, + message: '请选择设备类型', + }} + > + <Select + style={{ width: '600px' }} + options={__$$eval(() => this.state.projectModalsArray)} + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + placeholder="请选择设备类型" + /> + </Form.Item> + <Form.Item + label="屏幕分辨率宽" + style={{ width: '600px' }} + name="displayWidth" + colon={false} + required={true} + requiredobj={{ + required: true, + message: '请输入屏幕分辨率宽', + }} + labelAlign="left" + > + <InputNumber + value={3} + style={{ width: '600px' }} + placeholder="例如1280" + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + min={0} + /> + </Form.Item> + <Form.Item + label="屏幕分辨率高" + style={{ width: '600px' }} + labelAlign="left" + colon={false} + name="displayHeight" + required={true} + requiredobj={{ + required: true, + message: '请输入屏幕分辨率高', + }} + > + <InputNumber + value={3} + style={{ width: '600px' }} + placeholder="例如720" + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + min={0} + /> + </Form.Item> + <Form.Item + label="屏幕尺寸(inch)" + style={{ width: '600px' }} + name="displayInch" + labelAlign="left" + required={true} + colon={false} + requiredobj={{ + required: true, + message: '请输入屏幕尺寸', + }} + > + <InputNumber + value={3} + style={{ width: '600px' }} + placeholder="请输入尺寸" + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + min={0} + /> + </Form.Item> + <Form.Item + label="屏幕DPI" + style={{ width: '600px' }} + labelAlign="left" + colon={false} + required={false} + name="displayDpi" + > + <InputNumber + value={3} + style={{ width: '600px' }} + placeholder="UI定制项目必填" + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + min={0} + /> + </Form.Item> + <Form.Item + label="芯片名称" + colon={false} + required={true} + style={{ display: 'flex' }} + labelAlign="left" + extra="" + name="mainSoc" + requiredobj={{ + required: true, + message: '请输入芯片名称', + }} + lenobj={{ max: 50, message: '芯片名称不能超过50个字符' }} + > + <Input + placeholder="请输入芯片名称" + style={{ width: '600px' }} + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + /> + </Form.Item> + <Form.Item + label="芯片核数" + style={{ width: '600px' }} + required={true} + requiredobj={{ + required: true, + message: '请输入芯片核数', + }} + name="cpuCoreNum" + labelAlign="left" + colon={false} + > + <InputNumber + value={3} + style={{ width: '600px' }} + placeholder="请输入芯片核数" + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + defaultValue="" + min={0} + /> + </Form.Item> + <Form.Item + label="指令集" + style={{ width: '600px' }} + required={true} + requiredobj={{ required: true, message: '请选择指令集' }} + name="instructions" + colon={false} + > + <Select + style={{ width: '600px' }} + options={__$$eval(() => this.state.instructionsArray)} + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + /> + </Form.Item> + <Form.Item + label="系统版本" + labelAlign="left" + colon={false} + required={true} + style={{ width: '600px' }} + name="osVersion" + requiredobj={{ + required: true, + message: '请选择系统版本', + }} + > + <Select + style={{ width: '600px' }} + options={__$$eval(() => this.state.osVersionsArray)} + disabled={__$$eval( + () => + this.state.customerProjectInfo.id > 0 && + !this.state.isModifyStatus + )} + placeholder="请选择系统版本" + /> + </Form.Item> + <Form.Item + wrapperCol={{ offset: '' }} + style={{ + flexDirection: 'row', + width: '600px', + display: 'flex', + }} + > + <Button + style={{ marginLeft: '0' }} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onClickSecondBack', + }, + ], + eventList: [{ name: 'onClick', disabled: true }], + }} + onClick={function () { + this.onClickSecondBack.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + 返回 + </Button> + <Button + type="primary" + htmlType="submit" + style={{ float: 'right', marginLeft: '20px' }} + loading={__$$eval( + () => + this.state.LOADING_ADD_OR_UPDATE_CUSTOMER_PROJECT + )} + > + {__$$eval(() => this.state.secondCommitText)} + </Button> + <Button + type="primary" + htmlType="submit" + style={{ marginLeft: '0px', float: 'right' }} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onClickPreSecond', + }, + ], + eventList: [{ name: 'onClick', disabled: true }], + }} + onClick={function () { + this.onClickPreSecond.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + 上一步 + </Button> + </Form.Item> + </Form> + </NextP> + )} + {!!__$$eval(() => this.state.currentStep === 2) && ( + <NextP + wrap={false} + type="body2" + verAlign="middle" + textSpacing={true} + align="left" + full={true} + flex={true} + style={{ display: 'flex', justifyContent: 'center' }} + > + <Form + labelCol={{ span: 10 }} + wrapperCol={{ span: 10 }} + onFinishFailed={function () { + this.onFinishFailed.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + name="basic" + style={{ + display: 'flex', + flexDirection: 'column', + width: '600px', + justifyContent: 'center', + }} + layout="vertical" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onFinishFailed', + relatedEventName: 'onFinishFailed', + }, + ], + eventList: [ + { name: 'onFinish', disabled: false }, + { name: 'onFinishFailed', disabled: true }, + { name: 'onFieldsChange', disabled: false }, + { name: 'onValuesChange', disabled: false }, + ], + }} + > + <Form.Item label=""> + <Steps + current={1} + style={{ + width: '600px', + display: 'flex', + justifyContent: 'space-around', + alignItems: 'center', + height: '300px', + }} + labelPlacement="horizontal" + direction="vertical" + > + <Steps.Step + title="提交完成" + description="" + style={{ width: '200px' }} + /> + <Steps.Step + title={__$$eval(() => this.state.thirdAuditText)} + subTitle="" + description="" + style={{ width: '200px' }} + /> + </Steps> + </Form.Item> + <Form.Item + wrapperCol={{ offset: '' }} + style={{ + flexDirection: 'row', + width: '600px', + display: 'flex', + }} + > + <Button + style={{ marginLeft: '0' }} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onClickThirdBack', + }, + ], + eventList: [{ name: 'onClick', disabled: true }], + }} + onClick={function () { + this.onClickThirdBack.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + 返回 + </Button> + <Button + type="primary" + htmlType="submit" + style={{ float: 'right', marginLeft: '20px' }} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onClickModifyThird', + }, + ], + eventList: [{ name: 'onClick', disabled: true }], + }} + onClick={function () { + this.onClickModifyThird.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + {__$$eval(() => this.state.thirdButtonText)} + </Button> + {!!__$$eval( + () => this.state.customerProjectInfo.status > 2 + ) && ( + <Button + type="primary" + htmlType="submit" + style={{ marginLeft: '0px', float: 'right' }} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onClickPreThird', + }, + ], + eventList: [{ name: 'onClick', disabled: true }], + }} + onClick={function () { + this.onClickPreThird.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + 上一步 + </Button> + )} + </Form.Item> + </Form> + </NextP> + )} + </NextBlockCell> + </NextBlock> + </NextPage> + </div> + ); + } +} + +export default Test$$Page; + +function __$$eval(expr) { + try { + return expr(); + } catch (error) {} +} + +function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; +} + +function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/layout.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/layout.jsx new file mode 100644 index 0000000000..50fbb2d1f1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/pages/layout.jsx @@ -0,0 +1,10 @@ +import { Outlet } from 'ice'; +import BasicLayout from '@/layouts/BasicLayout'; + +export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + ); +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/typings.d.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/typings.d.ts new file mode 100644 index 0000000000..a9f8de7ceb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/typings.d.ts @@ -0,0 +1,9 @@ +/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/utils.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/utils.js new file mode 100644 index 0000000000..1190717924 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/utils.js @@ -0,0 +1,47 @@ +import { createRef } from 'react'; + +export class RefsManager { + constructor() { + this.refInsStore = {}; + } + + clearNullRefs() { + Object.keys(this.refInsStore).forEach((refName) => { + const filteredInsList = this.refInsStore[refName].filter( + (insRef) => !!insRef.current + ); + if (filteredInsList.length > 0) { + this.refInsStore[refName] = filteredInsList; + } else { + delete this.refInsStore[refName]; + } + }); + } + + get(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName][0].current; + } + + return null; + } + + getAll(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName].map((i) => i.current); + } + + return []; + } + + linkRef(refName) { + const refIns = createRef(); + this.refInsStore[refName] = this.refInsStore[refName] || []; + this.refInsStore[refName].push(refIns); + return refIns; + } +} + +export default {}; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/schema.json5 new file mode 100644 index 0000000000..4c829cfab1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/schema.json5 @@ -0,0 +1,1703 @@ +{ + version: '1.0.0', + componentsMap: [ + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Text', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextText', + }, + { + package: '@alilc/antd-lowcode', + version: '0.8.0', + exportName: 'Modal', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Modal', + }, + { + package: '@alilc/antd-lowcode', + version: '0.8.0', + exportName: 'Steps', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + subName: 'Step', + componentName: 'Steps.Step', + }, + { + package: '@alilc/antd-lowcode', + version: '0.8.0', + exportName: 'Steps', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Steps', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'P', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextP', + }, + { + package: '@alilc/antd-lowcode', + version: '0.8.0', + exportName: 'Input', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Input', + }, + { + package: '@alilc/antd-lowcode', + version: '0.8.0', + exportName: 'Form', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + subName: 'Item', + componentName: 'Form.Item', + }, + { + package: '@alilc/antd-lowcode', + version: '0.8.0', + exportName: 'Checkbox', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + subName: 'Group', + componentName: 'Checkbox.Group', + }, + { + package: '@alilc/antd-lowcode', + version: '0.8.0', + exportName: 'Select', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Select', + }, + { + package: '@alilc/antd-lowcode', + version: '0.8.0', + exportName: 'DatePicker', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'DatePicker', + }, + { + package: '@alilc/antd-lowcode', + version: '0.8.0', + exportName: 'InputNumber', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'InputNumber', + }, + { + package: '@alilc/antd-lowcode', + version: '0.8.0', + exportName: 'Button', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Button', + }, + { + package: '@alilc/antd-lowcode', + version: '0.8.0', + exportName: 'Form', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Form', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Block', + main: 'lib/index.js', + destructuring: true, + subName: 'Cell', + componentName: 'NextBlockCell', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Block', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextBlock', + }, + { + devMode: 'lowcode', + componentName: 'Slot', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Page', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextPage', + }, + { + devMode: 'lowcode', + componentName: 'Page', + }, + ], + componentsTree: [ + { + componentName: 'Page', + id: 'node_dockcviv8fo1', + props: { + ref: 'outterView', + style: { + height: '100%', + }, + }, + fileName: 'test', + dataSource: { + list: [], + }, + css: 'body {\n font-size: 12px;\n}\n\n.botton {\n width: 100px;\n color: #ff00ff\n}', + lifeCycles: { + constructor: { + type: 'JSFunction', + value: "function() { /*...*/ }", + }, + componentDidMount: { + type: 'JSFunction', + value: 'function() {}', + }, + componentDidUpdate: { + type: 'JSFunction', + value: 'function(prevProps, prevState, snapshot) {}', + }, + componentWillUnmount: { + type: 'JSFunction', + value: 'function() {}', + }, + }, + methods: { + __jp__init: { + type: 'JSFunction', + value: "function() { /*...*/ }", + }, + __jp__initRouter: { + type: 'JSFunction', + value: "function() { /*...*/ }", + }, + __jp__initDataSource: { + type: 'JSFunction', + value: "function() { /*...*/ }", + }, + __jp__initEnv: { + type: 'JSFunction', + value: "function() { /*...*/ }", + }, + __jp__initUtils: { + type: 'JSFunction', + value: "function() { /*...*/ }", + }, + onFinishFirst: { + type: 'JSFunction', + value: "function() { /*...*/ }", + }, + onClickPreSecond: { + type: 'JSFunction', + value: "function() { /*...*/ }", + }, + onFinishSecond: { + type: 'JSFunction', + value: "function() { /*...*/ }", + }, + onClickModifyThird: { + type: 'JSFunction', + value: "function() { /*...*/ }", + }, + onOkModifyDialogThird: { + type: 'JSFunction', + value: 'function() {\n //第三步 修改 对话框 确定\n\n this.setState({\n currentStep: 0,\n isModifyDialogVisible: false,\n });\n }', + }, + onCancelModifyDialogThird: { + type: 'JSFunction', + value: 'function() {\n //第三步 修改 对话框 取消\n\n this.setState({\n isModifyDialogVisible: false,\n });\n }', + }, + onFinishFailed: { + type: 'JSFunction', + value: 'function() {}', + }, + onClickPreThird: { + type: 'JSFunction', + value: 'function() {\n // 第三步 上一步\n this.setState({\n currentStep: 1,\n });\n }', + }, + onClickFirstBack: { + type: 'JSFunction', + value: "function() {\n // 第一步 返回按钮\n this.$router.push('/myProjectList');\n }", + }, + onClickSecondBack: { + type: 'JSFunction', + value: "function() {\n // 第二步 返回按钮\n this.$router.push('/myProjectList');\n }", + }, + onClickThirdBack: { + type: 'JSFunction', + value: "function() {\n // 第三步 返回按钮\n this.$router.push('/myProjectList');\n }", + }, + onValuesChange: { + type: 'JSFunction', + value: 'function(_, values) {\n this.setState({\n customerProjectInfo: {\n ...this.state.customerProjectInfo,\n ...values,\n },\n });\n }', + }, + }, + state: { + books: [], + currentStep: 0, + isModifyDialogVisible: false, + isModifyStatus: false, + secondCommitText: '完成并提交', + thirdAuditText: '审核中', + thirdButtonText: '修改', + customerProjectInfo: { + id: null, + systemProjectName: null, + projectVersionTypeArray: null, + projectVersionType: null, + versionLine: 2, + expectedTime: null, + expectedNum: null, + projectModal: null, + displayWidth: null, + displayHeight: null, + displayInch: null, + displayDpi: null, + mainSoc: null, + cpuCoreNum: null, + instructions: null, + osVersion: null, + status: null, + }, + versionLinesArray: [ + { + label: 'AmapAuto 485', + value: 1, + }, + { + label: 'AmapAuto 505', + value: 2, + }, + ], + projectModalsArray: [ + { + label: '车机', + value: 1, + }, + { + label: '车镜', + value: 2, + }, + { + label: '记录仪', + value: 3, + }, + { + label: '其他', + value: 4, + }, + ], + osVersionsArray: [ + { + label: '安卓5', + value: 1, + }, + { + label: '安卓6', + value: 2, + }, + { + label: '安卓7', + value: 3, + }, + { + label: '安卓8', + value: 4, + }, + { + label: '安卓9', + value: 5, + }, + { + label: '安卓10', + value: 6, + }, + ], + instructionsArray: [ + { + label: 'ARM64-V8', + value: 'ARM64-V8', + }, + { + label: 'ARM32-V7', + value: 'ARM32-V7', + }, + { + label: 'X86', + value: 'X86', + }, + { + label: 'X64', + value: 'X64', + }, + ], + }, + children: [ + { + componentName: 'Modal', + id: 'node_ockodngwu940', + props: { + title: '是否修改', + visible: { + type: 'JSExpression', + value: 'this.state.isModifyDialogVisible', + }, + okText: '确认', + okType: '', + forceRender: false, + cancelText: '取消', + zIndex: 2000, + destroyOnClose: false, + confirmLoading: false, + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onOk', + relatedEventName: 'onOkModifyDialogThird', + }, + { + type: 'componentEvent', + name: 'onCancel', + relatedEventName: 'onCancelModifyDialogThird', + }, + ], + eventList: [ + { + name: 'onCancel', + disabled: true, + }, + { + name: 'onOk', + disabled: true, + }, + ], + }, + onOk: { + type: 'JSFunction', + value: 'function(){this.onOkModifyDialogThird.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + onCancel: { + type: 'JSFunction', + value: 'function(){this.onCancelModifyDialogThird.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + hidden: true, + children: [ + { + componentName: 'NextText', + id: 'node_ockodngwu946', + props: { + type: 'inherit', + children: '修改将撤回此前填写的信息', + style: { + fontStyle: 'normal', + textAlign: 'left', + display: 'block', + fontFamily: 'arial, helvetica, microsoft yahei', + fontWeight: 'normal', + }, + }, + }, + ], + }, + { + componentName: 'NextPage', + id: 'node_ocko19zplh1', + props: { + columns: 12, + headerDivider: true, + placeholderStyle: { + gridRowEnd: 'span 1', + gridColumnEnd: 'span 12', + }, + placeholder: '页面主体内容:拖拽Block布局组件到这里', + header: { + type: 'JSSlot', + title: 'header', + }, + headerProps: { + background: 'surface', + }, + footer: { + type: 'JSSlot', + title: 'footer', + }, + minHeight: '100vh', + style: {}, + }, + title: '页面', + children: [ + { + componentName: 'NextBlock', + id: 'node_ocko19zplh2', + props: { + prefix: 'next-', + placeholderStyle: { + height: '100%', + }, + noPadding: false, + noBorder: false, + background: 'surface', + layoutmode: 'O', + colSpan: 12, + rowSpan: 1, + childTotalColumns: 12, + }, + title: '区块', + children: [ + { + componentName: 'NextBlockCell', + id: 'node_ocko19zplh3', + props: { + title: '', + prefix: 'next-', + placeholderStyle: { + height: '100%', + }, + layoutmode: 'O', + childTotalColumns: 12, + isAutoContainer: true, + colSpan: 12, + rowSpan: 1, + }, + children: [ + { + componentName: 'NextP', + id: 'node_ockoco6icv1w', + props: { + wrap: false, + type: 'body2', + verAlign: 'middle', + textSpacing: true, + align: 'left', + flex: true, + style: { + marginBottom: '24px', + }, + }, + title: '段落', + children: [ + { + componentName: 'Steps', + id: 'node_ockoco6icv1x', + props: { + current: { + type: 'JSExpression', + value: 'this.state.currentStep', + }, + }, + children: [ + { + componentName: 'Steps.Step', + id: 'node_ockoco6icv1y', + props: { + title: '版本申请', + description: '', + }, + }, + { + componentName: 'Steps.Step', + id: 'node_ockoco6icv1z', + props: { + title: '机器配置', + subTitle: '', + description: '', + }, + }, + { + componentName: 'Steps.Step', + id: 'node_ockoco6icv20', + props: { + title: '项目审批', + description: '', + }, + }, + ], + }, + ], + }, + { + componentName: 'NextP', + id: 'node_ockoco6icv12w', + props: { + wrap: false, + type: 'body2', + verAlign: 'middle', + textSpacing: true, + align: 'left', + full: true, + flex: true, + style: { + display: 'flex', + justifyContent: 'center', + }, + }, + title: '段落', + condition: { + type: 'JSExpression', + value: 'this.state.currentStep === 0', + }, + children: [ + { + componentName: 'Form', + id: 'node_ockoco6icv12x', + props: { + labelCol: { + span: 10, + }, + wrapperCol: { + span: 10, + }, + onFinish: { + type: 'JSFunction', + value: 'function(){this.onFinishFirst.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + name: 'basic', + style: { + display: 'flex', + flexDirection: 'column', + width: '600px', + justifyContent: 'center', + }, + layout: 'vertical', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onFinish', + relatedEventName: 'onFinishFirst', + }, + { + type: 'componentEvent', + name: 'onValuesChange', + relatedEventName: 'onValuesChange', + }, + ], + eventList: [ + { + name: 'onFinish', + disabled: true, + }, + { + name: 'onFinishFailed', + disabled: false, + }, + { + name: 'onFieldsChange', + disabled: false, + }, + { + name: 'onValuesChange', + disabled: true, + }, + ], + }, + initialValues: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo', + }, + onValuesChange: { + type: 'JSFunction', + value: 'function(){this.onValuesChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + children: [ + { + componentName: 'Form.Item', + id: 'node_ockojhvrkn2u', + props: { + label: '', + style: { + width: '600px', + }, + colon: false, + name: 'id', + }, + condition: false, + children: [ + { + componentName: 'Input', + id: 'node_ockojhvrkn2v', + props: { + placeholder: '', + style: { + width: '600px', + }, + bordered: false, + disabled: true, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockoco6icv12y', + props: { + label: '版本类型选择', + name: 'projectVersionTypeArray', + initialValue: '', + labelAlign: 'left', + colon: false, + required: true, + style: { + flexDirection: 'column', + width: '600px', + }, + requiredobj: { + required: true, + message: '请选择版本类型', + }, + }, + children: [ + { + componentName: 'Checkbox.Group', + id: 'node_ockoco6icv12z', + props: { + options: [ + { + label: '基础版本', + value: '3', + }, + { + label: 'AR导航', + value: '1', + }, + { + label: '货车导航', + value: '2', + }, + { + label: 'UI定制', + value: '4', + disabled: false, + }, + ], + style: { + width: '600px', + }, + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockoco6icv13a', + props: { + label: '版本线选择', + labelAlign: 'left', + colon: false, + required: true, + style: { + width: '600px', + }, + name: 'versionLine', + requiredobj: { + required: true, + message: '请选择版本线', + }, + extra: '', + }, + children: [ + { + componentName: 'Select', + id: 'node_ockoco6icv13b', + props: { + style: { + width: '600px', + }, + options: { + type: 'JSExpression', + value: 'this.state.versionLinesArray', + }, + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + placeholder: '请选择版本线', + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockoco6icv13o', + props: { + label: '项目名称', + colon: false, + required: true, + style: { + display: 'flex', + }, + labelAlign: 'left', + extra: '', + name: 'systemProjectName', + requiredobj: { + required: true, + message: '请按格式填写项目名称', + }, + typeobj: { + type: 'string', + message: '请输入项目名称,格式:公司简称-产品名称-版本类型', + }, + lenobj: { + max: 100, + message: '项目名称不能超过100个字符', + }, + }, + children: [ + { + componentName: 'Input', + id: 'node_ockoco6icv13p', + props: { + placeholder: '公司简称-产品名称-版本类型', + style: { + width: '600px', + }, + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockoco6icv13v', + props: { + label: '预期交付时间', + style: { + width: '600px', + }, + colon: false, + required: true, + name: 'expectedTime', + labelAlign: 'left', + requiredobj: { + required: true, + message: '请填写预期交付时间', + }, + }, + children: [ + { + componentName: 'DatePicker', + id: 'node_ockoco6icv13w', + props: { + style: { + width: '600px', + }, + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockpmbs0bv8', + props: { + label: '预期出货量', + style: { + width: '600px', + }, + required: true, + requiredobj: { + required: true, + message: '请填写预期出货量', + }, + name: 'expectedNum', + labelAlign: 'left', + colon: false, + }, + children: [ + { + componentName: 'InputNumber', + id: 'node_ockpmbs0bv9', + props: { + value: 3, + style: { + width: '600px', + }, + placeholder: '单位(台)使用该版本的机器数量+预计出货量,请如实填写', + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + min: 0, + size: 'middle', + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockoco6icv130', + props: { + wrapperCol: { + offset: '', + }, + style: { + flexDirection: 'row', + alignItems: 'baseline', + justifyContent: 'space-between', + width: '600px', + display: 'block', + }, + labelAlign: 'left', + colon: false, + }, + children: [ + { + componentName: 'Button', + id: 'node_ockoco6icv132', + props: { + style: { + margin: '0px', + }, + children: '返回', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onClickFirstBack', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.onClickFirstBack.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + { + componentName: 'Button', + id: 'node_ockoco6icv131', + props: { + type: 'primary', + children: '下一步', + htmlType: 'submit', + style: { + boxShadow: 'rgba(31, 56, 88, 0.2) 0px 0px 0px 0px', + float: 'right', + }, + __events: { + eventDataList: [], + eventList: [ + { + name: 'onClick', + disabled: false, + }, + ], + }, + }, + }, + ], + }, + ], + }, + ], + }, + { + componentName: 'NextP', + id: 'node_ockoco6icv1ue', + props: { + wrap: false, + type: 'body2', + verAlign: 'middle', + textSpacing: true, + align: 'left', + full: true, + flex: true, + style: { + display: 'flex', + justifyContent: 'center', + }, + }, + title: '段落', + condition: { + type: 'JSExpression', + value: 'this.state.currentStep === 1', + }, + children: [ + { + componentName: 'Form', + id: 'node_ockoco6icv1uf', + props: { + labelCol: { + span: 10, + }, + wrapperCol: { + span: 10, + }, + onFinish: { + type: 'JSFunction', + value: 'function(){this.onFinishSecond.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + name: 'basic', + style: { + display: 'flex', + flexDirection: 'column', + width: '600px', + justifyContent: 'center', + height: '800px', + }, + layout: 'vertical', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onFinish', + relatedEventName: 'onFinishSecond', + }, + { + type: 'componentEvent', + name: 'onValuesChange', + relatedEventName: 'onValuesChange', + }, + ], + eventList: [ + { + name: 'onFinish', + disabled: true, + }, + { + name: 'onFinishFailed', + disabled: false, + }, + { + name: 'onFieldsChange', + disabled: false, + }, + { + name: 'onValuesChange', + disabled: true, + }, + ], + }, + initialValues: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo', + }, + onValuesChange: { + type: 'JSFunction', + value: 'function(){this.onValuesChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + children: [ + { + componentName: 'Form.Item', + id: 'node_ockoco6icv1ui', + props: { + label: '设备类型选择', + labelAlign: 'left', + colon: false, + required: true, + style: { + width: '600px', + }, + name: 'projectModal', + requiredobj: { + required: true, + message: '请选择设备类型', + }, + }, + children: [ + { + componentName: 'Select', + id: 'node_ockoco6icv1uj', + props: { + style: { + width: '600px', + }, + options: { + type: 'JSExpression', + value: 'this.state.projectModalsArray', + }, + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + placeholder: '请选择设备类型', + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockpmbs0bv17', + props: { + label: '屏幕分辨率宽', + style: { + width: '600px', + }, + name: 'displayWidth', + colon: false, + required: true, + requiredobj: { + required: true, + message: '请输入屏幕分辨率宽', + }, + labelAlign: 'left', + }, + children: [ + { + componentName: 'InputNumber', + id: 'node_ockpmbs0bv18', + props: { + value: 3, + style: { + width: '600px', + }, + placeholder: '例如1280', + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + min: 0, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockpmbs0bv10', + props: { + label: '屏幕分辨率高', + style: { + width: '600px', + }, + labelAlign: 'left', + colon: false, + name: 'displayHeight', + required: true, + requiredobj: { + required: true, + message: '请输入屏幕分辨率高', + }, + }, + children: [ + { + componentName: 'InputNumber', + id: 'node_ockpmbs0bv11', + props: { + value: 3, + style: { + width: '600px', + }, + placeholder: '例如720', + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + min: 0, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockpmbs0bvt', + props: { + label: '屏幕尺寸(inch)', + style: { + width: '600px', + }, + name: 'displayInch', + labelAlign: 'left', + required: true, + colon: false, + requiredobj: { + required: true, + message: '请输入屏幕尺寸', + }, + }, + children: [ + { + componentName: 'InputNumber', + id: 'node_ockpmbs0bvu', + props: { + value: 3, + style: { + width: '600px', + }, + placeholder: '请输入尺寸', + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + min: 0, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockpmbs0bvm', + props: { + label: '屏幕DPI', + style: { + width: '600px', + }, + labelAlign: 'left', + colon: false, + required: false, + name: 'displayDpi', + }, + children: [ + { + componentName: 'InputNumber', + id: 'node_ockpmbs0bvn', + props: { + value: 3, + style: { + width: '600px', + }, + placeholder: 'UI定制项目必填', + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + min: 0, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockoco6icv1v3', + props: { + label: '芯片名称', + colon: false, + required: true, + style: { + display: 'flex', + }, + labelAlign: 'left', + extra: '', + name: 'mainSoc', + requiredobj: { + required: true, + message: '请输入芯片名称', + }, + lenobj: { + max: 50, + message: '芯片名称不能超过50个字符', + }, + }, + children: [ + { + componentName: 'Input', + id: 'node_ockoco6icv1v4', + props: { + placeholder: '请输入芯片名称', + style: { + width: '600px', + }, + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockpmbs0bvf', + props: { + label: '芯片核数', + style: { + width: '600px', + }, + required: true, + requiredobj: { + required: true, + message: '请输入芯片核数', + }, + name: 'cpuCoreNum', + labelAlign: 'left', + colon: false, + }, + children: [ + { + componentName: 'InputNumber', + id: 'node_ockpmbs0bvg', + props: { + value: 3, + style: { + width: '600px', + }, + placeholder: '请输入芯片核数', + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + defaultValue: '', + min: 0, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockpxba11aa', + props: { + label: '指令集', + style: { + width: '600px', + }, + required: true, + requiredobj: { + required: true, + message: '请选择指令集', + }, + name: 'instructions', + colon: false, + }, + children: [ + { + componentName: 'Select', + id: 'node_ockpxba11ab', + props: { + style: { + width: '600px', + }, + options: { + type: 'JSExpression', + value: 'this.state.instructionsArray', + }, + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockodz1kiqh', + props: { + label: '系统版本', + labelAlign: 'left', + colon: false, + required: true, + style: { + width: '600px', + }, + name: 'osVersion', + requiredobj: { + required: true, + message: '请选择系统版本', + }, + }, + children: [ + { + componentName: 'Select', + id: 'node_ockodz1kiqi', + props: { + style: { + width: '600px', + }, + options: { + type: 'JSExpression', + value: 'this.state.osVersionsArray', + }, + disabled: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.id > 0 && ! this.state.isModifyStatus', + }, + placeholder: '请选择系统版本', + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockoco6icv1uq', + props: { + wrapperCol: { + offset: '', + }, + style: { + flexDirection: 'row', + width: '600px', + display: 'flex', + }, + }, + children: [ + { + componentName: 'Button', + id: 'node_ockoco6icv1ur', + props: { + style: { + marginLeft: '0', + }, + children: '返回', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onClickSecondBack', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.onClickSecondBack.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + { + componentName: 'Button', + id: 'node_ockoco6icv1vb', + props: { + type: 'primary', + children: { + type: 'JSExpression', + value: 'this.state.secondCommitText', + }, + htmlType: 'submit', + style: { + float: 'right', + marginLeft: '20px', + }, + loading: { + type: 'JSExpression', + value: 'this.state.LOADING_ADD_OR_UPDATE_CUSTOMER_PROJECT', + }, + }, + }, + { + componentName: 'Button', + id: 'node_ockoco6icv1us', + props: { + type: 'primary', + children: '上一步', + htmlType: 'submit', + style: { + marginLeft: '0px', + float: 'right', + }, + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onClickPreSecond', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.onClickPreSecond.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + ], + }, + ], + }, + { + componentName: 'NextP', + id: 'node_ockodngwu9m', + props: { + wrap: false, + type: 'body2', + verAlign: 'middle', + textSpacing: true, + align: 'left', + full: true, + flex: true, + style: { + display: 'flex', + justifyContent: 'center', + }, + }, + title: '段落', + condition: { + type: 'JSExpression', + value: 'this.state.currentStep === 2', + }, + children: [ + { + componentName: 'Form', + id: 'node_ockodngwu9n', + props: { + labelCol: { + span: 10, + }, + wrapperCol: { + span: 10, + }, + onFinishFailed: { + type: 'JSFunction', + value: 'function(){this.onFinishFailed.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + name: 'basic', + style: { + display: 'flex', + flexDirection: 'column', + width: '600px', + justifyContent: 'center', + }, + layout: 'vertical', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onFinishFailed', + relatedEventName: 'onFinishFailed', + }, + ], + eventList: [ + { + name: 'onFinish', + disabled: false, + }, + { + name: 'onFinishFailed', + disabled: true, + }, + { + name: 'onFieldsChange', + disabled: false, + }, + { + name: 'onValuesChange', + disabled: false, + }, + ], + }, + }, + children: [ + { + componentName: 'Form.Item', + id: 'node_ockodngwu91m', + props: { + label: '', + }, + children: [ + { + componentName: 'Steps', + id: 'node_ockodngwu91n', + props: { + current: 1, + style: { + width: '600px', + display: 'flex', + justifyContent: 'space-around', + alignItems: 'center', + height: '300px', + }, + labelPlacement: 'horizontal', + direction: 'vertical', + }, + children: [ + { + componentName: 'Steps.Step', + id: 'node_ockodngwu91o', + props: { + title: '提交完成', + description: '', + style: { + width: '200px', + }, + }, + }, + { + componentName: 'Steps.Step', + id: 'node_ockodngwu91p', + props: { + title: { + type: 'JSExpression', + value: 'this.state.thirdAuditText', + }, + subTitle: '', + description: '', + style: { + width: '200px', + }, + }, + }, + ], + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ockodngwu914', + props: { + wrapperCol: { + offset: '', + }, + style: { + flexDirection: 'row', + width: '600px', + display: 'flex', + }, + }, + children: [ + { + componentName: 'Button', + id: 'node_ockodngwu915', + props: { + style: { + marginLeft: '0', + }, + children: '返回', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onClickThirdBack', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.onClickThirdBack.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + { + componentName: 'Button', + id: 'node_ockodngwu916', + props: { + type: 'primary', + children: { + type: 'JSExpression', + value: 'this.state.thirdButtonText', + }, + htmlType: 'submit', + style: { + float: 'right', + marginLeft: '20px', + }, + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onClickModifyThird', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.onClickModifyThird.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + { + componentName: 'Button', + id: 'node_ockosjrkvr1d', + props: { + type: 'primary', + children: '上一步', + htmlType: 'submit', + style: { + marginLeft: '0px', + float: 'right', + }, + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onClickPreThird', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.onClickPreThird.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + condition: { + type: 'JSExpression', + value: 'this.state.customerProjectInfo.status > 2', + }, + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + i18n: {}, +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/.browserslistrc b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/.browserslistrc new file mode 100644 index 0000000000..55a130413d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/.browserslistrc @@ -0,0 +1,3 @@ +defaults +ios_saf 9 + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/.gitignore b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/.gitignore new file mode 100644 index 0000000000..4ec178818e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/.gitignore @@ -0,0 +1,25 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/README.md b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/README.md new file mode 100644 index 0000000000..6d9dd75215 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/README.md @@ -0,0 +1 @@ +This project is generated by lowcode-code-generator & lowcode-solution-icejs3. \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/ice.config.mts new file mode 100644 index 0000000000..fe77c9b6cd --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/ice.config.mts @@ -0,0 +1,90 @@ +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + }, + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = ` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + `; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion({ + importStyle: true, + }), + locales(), + plugin(), + ], +})); + diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/package.json new file mode 100644 index 0000000000..45c8e304a9 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/package.json @@ -0,0 +1,44 @@ +{ + "name": "icejs3-demo-app", + "version": "0.1.5", + "description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。", + "dependencies": { + "moment": "^2.24.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router": "^6.9.0", + "react-router-dom": "^6.9.0", + "intl-messageformat": "^9.3.6", + "@alifd/next": "1.26.15", + "@ice/runtime": "^1.0.0", + "@alilc/lowcode-datasource-engine": "^1.0.0", + "@alilc/lowcode-datasource-http-handler": "^1.0.0", + "@alilc/lowcode-components": "^1.0.0" + }, + "devDependencies": { + "@ice/app": "^3.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/node": "^18.11.17", + "@ice/plugin-fusion": "^1.0.1", + "@ice/plugin-moment-locales": "^1.0.0", + "eslint": "^6.0.1", + "stylelint": "^13.2.0" + }, + "scripts": { + "start": "ice start", + "build": "ice build", + "lint": "npm run eslint && npm run stylelint", + "eslint": "eslint --cache --ext .js,.jsx ./", + "stylelint": "stylelint ./**/*.scss" + }, + "engines": { + "node": ">=14.0.0" + }, + "repository": { + "type": "git", + "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" + }, + "private": true, + "originTemplate": "@alifd/scaffold-lite-js" +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/app.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/app.ts new file mode 100644 index 0000000000..6d5856292d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/app.ts @@ -0,0 +1,13 @@ +import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +})); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/constants.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/constants.js new file mode 100644 index 0000000000..ea766c9da3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/constants.js @@ -0,0 +1,3 @@ +const __$$constants = {}; + +export default __$$constants; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/document.tsx new file mode 100644 index 0000000000..286be9f8ca --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/document.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/global.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/global.scss new file mode 100644 index 0000000000..82ca3eac73 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/global.scss @@ -0,0 +1,6 @@ +// 引入默认全局样式 +@import '@alifd/next/reset.scss'; + +body { + -webkit-font-smoothing: antialiased; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/i18n.js new file mode 100644 index 0000000000..adbbe673dc --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/i18n.js @@ -0,0 +1,77 @@ +const i18nConfig = {}; + +let locale = + typeof navigator === 'object' && typeof navigator.language === 'string' + ? navigator.language + : 'zh-CN'; + +const getLocale = () => locale; + +const setLocale = (target) => { + locale = target; +}; + +const isEmptyVariables = (variables) => + (Array.isArray(variables) && variables.length === 0) || + (typeof variables === 'object' && + (!variables || Object.keys(variables).length === 0)); + +// 按低代码规范里面的要求进行变量替换 +const format = (msg, variables) => + typeof msg === 'string' + ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + : msg; + +const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { + const msg = + i18nConfig[locale]?.[id] ?? + i18nConfig[locale.replace('-', '_')]?.[id] ?? + defaultMessage; + if (msg == null) { + console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); + return fallback === undefined ? `${id}` : fallback; + } + + return format(msg, variables); +}; + +const i18n = (id, params) => { + return i18nFormat({ id }, params); +}; + +// 将国际化的一些方法注入到目标对象&上下文中 +const _inject2 = (target) => { + target.i18n = i18n; + target.getLocale = getLocale; + target.setLocale = (locale) => { + setLocale(locale); + target.forceUpdate(); + }; + target._i18nText = (t) => { + // 优先取直接传过来的语料 + const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]; + if (localMsg != null) { + return format(localMsg, t.params); + } + + // 其次用项目级别的 + const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params); + if (projectMsg != null) { + return projectMsg; + } + + // 兜底用 use 指定的或默认语言的 + return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params); + }; + + // 注入到上下文中去 + if (target._context && target._context !== target) { + Object.assign(target._context, { + i18n, + getLocale, + setLocale: target.setLocale, + }); + } +}; + +export { getLocale, setLocale, i18n, i18nFormat, _inject2 }; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx new file mode 100644 index 0000000000..cc70d53bea --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx @@ -0,0 +1,14 @@ + +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss new file mode 100644 index 0000000000..81e77fda5f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss @@ -0,0 +1,15 @@ + +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx new file mode 100644 index 0000000000..265bfdaa07 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss new file mode 100644 index 0000000000..1ab56d3945 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -0,0 +1,20 @@ + +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx new file mode 100644 index 0000000000..911998b0d3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/index.jsx new file mode 100644 index 0000000000..18db44df5e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/index.jsx @@ -0,0 +1,81 @@ + +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/menuConfig.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/menuConfig.js new file mode 100644 index 0000000000..5332202be4 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/menuConfig.js @@ -0,0 +1,11 @@ + +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.css b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.jsx new file mode 100644 index 0000000000..9a661ad753 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/Example/index.jsx @@ -0,0 +1,116 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:react 框架的导出名和各种组件名除外。 +import React from 'react'; + +import { Page, Table } from '@alilc/lowcode-components'; + +import { createHttpHandler as __$$createHttpRequestHandler } from '@alilc/lowcode-datasource-http-handler'; + +import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime'; + +import utils from '../../utils'; + +import * as __$$i18n from '../../i18n'; + +import __$$constants from '../../constants'; + +import './index.css'; + +class Example$$Page extends React.Component { + _context = this; + + _dataSourceConfig = this._defineDataSourceConfig(); + _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, { + runtimeConfig: true, + requestHandlersMap: { http: __$$createHttpRequestHandler() }, + }); + + get dataSourceMap() { + return this._dataSourceEngine.dataSourceMap || {}; + } + + reloadDataSource = async () => { + await this._dataSourceEngine.reloadDataSource(); + }; + + get constants() { + return __$$constants || {}; + } + + constructor(props, context) { + super(props); + + this.utils = utils; + + __$$i18n._inject2(this); + + this.state = {}; + } + + $ = () => null; + + $$ = () => []; + + _defineDataSourceConfig() { + const _this = this; + return { + list: [ + { + id: 'userList', + type: 'http', + description: '用户列表', + options: function () { + return { + uri: 'https://api.example.com/user/list', + }; + }.bind(_this), + isInit: function () { + return undefined; + }.bind(_this), + }, + ], + }; + } + + componentDidMount() { + this._dataSourceEngine.reloadDataSource(); + } + + render() { + const __$$context = this._context || this; + const { state } = __$$context; + return ( + <div> + <Table + dataSource={__$$eval(() => this.dataSourceMap['userList'])} + columns={[ + { dataIndex: 'name', title: '姓名' }, + { dataIndex: 'age', title: '年龄' }, + ]} + /> + </div> + ); + } +} + +export default Example$$Page; + +function __$$eval(expr) { + try { + return expr(); + } catch (error) {} +} + +function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; +} + +function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/layout.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/layout.jsx new file mode 100644 index 0000000000..50fbb2d1f1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/pages/layout.jsx @@ -0,0 +1,10 @@ +import { Outlet } from 'ice'; +import BasicLayout from '@/layouts/BasicLayout'; + +export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + ); +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/typings.d.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/typings.d.ts new file mode 100644 index 0000000000..a9f8de7ceb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/typings.d.ts @@ -0,0 +1,9 @@ +/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/utils.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/utils.js new file mode 100644 index 0000000000..1190717924 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/utils.js @@ -0,0 +1,47 @@ +import { createRef } from 'react'; + +export class RefsManager { + constructor() { + this.refInsStore = {}; + } + + clearNullRefs() { + Object.keys(this.refInsStore).forEach((refName) => { + const filteredInsList = this.refInsStore[refName].filter( + (insRef) => !!insRef.current + ); + if (filteredInsList.length > 0) { + this.refInsStore[refName] = filteredInsList; + } else { + delete this.refInsStore[refName]; + } + }); + } + + get(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName][0].current; + } + + return null; + } + + getAll(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName].map((i) => i.current); + } + + return []; + } + + linkRef(refName) { + const refIns = createRef(); + this.refInsStore[refName] = this.refInsStore[refName] || []; + this.refInsStore[refName].push(refIns); + return refIns; + } +} + +export default {}; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/schema.json5 new file mode 100644 index 0000000000..1e61996cf5 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/schema.json5 @@ -0,0 +1,65 @@ +{ + version: '1.0.0', + componentsMap: [ + { + package: '@alilc/lowcode-components', + version: '^1.0.0', + componentName: 'Page', + destructuring: true, + exportName: 'Page', + }, + { + package: '@alilc/lowcode-components', + version: '^1.0.0', + componentName: 'Table', + destructuring: true, + exportName: 'Table', + }, + ], + componentsTree: [ + { + componentName: 'Page', + id: 'node_ockp6ci0hm1', + props: {}, + fileName: 'example', + dataSource: { + list: [ + { + id: 'userList', + type: 'http', + description: '用户列表', + options: { + uri: 'https://api.example.com/user/list', + }, + }, + ], + }, + children: [ + { + componentName: 'Table', + id: 'node_ockp6ci0hm22', + props: { + dataSource: { + type: 'DataSource', + id: 'userList', + }, + columns: [ + { + dataIndex: 'name', + title: '姓名', + }, + { + dataIndex: 'age', + title: '年龄', + }, + ], + }, + }, + ], + }, + ], + meta: { + name: 'example', + description: 'Example', + }, +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/.browserslistrc b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/.browserslistrc new file mode 100644 index 0000000000..55a130413d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/.browserslistrc @@ -0,0 +1,3 @@ +defaults +ios_saf 9 + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/.gitignore b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/.gitignore new file mode 100644 index 0000000000..4ec178818e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/.gitignore @@ -0,0 +1,25 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/README.md b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/README.md new file mode 100644 index 0000000000..6d9dd75215 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/README.md @@ -0,0 +1 @@ +This project is generated by lowcode-code-generator & lowcode-solution-icejs3. \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/ice.config.mts new file mode 100644 index 0000000000..fe77c9b6cd --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/ice.config.mts @@ -0,0 +1,90 @@ +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + }, + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = ` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + `; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion({ + importStyle: true, + }), + locales(), + plugin(), + ], +})); + diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/package.json new file mode 100644 index 0000000000..87ad385141 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/package.json @@ -0,0 +1,43 @@ +{ + "name": "icejs3-demo-app", + "version": "0.1.5", + "description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。", + "dependencies": { + "moment": "^2.24.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router": "^6.9.0", + "react-router-dom": "^6.9.0", + "intl-messageformat": "^9.3.6", + "@alifd/next": "1.19.18", + "@ice/runtime": "^1.0.0", + "@alilc/lowcode-datasource-engine": "^1.0.0", + "@alilc/lowcode-datasource-jsonp-handler": "^1.0.0" + }, + "devDependencies": { + "@ice/app": "^3.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/node": "^18.11.17", + "@ice/plugin-fusion": "^1.0.1", + "@ice/plugin-moment-locales": "^1.0.0", + "eslint": "^6.0.1", + "stylelint": "^13.2.0" + }, + "scripts": { + "start": "ice start", + "build": "ice build", + "lint": "npm run eslint && npm run stylelint", + "eslint": "eslint --cache --ext .js,.jsx ./", + "stylelint": "stylelint ./**/*.scss" + }, + "engines": { + "node": ">=14.0.0" + }, + "repository": { + "type": "git", + "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" + }, + "private": true, + "originTemplate": "@alifd/scaffold-lite-js" +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/app.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/app.ts new file mode 100644 index 0000000000..6d5856292d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/app.ts @@ -0,0 +1,13 @@ +import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +})); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/constants.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/constants.js new file mode 100644 index 0000000000..ea766c9da3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/constants.js @@ -0,0 +1,3 @@ +const __$$constants = {}; + +export default __$$constants; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/document.tsx new file mode 100644 index 0000000000..286be9f8ca --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/document.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/global.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/global.scss new file mode 100644 index 0000000000..82ca3eac73 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/global.scss @@ -0,0 +1,6 @@ +// 引入默认全局样式 +@import '@alifd/next/reset.scss'; + +body { + -webkit-font-smoothing: antialiased; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/i18n.js new file mode 100644 index 0000000000..adbbe673dc --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/i18n.js @@ -0,0 +1,77 @@ +const i18nConfig = {}; + +let locale = + typeof navigator === 'object' && typeof navigator.language === 'string' + ? navigator.language + : 'zh-CN'; + +const getLocale = () => locale; + +const setLocale = (target) => { + locale = target; +}; + +const isEmptyVariables = (variables) => + (Array.isArray(variables) && variables.length === 0) || + (typeof variables === 'object' && + (!variables || Object.keys(variables).length === 0)); + +// 按低代码规范里面的要求进行变量替换 +const format = (msg, variables) => + typeof msg === 'string' + ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + : msg; + +const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { + const msg = + i18nConfig[locale]?.[id] ?? + i18nConfig[locale.replace('-', '_')]?.[id] ?? + defaultMessage; + if (msg == null) { + console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); + return fallback === undefined ? `${id}` : fallback; + } + + return format(msg, variables); +}; + +const i18n = (id, params) => { + return i18nFormat({ id }, params); +}; + +// 将国际化的一些方法注入到目标对象&上下文中 +const _inject2 = (target) => { + target.i18n = i18n; + target.getLocale = getLocale; + target.setLocale = (locale) => { + setLocale(locale); + target.forceUpdate(); + }; + target._i18nText = (t) => { + // 优先取直接传过来的语料 + const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]; + if (localMsg != null) { + return format(localMsg, t.params); + } + + // 其次用项目级别的 + const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params); + if (projectMsg != null) { + return projectMsg; + } + + // 兜底用 use 指定的或默认语言的 + return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params); + }; + + // 注入到上下文中去 + if (target._context && target._context !== target) { + Object.assign(target._context, { + i18n, + getLocale, + setLocale: target.setLocale, + }); + } +}; + +export { getLocale, setLocale, i18n, i18nFormat, _inject2 }; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx new file mode 100644 index 0000000000..cc70d53bea --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx @@ -0,0 +1,14 @@ + +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss new file mode 100644 index 0000000000..81e77fda5f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss @@ -0,0 +1,15 @@ + +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx new file mode 100644 index 0000000000..265bfdaa07 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss new file mode 100644 index 0000000000..1ab56d3945 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -0,0 +1,20 @@ + +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx new file mode 100644 index 0000000000..911998b0d3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/index.jsx new file mode 100644 index 0000000000..18db44df5e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/index.jsx @@ -0,0 +1,81 @@ + +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/menuConfig.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/menuConfig.js new file mode 100644 index 0000000000..5332202be4 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/menuConfig.js @@ -0,0 +1,11 @@ + +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.css b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx new file mode 100644 index 0000000000..1f2bf90418 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx @@ -0,0 +1,123 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:react 框架的导出名和各种组件名除外。 +import React from 'react'; + +import { Switch } from '@alifd/next'; + +import { createJsonpHandler as __$$createJsonpRequestHandler } from '@alilc/lowcode-datasource-jsonp-handler'; + +import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime'; + +import utils from '../../utils'; + +import * as __$$i18n from '../../i18n'; + +import __$$constants from '../../constants'; + +import './index.css'; + +class $$Page extends React.Component { + _context = this; + + _dataSourceConfig = this._defineDataSourceConfig(); + _dataSourceEngine = __$$createDataSourceEngine(this._dataSourceConfig, this, { + runtimeConfig: true, + requestHandlersMap: { jsonp: __$$createJsonpRequestHandler() }, + }); + + get dataSourceMap() { + return this._dataSourceEngine.dataSourceMap || {}; + } + + reloadDataSource = async () => { + await this._dataSourceEngine.reloadDataSource(); + }; + + get constants() { + return __$$constants || {}; + } + + constructor(props, context) { + super(props); + + this.utils = utils; + + __$$i18n._inject2(this); + + this.state = {}; + } + + $ = () => null; + + $$ = () => []; + + _defineDataSourceConfig() { + const _this = this; + return { + list: [ + { + id: 'todos', + isInit: function () { + return true; + }.bind(_this), + type: 'jsonp', + options: function () { + return { + method: 'GET', + uri: 'https://a0ee9135-6a7f-4c0f-a215-f0f247ad907d.mock.pstmn.io', + }; + }.bind(_this), + dataHandler: function dataHandler(data) { + return data.data; + }, + }, + ], + }; + } + + componentDidMount() { + this._dataSourceEngine.reloadDataSource(); + } + + render() { + const __$$context = this._context || this; + const { state } = __$$context; + return ( + <div> + {__$$evalArray(() => this.dataSourceMap.todos.data).map((item, index) => + ((__$$context) => ( + <div> + <Switch + checkedChildren="开" + unCheckedChildren="关" + checked={__$$eval(() => item.done)} + /> + </div> + ))(__$$createChildContext(__$$context, { item, index })) + )} + </div> + ); + } +} + +export default $$Page; + +function __$$eval(expr) { + try { + return expr(); + } catch (error) {} +} + +function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; +} + +function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/layout.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/layout.jsx new file mode 100644 index 0000000000..50fbb2d1f1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/layout.jsx @@ -0,0 +1,10 @@ +import { Outlet } from 'ice'; +import BasicLayout from '@/layouts/BasicLayout'; + +export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + ); +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/typings.d.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/typings.d.ts new file mode 100644 index 0000000000..a9f8de7ceb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/typings.d.ts @@ -0,0 +1,9 @@ +/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/utils.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/utils.js new file mode 100644 index 0000000000..1190717924 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/utils.js @@ -0,0 +1,47 @@ +import { createRef } from 'react'; + +export class RefsManager { + constructor() { + this.refInsStore = {}; + } + + clearNullRefs() { + Object.keys(this.refInsStore).forEach((refName) => { + const filteredInsList = this.refInsStore[refName].filter( + (insRef) => !!insRef.current + ); + if (filteredInsList.length > 0) { + this.refInsStore[refName] = filteredInsList; + } else { + delete this.refInsStore[refName]; + } + }); + } + + get(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName][0].current; + } + + return null; + } + + getAll(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName].map((i) => i.current); + } + + return []; + } + + linkRef(refName) { + const refIns = createRef(); + this.refInsStore[refName] = this.refInsStore[refName] || []; + this.refInsStore[refName].push(refIns); + return refIns; + } +} + +export default {}; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/schema.json5 new file mode 100644 index 0000000000..f91f132ad2 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/schema.json5 @@ -0,0 +1,59 @@ +{ + version: '1.0.0', + componentsMap: [ + { + componentName: 'Switch', + package: '@alifd/next', + version: '1.19.18', + exportName: 'Switch', + destructuring: true, + subName: '', + }, + ], + componentsTree: [ + { + componentName: 'Page', + props: {}, + children: [ + { + componentName: 'Div', + props: {}, + children: [ + { + componentName: 'Switch', + props: { + checkedChildren: '开', + unCheckedChildren: '关', + checked: { + type: 'JSExpression', + value: 'this.item.done', + }, + }, + }, + ], + loop: { + type: 'JSExpression', + value: 'this.dataSourceMap.todos.data', + }, + }, + ], + dataSource: { + list: [ + { + id: 'todos', + isInit: true, + type: 'jsonp', + options: { + method: 'GET', + uri: 'https://a0ee9135-6a7f-4c0f-a215-f0f247ad907d.mock.pstmn.io', + }, + dataHandler: { + type: 'JSFunction', + value: 'function dataHandler(data) {return data.data;}', + }, + }, + ], + }, + }, + ], +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/.browserslistrc b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/.browserslistrc new file mode 100644 index 0000000000..55a130413d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/.browserslistrc @@ -0,0 +1,3 @@ +defaults +ios_saf 9 + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/.gitignore b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/.gitignore new file mode 100644 index 0000000000..4ec178818e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/.gitignore @@ -0,0 +1,25 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/README.md b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/README.md new file mode 100644 index 0000000000..6d9dd75215 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/README.md @@ -0,0 +1 @@ +This project is generated by lowcode-code-generator & lowcode-solution-icejs3. \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/ice.config.mts new file mode 100644 index 0000000000..fe77c9b6cd --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/ice.config.mts @@ -0,0 +1,90 @@ +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + }, + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = ` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + `; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion({ + importStyle: true, + }), + locales(), + plugin(), + ], +})); + diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/package.json new file mode 100644 index 0000000000..cad3038d99 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/package.json @@ -0,0 +1,46 @@ +{ + "name": "icejs3-demo-app", + "version": "0.1.5", + "description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。", + "dependencies": { + "moment": "^2.24.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router": "^6.9.0", + "react-router-dom": "^6.9.0", + "intl-messageformat": "^9.3.6", + "@alifd/next": "1.26.15", + "@ice/runtime": "^1.0.0", + "@alilc/lowcode-datasource-engine": "^1.0.0", + "undefined": "*", + "@alilc/antd-lowcode-materials": "0.9.4", + "@alife/mc-assets-1935": "0.1.42", + "@alife/container": "0.3.7" + }, + "devDependencies": { + "@ice/app": "^3.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/node": "^18.11.17", + "@ice/plugin-fusion": "^1.0.1", + "@ice/plugin-moment-locales": "^1.0.0", + "eslint": "^6.0.1", + "stylelint": "^13.2.0" + }, + "scripts": { + "start": "ice start", + "build": "ice build", + "lint": "npm run eslint && npm run stylelint", + "eslint": "eslint --cache --ext .js,.jsx ./", + "stylelint": "stylelint ./**/*.scss" + }, + "engines": { + "node": ">=14.0.0" + }, + "repository": { + "type": "git", + "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" + }, + "private": true, + "originTemplate": "@alifd/scaffold-lite-js" +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/app.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/app.ts new file mode 100644 index 0000000000..6d5856292d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/app.ts @@ -0,0 +1,13 @@ +import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +})); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/constants.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/constants.js new file mode 100644 index 0000000000..ea766c9da3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/constants.js @@ -0,0 +1,3 @@ +const __$$constants = {}; + +export default __$$constants; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/document.tsx new file mode 100644 index 0000000000..286be9f8ca --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/document.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/global.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/global.scss new file mode 100644 index 0000000000..82ca3eac73 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/global.scss @@ -0,0 +1,6 @@ +// 引入默认全局样式 +@import '@alifd/next/reset.scss'; + +body { + -webkit-font-smoothing: antialiased; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/i18n.js new file mode 100644 index 0000000000..adbbe673dc --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/i18n.js @@ -0,0 +1,77 @@ +const i18nConfig = {}; + +let locale = + typeof navigator === 'object' && typeof navigator.language === 'string' + ? navigator.language + : 'zh-CN'; + +const getLocale = () => locale; + +const setLocale = (target) => { + locale = target; +}; + +const isEmptyVariables = (variables) => + (Array.isArray(variables) && variables.length === 0) || + (typeof variables === 'object' && + (!variables || Object.keys(variables).length === 0)); + +// 按低代码规范里面的要求进行变量替换 +const format = (msg, variables) => + typeof msg === 'string' + ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + : msg; + +const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { + const msg = + i18nConfig[locale]?.[id] ?? + i18nConfig[locale.replace('-', '_')]?.[id] ?? + defaultMessage; + if (msg == null) { + console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); + return fallback === undefined ? `${id}` : fallback; + } + + return format(msg, variables); +}; + +const i18n = (id, params) => { + return i18nFormat({ id }, params); +}; + +// 将国际化的一些方法注入到目标对象&上下文中 +const _inject2 = (target) => { + target.i18n = i18n; + target.getLocale = getLocale; + target.setLocale = (locale) => { + setLocale(locale); + target.forceUpdate(); + }; + target._i18nText = (t) => { + // 优先取直接传过来的语料 + const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]; + if (localMsg != null) { + return format(localMsg, t.params); + } + + // 其次用项目级别的 + const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params); + if (projectMsg != null) { + return projectMsg; + } + + // 兜底用 use 指定的或默认语言的 + return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params); + }; + + // 注入到上下文中去 + if (target._context && target._context !== target) { + Object.assign(target._context, { + i18n, + getLocale, + setLocale: target.setLocale, + }); + } +}; + +export { getLocale, setLocale, i18n, i18nFormat, _inject2 }; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx new file mode 100644 index 0000000000..cc70d53bea --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx @@ -0,0 +1,14 @@ + +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss new file mode 100644 index 0000000000..81e77fda5f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss @@ -0,0 +1,15 @@ + +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx new file mode 100644 index 0000000000..265bfdaa07 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss new file mode 100644 index 0000000000..1ab56d3945 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -0,0 +1,20 @@ + +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx new file mode 100644 index 0000000000..911998b0d3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/index.jsx new file mode 100644 index 0000000000..18db44df5e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/index.jsx @@ -0,0 +1,81 @@ + +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/menuConfig.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/menuConfig.js new file mode 100644 index 0000000000..5332202be4 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/menuConfig.js @@ -0,0 +1,11 @@ + +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.css b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.css new file mode 100644 index 0000000000..066114aeeb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.css @@ -0,0 +1,8 @@ +body { + font-size: 12px; +} + +.botton { + width: 100px; + color: #ff00ff; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.jsx new file mode 100644 index 0000000000..922ad47ad8 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/Test/index.jsx @@ -0,0 +1,822 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:react 框架的导出名和各种组件名除外。 +import React from 'react'; + +import { + Modal, + Button, + Typography, + Form, + Select, + Input, + ConfigProvider, + Tooltip, + Empty, +} from '@alilc/antd-lowcode-materials/dist/antd-lowcode.esm.js'; + +import { + AliAutoDiv, + AliAutoSearchTable, +} from '@alife/mc-assets-1935/build/lowcode/index.js'; + +import { + Page as NextPage, + Block as NextBlock, + P as NextP, +} from '@alife/container/lib/index.js'; + +import utils, { RefsManager } from '../../utils'; + +import * as __$$i18n from '../../i18n'; + +import __$$constants from '../../constants'; + +import './index.css'; + +const AliAutoDivDefault = AliAutoDiv.default; + +const AliAutoSearchTableDefault = AliAutoSearchTable.default; + +const NextBlockCell = NextBlock.Cell; + +class Test$$Page extends React.Component { + _context = this; + + get constants() { + return __$$constants || {}; + } + + constructor(props, context) { + super(props); + + this.utils = utils; + + this._refsManager = new RefsManager(); + + __$$i18n._inject2(this); + + this.state = { + pkgs: [], + total: 0, + isSearch: false, + projects: [], + results: [], + resultVisible: false, + }; + + this.__jp__init(); + this.statusDesc = { + 0: '失败', + 1: '成功', + 2: '构建中', + 3: '构建超时', + }; + this.pageParams = {}; + } + + $ = (refName) => { + return this._refsManager.get(refName); + }; + + $$ = (refName) => { + return this._refsManager.getAll(refName); + }; + + componentDidUpdate(prevProps, prevState, snapshot) {} + + componentWillUnmount() {} + + __jp__init() { + /*...*/ + } + + __jp__initRouter() { + if (window.arsenal) { + this.$router = new window.jianpin.ArsenalRouter({ + app: this.props.microApp, + }); + } else { + this.$router = new window.jianpin.ArsenalRouter(); + } + } + + __jp__initDataSource() { + /*...*/ + } + + __jp__initEnv() { + /*...*/ + } + + __jp__initConfig() { + /*...*/ + } + + __jp__initUtils() { + this.$utils = { + message: window.jianpin.utils.message, + axios: window.jianpin.utils.axios, + moment: window.jianpin.utils.moment, + }; + } + + fetchPkgs() { + /*...*/ + } + + onPageChange(pageIndex, pageSize) { + this.pageParams = { + pageIndex, + pageSize, + }; + this.fetchPkgs(); + } + + renderTime(time) { + return this.$utils.moment(time).format('YYYY-MM-DD HH:mm'); + } + + renderUserName(user) { + return user.user_name; + } + + reload() { + /*...*/ + } + + handleResult() { + /*...*/ + } + + handleDetail() { + // 跳转详情页面 TODO + } + + onResultCancel() { + this.setState({ + resultVisible: false, + }); + } + + formatResult(item) { + if (!item) { + return '暂无结果'; + } + const { channel, plat, version, status } = item; + return [channel, plat, version, status].join('-'); + } + + handleDownload() { + /*...*/ + } + + onFinish() { + /*...*/ + } + + componentDidMount() { + this.$ds.resolve('PROJECTS', { + params: { + size: 5000, + }, + }); + // if (this.state.init === false) { + // this.setState({ + // init: true, + // }); + // } + } + + render() { + const __$$context = this._context || this; + const { state } = __$$context; + return ( + <div + ref={this._refsManager.linkRef('outterView')} + style={{ height: '100%' }} + > + <Modal + title="查看结果" + visible={__$$eval(() => this.state.resultVisible)} + footer={ + <Button + type="primary" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onResultCancel', + }, + ], + eventList: [{ name: 'onClick', disabled: true }], + }} + onClick={function () { + this.onResultCancel.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + 确定 + </Button> + } + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onCancel', + relatedEventName: 'onResultCancel', + }, + ], + eventList: [ + { name: 'onCancel', disabled: true }, + { name: 'onOk', disabled: false }, + ], + }} + onCancel={function () { + this.onResultCancel.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + width="720px" + centered={true} + > + {__$$evalArray(() => this.state.results).map((item, index) => + ((__$$context) => ( + <AliAutoDivDefault style={{ width: '100%' }}> + {!!__$$eval( + () => + __$$context.state.results && + __$$context.state.results.length > 0 + ) && ( + <AliAutoDivDefault + style={{ + width: '100%', + textAlign: 'left', + marginBottom: '10px', + }} + > + <Button + type="primary" + size="small" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'handleDownload', + }, + ], + eventList: [{ name: 'onClick', disabled: true }], + }} + onClick={function () { + this.handleDownload.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(__$$context)} + > + 下载全部 + </Button> + </AliAutoDivDefault> + )} + <Typography.Text> + {__$$eval(() => __$$context.formatResult(item))} + </Typography.Text> + {!!__$$eval(() => item.download_link) && ( + <Typography.Link + href={__$$eval(() => item.download_link)} + target="_blank" + > + {' '} + - 点击下载 + </Typography.Link> + )} + {!!__$$eval(() => item.release_notes) && ( + <Typography.Link + href={__$$eval(() => item.release_notes)} + target="_blank" + > + {' '} + - 跳转发布节点 + </Typography.Link> + )} + </AliAutoDivDefault> + ))(__$$createChildContext(__$$context, { item, index })) + )} + </Modal> + <NextPage + columns={12} + headerDivider={true} + placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }} + placeholder="页面主体内容:拖拽Block布局组件到这里" + header={null} + headerProps={{ background: 'surface' }} + footer={null} + minHeight="100vh" + > + <NextBlock + prefix="next-" + placeholderStyle={{ height: '100%' }} + noPadding={false} + noBorder={false} + background="surface" + layoutmode="O" + colSpan={12} + rowSpan={1} + childTotalColumns={12} + > + <NextBlockCell + title="" + prefix="next-" + placeholderStyle={{ height: '100%' }} + layoutmode="O" + childTotalColumns={12} + isAutoContainer={true} + colSpan={12} + rowSpan={1} + > + <NextP + wrap={false} + type="body2" + verAlign="middle" + textSpacing={true} + align="left" + full={true} + flex={true} + > + <Form + labelCol={{ span: 10 }} + wrapperCol={{ span: 14 }} + onFinish={function () { + this.onFinish.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + name="basic" + layout="inline" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onFinish', + relatedEventName: 'onFinish', + }, + ], + eventList: [ + { name: 'onFinish', disabled: true }, + { name: 'onFinishFailed', disabled: false }, + { name: 'onFieldsChange', disabled: false }, + { name: 'onValuesChange', disabled: false }, + ], + }} + > + <Form.Item label="项目名称/渠道号" name="channel_id"> + <Select + style={{ width: '280px' }} + options={__$$eval(() => this.state.projects)} + showArrow={true} + tokenSeparators={[]} + showSearch={true} + /> + </Form.Item> + <Form.Item label="版本号" name="buildId"> + <Input + placeholder="请输入" + style={{ width: '280px' }} + size="middle" + /> + </Form.Item> + <Form.Item label="构建人" name="user_id"> + <Select + style={{ width: 200 }} + options={[ + { label: 'A', value: 'A' }, + { label: 'B', value: 'B' }, + { label: 'C', value: 'C' }, + ]} + showSearch={true} + /> + </Form.Item> + <Form.Item label="ID" name="id"> + <Input placeholder="请输入" style={{ width: '160px' }} /> + </Form.Item> + <Form.Item wrapperCol={{ offset: 6 }}> + <Button type="primary" htmlType="submit"> + 查询 + </Button> + </Form.Item> + </Form> + </NextP> + </NextBlockCell> + </NextBlock> + <NextBlock childTotalColumns={12}> + <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}> + <NextP + wrap={false} + type="body2" + verAlign="middle" + textSpacing={true} + align="left" + flex={true} + > + <ConfigProvider locale="zh-CN"> + {!!__$$eval( + () => + !this.state.isSearch || + (this.state.isSearch && this.state.pkgs.length > 0) + ) && ( + <AliAutoSearchTableDefault + rowKey="key" + dataSource={__$$eval(() => this.state.pkgs)} + columns={[ + { + title: 'ID', + dataIndex: 'id', + key: 'name', + width: 80, + }, + { + title: '渠道号', + dataIndex: 'channels', + key: 'age', + width: 142, + render: (text, record, index) => + ((__$$context) => + __$$evalArray(() => text.split(',')).map( + (item, index) => + ((__$$context) => ( + <Typography.Text + style={{ display: 'block' }} + > + {__$$eval(() => item)} + </Typography.Text> + ))( + __$$createChildContext(__$$context, { + item, + index, + }) + ) + ))( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + }, + { + title: '版本号', + dataIndex: 'dic_version', + key: 'address', + render: (text, record, index) => + ((__$$context) => ( + <Tooltip + title={__$$evalArray(() => text || []).map( + (item, index) => + ((__$$context) => ( + <Typography.Text + style={{ + display: 'block', + color: '#FFFFFF', + }} + > + {__$$eval( + () => + item.channelId + + ' / ' + + item.version + )} + </Typography.Text> + ))( + __$$createChildContext(__$$context, { + item, + index, + }) + ) + )} + > + <Typography.Text> + {__$$eval(() => text[0].version)} + </Typography.Text> + </Tooltip> + ))( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + width: 120, + }, + { title: '构建Job', dataIndex: 'job_name', width: 180 }, + { + title: '构建类型', + dataIndex: 'packaging_type', + width: 94, + }, + { + title: '构建状态', + dataIndex: 'status', + render: (text, record, index) => + ((__$$context) => [ + <Typography.Text> + {__$$eval(() => __$$context.statusDesc[text])} + </Typography.Text>, + !!__$$eval(() => text === 2) && ( + <Icon + type="SyncOutlined" + size={16} + spin={true} + style={{ marginLeft: '10px' }} + /> + ), + ])( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + width: 100, + }, + { + title: '构建时间', + dataIndex: 'start_time', + render: function () { + return this.renderTime.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this), + width: 148, + }, + { + title: '构建人', + dataIndex: 'user', + render: function () { + return this.renderUserName.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this), + width: 80, + }, + { + title: 'Jenkins 链接', + dataIndex: 'jenkins_link', + render: (text, record, index) => + ((__$$context) => [ + !!__$$eval(() => text) && ( + <Typography.Link + href={__$$eval(() => text)} + target="_blank" + > + 查看 + </Typography.Link> + ), + !!__$$eval(() => !text) && ( + <Typography.Text>暂无</Typography.Text> + ), + ])( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + width: 120, + }, + { + title: '测试平台链接', + dataIndex: 'is_run_testing', + width: 120, + render: (text, record, index) => + ((__$$context) => [ + !!__$$eval(() => text) && ( + <Typography.Link + href="http://rivermap.alibaba.net/dashboard/testExecute" + target="_blank" + > + 查看 + </Typography.Link> + ), + !!__$$eval(() => !text) && ( + <Typography.Text>暂无</Typography.Text> + ), + ])( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + }, + { title: '触发源', dataIndex: 'source', width: 120 }, + { + title: '详情', + dataIndex: 'id', + render: (text, record, index) => + ((__$$context) => ( + <Button + type="link" + size="small" + style={{ padding: '0px' }} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'handleDetail', + }, + ], + eventList: [ + { name: 'onClick', disabled: true }, + ], + }} + onClick={function () { + this.handleDetail.apply( + this, + Array.prototype.slice + .call(arguments) + .concat([]) + ); + }.bind(__$$context)} + > + 查看 + </Button> + ))( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + width: 80, + fixed: 'right', + }, + { + title: '结果', + dataIndex: 'id', + render: (text, record, index) => + ((__$$context) => ( + <Button + type="link" + size="small" + style={{ padding: '0px' }} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'handleResult', + paramStr: 'this.text', + }, + ], + eventList: [ + { name: 'onClick', disabled: true }, + ], + }} + onClick={function () { + this.handleResult.apply( + this, + Array.prototype.slice + .call(arguments) + .concat([]) + ); + }.bind(__$$context)} + ghost={false} + href={__$$eval(() => text)} + > + 查看 + </Button> + ))( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + width: 80, + fixed: 'right', + }, + { + title: '重新执行', + dataIndex: 'id', + width: 92, + render: (text, record, index) => + ((__$$context) => ( + <Button + type="text" + children="" + icon={ + <Icon + type="ReloadOutlined" + size={14} + color="#0593d3" + style={{ + padding: '3px', + border: '1px solid #0593d3', + borderRadius: '14px', + cursor: 'pointer', + height: '22px', + }} + spin={false} + /> + } + shape="circle" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'reload', + }, + ], + eventList: [ + { name: 'onClick', disabled: true }, + ], + }} + onClick={function () { + this.reload.apply( + this, + Array.prototype.slice + .call(arguments) + .concat([]) + ); + }.bind(__$$context)} + /> + ))( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + fixed: 'right', + }, + ]} + actions={[]} + pagination={{ + total: __$$eval(() => this.state.total), + defaultPageSize: 8, + onPageChange: function () { + return this.onPageChange.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this), + }} + scrollX={1200} + /> + )} + </ConfigProvider> + </NextP> + </NextBlockCell> + </NextBlock> + <NextBlock childTotalColumns={12}> + <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}> + <NextP + wrap={false} + type="body2" + verAlign="middle" + textSpacing={true} + align="left" + flex={true} + > + {!!__$$eval( + () => this.state.pkgs.length < 1 && this.state.isSearch + ) && <Empty description="暂无数据" />} + </NextP> + </NextBlockCell> + </NextBlock> + </NextPage> + </div> + ); + } +} + +export default Test$$Page; + +function __$$eval(expr) { + try { + return expr(); + } catch (error) {} +} + +function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; +} + +function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/layout.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/layout.jsx new file mode 100644 index 0000000000..50fbb2d1f1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/pages/layout.jsx @@ -0,0 +1,10 @@ +import { Outlet } from 'ice'; +import BasicLayout from '@/layouts/BasicLayout'; + +export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + ); +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/typings.d.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/typings.d.ts new file mode 100644 index 0000000000..a9f8de7ceb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/typings.d.ts @@ -0,0 +1,9 @@ +/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/utils.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/utils.js new file mode 100644 index 0000000000..1190717924 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/utils.js @@ -0,0 +1,47 @@ +import { createRef } from 'react'; + +export class RefsManager { + constructor() { + this.refInsStore = {}; + } + + clearNullRefs() { + Object.keys(this.refInsStore).forEach((refName) => { + const filteredInsList = this.refInsStore[refName].filter( + (insRef) => !!insRef.current + ); + if (filteredInsList.length > 0) { + this.refInsStore[refName] = filteredInsList; + } else { + delete this.refInsStore[refName]; + } + }); + } + + get(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName][0].current; + } + + return null; + } + + getAll(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName].map((i) => i.current); + } + + return []; + } + + linkRef(refName) { + const refIns = createRef(); + this.refInsStore[refName] = this.refInsStore[refName] || []; + this.refInsStore[refName].push(refIns); + return refIns; + } +} + +export default {}; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/schema.json5 new file mode 100644 index 0000000000..a499dfc650 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/schema.json5 @@ -0,0 +1,1206 @@ +{ + version: '1.0.0', + componentsMap: [ + { + devMode: 'lowcode', + componentName: 'Slot', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.9.4', + exportName: 'Button', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Button', + }, + { + package: '@alife/mc-assets-1935', + version: '0.1.42', + exportName: 'AliAutoDiv', + main: 'build/lowcode/index.js', + destructuring: true, + subName: 'default', + componentName: 'AliAutoDivDefault', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.9.4', + exportName: 'Typography', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + subName: 'Text', + componentName: 'Typography.Text', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.9.4', + exportName: 'Typography', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + subName: 'Link', + componentName: 'Typography.Link', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.9.4', + exportName: 'Modal', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Modal', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.9.4', + exportName: 'Select', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Select', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.9.4', + exportName: 'Form', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + subName: 'Item', + componentName: 'Form.Item', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.9.4', + exportName: 'Input', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Input', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.9.4', + exportName: 'Form', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Form', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'P', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextP', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Block', + main: 'lib/index.js', + destructuring: true, + subName: 'Cell', + componentName: 'NextBlockCell', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Block', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextBlock', + }, + { + package: '@alife/mc-assets-1935', + version: '0.1.42', + exportName: 'AliAutoSearchTable', + main: 'build/lowcode/index.js', + destructuring: true, + subName: 'default', + componentName: 'AliAutoSearchTableDefault', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.9.4', + exportName: 'ConfigProvider', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'ConfigProvider', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.9.4', + exportName: 'Empty', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Empty', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Page', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextPage', + }, + { + devMode: 'lowcode', + componentName: 'Page', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.9.4', + exportName: 'Tooltip', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Tooltip', + }, + ], + componentsTree: [ + { + componentName: 'Page', + id: 'node_dockcviv8fo1', + props: { + ref: 'outterView', + style: { + height: '100%', + }, + }, + fileName: 'test', + dataSource: { + list: [], + }, + css: 'body {\n font-size: 12px;\n}\n\n.botton {\n width: 100px;\n color: #ff00ff\n}', + lifeCycles: { + constructor: { + type: 'JSFunction', + value: "function() {\n this.__jp__init();\n this.statusDesc = {\n 0: '失败',\n 1: '成功',\n 2: '构建中',\n 3: '构建超时',\n };\n this.pageParams = {};\n }", + }, + componentDidMount: { + type: 'JSFunction', + value: "function() {\n this.$ds.resolve('PROJECTS', {\n params: {\n size: 5000,\n },\n });\n // if (this.state.init === false) {\n // this.setState({\n // init: true,\n // });\n // }\n }", + }, + componentDidUpdate: { + type: 'JSFunction', + value: 'function(prevProps, prevState, snapshot) {}', + }, + componentWillUnmount: { + type: 'JSFunction', + value: 'function() {}', + }, + }, + methods: { + __jp__init: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + __jp__initRouter: { + type: 'JSFunction', + value: 'function() {\n if (window.arsenal) {\n this.$router = new window.jianpin.ArsenalRouter({\n app: this.props.microApp,\n });\n } else {\n this.$router = new window.jianpin.ArsenalRouter();\n }\n}', + }, + __jp__initDataSource: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + __jp__initEnv: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + __jp__initConfig: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + __jp__initUtils: { + type: 'JSFunction', + value: 'function() {\n this.$utils = {\n message: window.jianpin.utils.message,\n axios: window.jianpin.utils.axios,\n moment: window.jianpin.utils.moment,\n };\n}', + }, + fetchPkgs: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + onPageChange: { + type: 'JSFunction', + value: 'function(pageIndex, pageSize) {\n this.pageParams = {\n pageIndex,\n pageSize,\n };\n this.fetchPkgs();\n }', + }, + renderTime: { + type: 'JSFunction', + value: "function(time) {\n return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\n }", + }, + renderUserName: { + type: 'JSFunction', + value: 'function(user) {\n return user.user_name;\n }', + }, + reload: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + handleResult: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + handleDetail: { + type: 'JSFunction', + value: 'function() {\n // 跳转详情页面 TODO\n }', + }, + onResultCancel: { + type: 'JSFunction', + value: 'function() {\n this.setState({\n resultVisible: false,\n });\n }', + }, + formatResult: { + type: 'JSFunction', + value: "function(item) {\n if (!item) {\n return '暂无结果';\n }\n const { channel, plat, version, status } = item;\n return [channel, plat, version, status].join('-');\n }", + }, + handleDownload: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + onFinish: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + }, + state: { + pkgs: [], + total: 0, + isSearch: false, + projects: [], + results: [], + resultVisible: false, + }, + children: [ + { + componentName: 'Modal', + id: 'node_ocksh9yppxb', + props: { + title: '查看结果', + visible: { + type: 'JSExpression', + value: 'this.state.resultVisible', + }, + footer: { + type: 'JSSlot', + value: [ + { + componentName: 'Button', + id: 'node_ocksh9yppxf', + props: { + type: 'primary', + children: '确定', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onResultCancel', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onCancel', + relatedEventName: 'onResultCancel', + }, + ], + eventList: [ + { + name: 'onCancel', + disabled: true, + }, + { + name: 'onOk', + disabled: false, + }, + ], + }, + onCancel: { + type: 'JSFunction', + value: 'function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + width: '720px', + centered: true, + }, + hidden: true, + children: [ + { + componentName: 'AliAutoDivDefault', + id: 'node_ockshazuxa4', + props: { + style: { + width: '100%', + }, + }, + loop: { + type: 'JSExpression', + value: 'this.state.results', + }, + children: [ + { + componentName: 'AliAutoDivDefault', + id: 'node_ockshazuxai', + props: { + style: { + width: '100%', + textAlign: 'left', + marginBottom: '10px', + }, + }, + condition: { + type: 'JSExpression', + value: 'this.state.results && this.state.results.length > 0', + }, + children: [ + { + componentName: 'Button', + id: 'node_ockshazuxah', + props: { + type: 'primary', + children: '下载全部', + size: 'small', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'handleDownload', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.handleDownload.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + { + componentName: 'Typography.Text', + id: 'node_ockshazuxa5', + props: { + children: { + type: 'JSExpression', + value: 'this.formatResult(this.item)', + }, + }, + }, + { + componentName: 'Typography.Link', + id: 'node_ockshazuxa6', + props: { + href: { + type: 'JSExpression', + value: 'this.item.download_link', + }, + target: '_blank', + children: ' - 点击下载', + }, + condition: { + type: 'JSExpression', + value: 'this.item.download_link', + }, + }, + { + componentName: 'Typography.Link', + id: 'node_ockshazuxa7', + props: { + href: { + type: 'JSExpression', + value: 'this.item.release_notes', + }, + target: '_blank', + children: ' - 跳转发布节点', + }, + condition: { + type: 'JSExpression', + value: 'this.item.release_notes', + }, + }, + ], + }, + ], + }, + { + componentName: 'NextPage', + id: 'node_ocko19zplh1', + props: { + columns: 12, + headerDivider: true, + placeholderStyle: { + gridRowEnd: 'span 1', + gridColumnEnd: 'span 12', + }, + placeholder: '页面主体内容:拖拽Block布局组件到这里', + header: { + type: 'JSSlot', + title: 'header', + }, + headerProps: { + background: 'surface', + }, + footer: { + type: 'JSSlot', + title: 'footer', + }, + minHeight: '100vh', + }, + title: '页面', + children: [ + { + componentName: 'NextBlock', + id: 'node_ocko19zplh2', + props: { + prefix: 'next-', + placeholderStyle: { + height: '100%', + }, + noPadding: false, + noBorder: false, + background: 'surface', + layoutmode: 'O', + colSpan: 12, + rowSpan: 1, + childTotalColumns: 12, + }, + title: '区块', + children: [ + { + componentName: 'NextBlockCell', + id: 'node_ocko19zplh3', + props: { + title: '', + prefix: 'next-', + placeholderStyle: { + height: '100%', + }, + layoutmode: 'O', + childTotalColumns: 12, + isAutoContainer: true, + colSpan: 12, + rowSpan: 1, + }, + children: [ + { + componentName: 'NextP', + id: 'node_ocks8dtt1ms', + props: { + wrap: false, + type: 'body2', + verAlign: 'middle', + textSpacing: true, + align: 'left', + full: true, + flex: true, + }, + title: '段落', + children: [ + { + componentName: 'Form', + id: 'node_ocks8dtt1mt', + props: { + labelCol: { + span: 10, + }, + wrapperCol: { + span: 14, + }, + onFinish: { + type: 'JSFunction', + value: 'function(){this.onFinish.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + name: 'basic', + layout: 'inline', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onFinish', + relatedEventName: 'onFinish', + }, + ], + eventList: [ + { + name: 'onFinish', + disabled: true, + }, + { + name: 'onFinishFailed', + disabled: false, + }, + { + name: 'onFieldsChange', + disabled: false, + }, + { + name: 'onValuesChange', + disabled: false, + }, + ], + }, + }, + children: [ + { + componentName: 'Form.Item', + id: 'node_ocks8dtt1mz', + props: { + label: '项目名称/渠道号', + name: 'channel_id', + }, + children: [ + { + componentName: 'Select', + id: 'node_ocksfuhwhsd', + props: { + style: { + width: '280px', + }, + options: { + type: 'JSExpression', + value: 'this.state.projects', + }, + showArrow: true, + tokenSeparators: [], + showSearch: true, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ocks8dtt1m12', + props: { + label: '版本号', + name: 'buildId', + }, + children: [ + { + componentName: 'Input', + id: 'node_ocksfuhwhs3', + props: { + placeholder: '请输入', + style: { + width: '280px', + }, + size: 'middle', + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ocks8dtt1m18', + props: { + label: '构建人', + name: 'user_id', + }, + children: [ + { + componentName: 'Select', + id: 'node_ocksfuhwhsi', + props: { + style: { + width: 200, + }, + options: [ + { + label: 'A', + value: 'A', + }, + { + label: 'B', + value: 'B', + }, + { + label: 'C', + value: 'C', + }, + ], + showSearch: true, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ocks8dtt1m19', + props: { + label: 'ID', + name: 'id', + }, + children: [ + { + componentName: 'Input', + id: 'node_ocksfuhwhs8', + props: { + placeholder: '请输入', + style: { + width: '160px', + }, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ocks8dtt1mw', + props: { + wrapperCol: { + offset: 6, + }, + }, + children: [ + { + componentName: 'Button', + id: 'node_ocks8dtt1mx', + props: { + type: 'primary', + children: '查询', + htmlType: 'submit', + }, + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + { + componentName: 'NextBlock', + id: 'node_ockshc4ifn1b', + props: { + childTotalColumns: 12, + }, + title: '区块', + children: [ + { + componentName: 'NextBlockCell', + id: 'node_ockshc4ifn1c', + props: { + isAutoContainer: true, + colSpan: 12, + rowSpan: 1, + }, + title: '子区块', + children: [ + { + componentName: 'NextP', + id: 'node_ockshc4ifn1d', + props: { + wrap: false, + type: 'body2', + verAlign: 'middle', + textSpacing: true, + align: 'left', + flex: true, + }, + title: '段落', + children: [ + { + componentName: 'ConfigProvider', + id: 'node_ockshc4ifn1e', + props: { + locale: 'zh-CN', + }, + children: [ + { + componentName: 'AliAutoSearchTableDefault', + id: 'node_ocksfuhwhsx', + props: { + rowKey: 'key', + dataSource: { + type: 'JSExpression', + value: 'this.state.pkgs', + }, + columns: [ + { + title: 'ID', + dataIndex: 'id', + key: 'name', + width: 80, + }, + { + title: '渠道号', + dataIndex: 'channels', + key: 'age', + width: 142, + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Typography.Text', + id: 'node_ocksh2bq0428', + props: { + children: { + type: 'JSExpression', + value: 'this.item', + }, + style: { + display: 'block', + }, + }, + loop: { + type: 'JSExpression', + value: "this.text.split(',')", + }, + }, + ], + }, + }, + { + title: '版本号', + dataIndex: 'dic_version', + key: 'address', + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Tooltip', + id: 'node_ocksso4xavj', + props: { + title: { + type: 'JSSlot', + value: [ + { + componentName: 'Typography.Text', + id: 'node_ocksso4xavn', + props: { + children: { + type: 'JSExpression', + value: "this.item. channelId + ' / ' + this.item.version", + }, + style: { + display: 'block', + color: '#FFFFFF', + }, + }, + loop: { + type: 'JSExpression', + value: 'this.text || []', + }, + }, + ], + }, + }, + children: [ + { + componentName: 'Typography.Text', + id: 'node_ocksso4xavm', + props: { + children: { + type: 'JSExpression', + value: 'this.text[0].version', + }, + }, + }, + ], + }, + ], + }, + width: 120, + }, + { + title: '构建Job', + dataIndex: 'job_name', + width: 180, + }, + { + title: '构建类型', + dataIndex: 'packaging_type', + width: 94, + }, + { + title: '构建状态', + dataIndex: 'status', + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Typography.Text', + id: 'node_ocksh3jkxzw', + props: { + children: { + type: 'JSExpression', + value: 'this.statusDesc[this.text]', + }, + }, + }, + { + componentName: 'Icon', + id: 'node_ocksh3jkxzx', + props: { + type: 'SyncOutlined', + size: 16, + spin: true, + style: { + marginLeft: '10px', + }, + }, + condition: { + type: 'JSExpression', + value: 'this.text === 2', + }, + }, + ], + }, + width: 100, + }, + { + title: '构建时间', + dataIndex: 'start_time', + render: { + type: 'JSFunction', + value: 'function(){ return this.renderTime.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + width: 148, + }, + { + title: '构建人', + dataIndex: 'user', + render: { + type: 'JSFunction', + value: 'function(){ return this.renderUserName.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + width: 80, + }, + { + title: 'Jenkins 链接', + dataIndex: 'jenkins_link', + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Typography.Link', + id: 'node_ocksh64kbx21', + props: { + href: { + type: 'JSExpression', + value: 'this.text', + }, + target: '_blank', + children: '查看', + }, + condition: { + type: 'JSExpression', + value: 'this.text', + }, + }, + { + componentName: 'Typography.Text', + id: 'node_ocksh64kbx22', + props: { + children: '暂无', + }, + condition: { + type: 'JSExpression', + value: '!this.text', + }, + }, + ], + }, + width: 120, + }, + { + title: '测试平台链接', + dataIndex: 'is_run_testing', + width: 120, + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Typography.Link', + id: 'node_ocksh3jkxz3e', + props: { + href: 'http://rivermap.alibaba.net/dashboard/testExecute', + target: '_blank', + children: '查看', + }, + condition: { + type: 'JSExpression', + value: 'this.text', + }, + }, + { + componentName: 'Typography.Text', + id: 'node_ocksh3jkxz3f', + props: { + children: '暂无', + }, + condition: { + type: 'JSExpression', + value: '!this.text', + }, + }, + ], + }, + }, + { + title: '触发源', + dataIndex: 'source', + width: 120, + }, + { + title: '详情', + dataIndex: 'id', + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Button', + id: 'node_ocksh8yryw7', + props: { + type: 'link', + children: '查看', + size: 'small', + style: { + padding: '0px', + }, + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'handleDetail', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.handleDetail.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + width: 80, + fixed: 'right', + }, + { + title: '结果', + dataIndex: 'id', + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Button', + id: 'node_ocksh9v6jw7', + props: { + type: 'link', + children: '查看', + size: 'small', + style: { + padding: '0px', + }, + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'handleResult', + paramStr: 'this.text', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.handleResult.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + ghost: false, + href: { + type: 'JSExpression', + value: 'this.text', + }, + }, + }, + ], + }, + width: 80, + fixed: 'right', + }, + { + title: '重新执行', + dataIndex: 'id', + width: 92, + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Button', + id: 'node_ocksh96rad1g', + props: { + type: 'text', + children: '', + icon: { + type: 'JSSlot', + value: [ + { + componentName: 'Icon', + id: 'node_ocksh96rad1j', + props: { + type: 'ReloadOutlined', + size: 14, + color: '#0593d3', + style: { + padding: '3px', + border: '1px solid #0593d3', + borderRadius: '14px', + cursor: 'pointer', + height: '22px', + }, + spin: false, + }, + }, + ], + }, + shape: 'circle', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'reload', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.reload.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + fixed: 'right', + }, + ], + actions: [], + pagination: { + total: { + type: 'JSExpression', + value: 'this.state.total', + }, + defaultPageSize: 8, + onPageChange: { + type: 'JSFunction', + value: 'function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + scrollX: 1200, + }, + condition: { + type: 'JSExpression', + value: '!this.state.isSearch || (this.state.isSearch && this.state.pkgs.length > 0)', + }, + }, + ], + }, + ], + }, + ], + }, + ], + }, + { + componentName: 'NextBlock', + id: 'node_ocksk6f8fa3b', + props: { + childTotalColumns: 12, + }, + title: '区块', + children: [ + { + componentName: 'NextBlockCell', + id: 'node_ocksk6f8fa3c', + props: { + isAutoContainer: true, + colSpan: 12, + rowSpan: 1, + }, + title: '子区块', + children: [ + { + componentName: 'NextP', + id: 'node_ocksk6f8fa3d', + props: { + wrap: false, + type: 'body2', + verAlign: 'middle', + textSpacing: true, + align: 'left', + flex: true, + }, + title: '段落', + children: [ + { + componentName: 'Empty', + id: 'node_ocksk6f8fa3e', + props: { + description: '暂无数据', + }, + condition: { + type: 'JSExpression', + value: 'this.state.pkgs.length < 1 && this.state.isSearch', + }, + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + i18n: {}, +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/.browserslistrc b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/.browserslistrc new file mode 100644 index 0000000000..55a130413d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/.browserslistrc @@ -0,0 +1,3 @@ +defaults +ios_saf 9 + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/.gitignore b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/.gitignore new file mode 100644 index 0000000000..4ec178818e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/.gitignore @@ -0,0 +1,25 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# production +build/ +dist/ +tmp/ +lib/ + +# misc +.idea/ +.happypack +.DS_Store +*.swp +*.dia~ +.ice + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +index.module.scss.d.ts + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/README.md b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/README.md new file mode 100644 index 0000000000..6d9dd75215 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/README.md @@ -0,0 +1 @@ +This project is generated by lowcode-code-generator & lowcode-solution-icejs3. \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/ice.config.mts new file mode 100644 index 0000000000..fe77c9b6cd --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/ice.config.mts @@ -0,0 +1,90 @@ +import { join } from 'path'; +import { defineConfig } from '@ice/app'; +import _ from 'lodash'; +import fusion from '@ice/plugin-fusion'; +import locales from '@ice/plugin-moment-locales'; +import type { Plugin } from '@ice/app/esm/types'; + +interface PluginOptions { + id: string; +} + +const plugin: Plugin<PluginOptions> = (options) => ({ + // name 可选,插件名称 + name: 'plugin-name', + // setup 必选,用于定制工程构建配置 + setup: ({ onGetConfig, modifyUserConfig }) => { + modifyUserConfig('codeSplitting', 'page'); + + onGetConfig((config) => { + config.entry = { + web: join(process.cwd(), '.ice/entry.client.tsx'), + }; + + config.cssFilename = '[name].css'; + + config.configureWebpack = config.configureWebpack || []; + config.configureWebpack?.push((webpackConfig) => { + if (webpackConfig.output) { + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.chunkFilename = '[name].js'; + } + return webpackConfig; + }); + + config.swcOptions = _.merge(config.swcOptions, { + compilationConfig: { + jsc: { + transform: { + react: { + runtime: 'classic', + }, + }, + }, + }, + }); + + // 解决 webpack publicPath 问题 + config.transforms = config.transforms || []; + config.transforms.push((source: string, id: string) => { + if (id.includes('.ice/entry.client.tsx')) { + let code = ` + if (!__webpack_public_path__?.startsWith('http') && document.currentScript) { + // @ts-ignore + __webpack_public_path__ = document.currentScript.src.replace(/^(.*\\/)[^/]+$/, '$1'); + window.__ICE_ASSETS_MANIFEST__ = window.__ICE_ASSETS_MANIFEST__ || {}; + window.__ICE_ASSETS_MANIFEST__.publicPath = __webpack_public_path__; + } + `; + code += source; + return { code }; + } + }); + }); + }, +}); + +// The project config, see https://v3.ice.work/docs/guide/basic/config +const minify = process.env.NODE_ENV === 'production' ? 'swc' : false; +export default defineConfig(() => ({ + ssr: false, + ssg: false, + minify, + + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', + '@alifd/next': 'Next', + lodash: 'var window._', + '@alilc/lowcode-engine': 'var window.AliLowCodeEngine', + }, + plugins: [ + fusion({ + importStyle: true, + }), + locales(), + plugin(), + ], +})); + diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/package.json new file mode 100644 index 0000000000..32b4ea8772 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/package.json @@ -0,0 +1,46 @@ +{ + "name": "icejs3-demo-app", + "version": "0.1.5", + "description": "icejs 3 轻量级模板,使用 JavaScript,仅包含基础的 Layout。", + "dependencies": { + "moment": "^2.24.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router": "^6.9.0", + "react-router-dom": "^6.9.0", + "intl-messageformat": "^9.3.6", + "@alifd/next": "1.26.15", + "@ice/runtime": "^1.0.0", + "@alilc/lowcode-datasource-engine": "^1.0.0", + "undefined": "*", + "@alilc/antd-lowcode-materials": "0.11.0", + "@alife/mc-assets-1935": "0.1.43", + "@alife/container": "0.3.7" + }, + "devDependencies": { + "@ice/app": "^3.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@types/node": "^18.11.17", + "@ice/plugin-fusion": "^1.0.1", + "@ice/plugin-moment-locales": "^1.0.0", + "eslint": "^6.0.1", + "stylelint": "^13.2.0" + }, + "scripts": { + "start": "ice start", + "build": "ice build", + "lint": "npm run eslint && npm run stylelint", + "eslint": "eslint --cache --ext .js,.jsx ./", + "stylelint": "stylelint ./**/*.scss" + }, + "engines": { + "node": ">=14.0.0" + }, + "repository": { + "type": "git", + "url": "http://gitlab.xxx.com/msd/leak-scan/tree/master" + }, + "private": true, + "originTemplate": "@alifd/scaffold-lite-js" +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/app.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/app.ts new file mode 100644 index 0000000000..6d5856292d --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/app.ts @@ -0,0 +1,13 @@ +import { defineAppConfig } from 'ice'; + +// App config, see https://v3.ice.work/docs/guide/basic/app +export default defineAppConfig(() => ({ + // Set your configs here. + app: { + rootId: 'App', + }, + router: { + type: 'browser', + basename: '/', + }, +})); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/constants.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/constants.js new file mode 100644 index 0000000000..ea766c9da3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/constants.js @@ -0,0 +1,3 @@ +const __$$constants = {}; + +export default __$$constants; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/document.tsx new file mode 100644 index 0000000000..286be9f8ca --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/document.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +export default function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="ice.js 3 lite scaffold" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.21.16/next.min.css" /> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> + <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> + <Scripts /> + </body> + </html> + ); +} \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/global.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/global.scss new file mode 100644 index 0000000000..82ca3eac73 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/global.scss @@ -0,0 +1,6 @@ +// 引入默认全局样式 +@import '@alifd/next/reset.scss'; + +body { + -webkit-font-smoothing: antialiased; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js new file mode 100644 index 0000000000..adbbe673dc --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js @@ -0,0 +1,77 @@ +const i18nConfig = {}; + +let locale = + typeof navigator === 'object' && typeof navigator.language === 'string' + ? navigator.language + : 'zh-CN'; + +const getLocale = () => locale; + +const setLocale = (target) => { + locale = target; +}; + +const isEmptyVariables = (variables) => + (Array.isArray(variables) && variables.length === 0) || + (typeof variables === 'object' && + (!variables || Object.keys(variables).length === 0)); + +// 按低代码规范里面的要求进行变量替换 +const format = (msg, variables) => + typeof msg === 'string' + ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + : msg; + +const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { + const msg = + i18nConfig[locale]?.[id] ?? + i18nConfig[locale.replace('-', '_')]?.[id] ?? + defaultMessage; + if (msg == null) { + console.warn('[i18n]: unknown message id: %o (locale=%o)', id, locale); + return fallback === undefined ? `${id}` : fallback; + } + + return format(msg, variables); +}; + +const i18n = (id, params) => { + return i18nFormat({ id }, params); +}; + +// 将国际化的一些方法注入到目标对象&上下文中 +const _inject2 = (target) => { + target.i18n = i18n; + target.getLocale = getLocale; + target.setLocale = (locale) => { + setLocale(locale); + target.forceUpdate(); + }; + target._i18nText = (t) => { + // 优先取直接传过来的语料 + const localMsg = t[locale] ?? t[String(locale).replace('-', '_')]; + if (localMsg != null) { + return format(localMsg, t.params); + } + + // 其次用项目级别的 + const projectMsg = i18nFormat({ id: t.key, fallback: null }, t.params); + if (projectMsg != null) { + return projectMsg; + } + + // 兜底用 use 指定的或默认语言的 + return format(t[t.use || 'zh-CN'] ?? t.en_US, t.params); + }; + + // 注入到上下文中去 + if (target._context && target._context !== target) { + Object.assign(target._context, { + i18n, + getLocale, + setLocale: target.setLocale, + }); + } +}; + +export { getLocale, setLocale, i18n, i18nFormat, _inject2 }; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx new file mode 100644 index 0000000000..cc70d53bea --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.jsx @@ -0,0 +1,14 @@ + +import React from 'react'; +import styles from './index.module.scss'; + +export default function Footer() { + return ( + <p className={styles.footer}> + <span className={styles.logo}>Alibaba Fusion</span> + <br /> + <span className={styles.copyright}>© 2019-现在 Alibaba Fusion & ICE</span> + </p> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss new file mode 100644 index 0000000000..81e77fda5f --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Footer/index.module.scss @@ -0,0 +1,15 @@ + +.footer { + line-height: 20px; + text-align: center; +} + +.logo { + font-weight: bold; + font-size: 16px; +} + +.copyright { + font-size: 12px; +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx new file mode 100644 index 0000000000..265bfdaa07 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.jsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { Link } from 'ice'; +import styles from './index.module.scss'; + +export default function Logo({ image, text, url }) { + return ( + <div className="logo"> + <Link to={url || '/'} className={styles.logo}> + {image && <img src={image} alt="logo" />} + <span>{text}</span> + </Link> + </div> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss new file mode 100644 index 0000000000..1ab56d3945 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -0,0 +1,20 @@ + +.logo{ + display: flex; + align-items: center; + justify-content: center; + color: $color-text1-1; + font-weight: bold; + font-size: 14px; + line-height: 22px; + + &:visited, &:link { + color: $color-text1-1; + } + + img { + height: 24px; + margin-right: 10px; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx new file mode 100644 index 0000000000..911998b0d3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/PageNav/index.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'ice'; +import { Nav } from '@alifd/next'; +import { asideMenuConfig } from '../../menuConfig'; + +const { SubNav } = Nav; +const NavItem = Nav.Item; + +function getNavMenuItems(menusData) { + if (!menusData) { + return []; + } + + return menusData + .filter(item => item.name && !item.hideInMenu) + .map((item, index) => getSubMenuOrItem(item, index)); +} + +function getSubMenuOrItem(item, index) { + if (item.children && item.children.some(child => child.name)) { + const childrenItems = getNavMenuItems(item.children); + + if (childrenItems && childrenItems.length > 0) { + const subNav = ( + <SubNav key={index} icon={item.icon} label={item.name}> + {childrenItems} + </SubNav> + ); + return subNav; + } + + return null; + } + + const navItem = ( + <NavItem key={item.path} icon={item.icon}> + <Link to={item.path}>{item.name}</Link> + </NavItem> + ); + return navItem; +} + +const Navigation = (props, context) => { + const location = useLocation(); + const { pathname } = location; + const { isCollapse } = context; + return ( + <Nav + type="primary" + selectedKeys={[pathname]} + defaultSelectedKeys={[pathname]} + embeddable + openMode="single" + iconOnly={isCollapse} + hasArrow={false} + mode={isCollapse ? 'popup' : 'inline'} + > + {getNavMenuItems(asideMenuConfig)} + </Nav> + ); +}; + +Navigation.contextTypes = { + isCollapse: PropTypes.bool, +}; +export default Navigation; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/index.jsx new file mode 100644 index 0000000000..18db44df5e --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/index.jsx @@ -0,0 +1,81 @@ + +import React, { useState } from 'react'; +import { Shell, ConfigProvider } from '@alifd/next'; +import PageNav from './components/PageNav'; +import Logo from './components/Logo'; +import Footer from './components/Footer'; + +(function() { + const throttle = function(type, name, obj = window) { + let running = false; + + const func = () => { + if (running) { + return; + } + + running = true; + requestAnimationFrame(() => { + obj.dispatchEvent(new CustomEvent(name)); + running = false; + }); + }; + + obj.addEventListener(type, func); + }; + + throttle('resize', 'optimizedResize'); +})(); + +export default function BasicLayout({ children }) { + const getDevice = width => { + const isPhone = + typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 680 || isPhone) { + return 'phone'; + } + if (width < 1280 && width > 680) { + return 'tablet'; + } + return 'desktop'; + }; + + const [device, setDevice] = useState(getDevice(NaN)); + window.addEventListener('optimizedResize', e => { + setDevice(getDevice(e && e.target && e.target.innerWidth)); + }); + return ( + <ConfigProvider device={device}> + <Shell + type="dark" + style={{ + minHeight: '100vh', + }} + > + <Shell.Branding> + <Logo + image="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" + text="Logo" + /> + </Shell.Branding> + <Shell.Navigation + direction="hoz" + style={{ + marginRight: 10, + }} + ></Shell.Navigation> + <Shell.Action></Shell.Action> + <Shell.Navigation> + <PageNav /> + </Shell.Navigation> + + <Shell.Content>{children}</Shell.Content> + <Shell.Footer> + <Footer /> + </Shell.Footer> + </Shell> + </ConfigProvider> + ); +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js new file mode 100644 index 0000000000..5332202be4 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/menuConfig.js @@ -0,0 +1,11 @@ + +const headerMenuConfig = []; +const asideMenuConfig = [ + { + name: 'Dashboard', + path: '/', + icon: 'smile', + }, +]; +export { headerMenuConfig, asideMenuConfig }; + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.css b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.css new file mode 100644 index 0000000000..066114aeeb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.css @@ -0,0 +1,8 @@ +body { + font-size: 12px; +} + +.botton { + width: 100px; + color: #ff00ff; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.jsx new file mode 100644 index 0000000000..5630342f37 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/Test/index.jsx @@ -0,0 +1,976 @@ +// 注意: 出码引擎注入的临时变量默认都以 "__$$" 开头,禁止在搭建的代码中直接访问。 +// 例外:react 框架的导出名和各种组件名除外。 +import React from 'react'; + +import { + Modal, + Button, + Typography, + Form, + Select, + Input, + Tooltip, + Icon, + Empty, +} from '@alilc/antd-lowcode-materials/dist/antd-lowcode.esm.js'; + +import { + AliAutoDiv, + AliAutoSearchTable, +} from '@alife/mc-assets-1935/build/lowcode/index.js'; + +import { + Page as NextPage, + Block as NextBlock, + P as NextP, +} from '@alife/container/lib/index.js'; + +import utils, { RefsManager } from '../../utils'; + +import * as __$$i18n from '../../i18n'; + +import __$$constants from '../../constants'; + +import './index.css'; + +const AliAutoDivDefault = AliAutoDiv.default; + +const AliAutoSearchTableDefault = AliAutoSearchTable.default; + +const NextBlockCell = NextBlock.Cell; + +class Test$$Page extends React.Component { + _context = this; + + get constants() { + return __$$constants || {}; + } + + constructor(props, context) { + super(props); + + this.utils = utils; + + this._refsManager = new RefsManager(); + + __$$i18n._inject2(this); + + this.state = { + pkgs: [], + total: 0, + isSearch: false, + projects: [], + results: [], + resultVisible: false, + userOptions: [], + searchValues: { user_id: '', channel_id: '' }, + }; + + this.__jp__init(); + this.statusDesc = { + 0: '失败', + 1: '成功', + 2: '构建中', + 3: '构建超时', + }; + this.pageParams = {}; + this.searchParams = {}; + this.userTimeout = null; + this.currentUser = null; + this.notFoundContent = null; + this.projectTimeout = null; + this.currentProject = null; + } + + $ = (refName) => { + return this._refsManager.get(refName); + }; + + $$ = (refName) => { + return this._refsManager.getAll(refName); + }; + + componentDidUpdate(prevProps, prevState, snapshot) {} + + componentWillUnmount() {} + + __jp__init() { + /*...*/ + } + + __jp__initRouter() { + /*...*/ + } + + __jp__initDataSource() { + /*...*/ + } + + __jp__initEnv() { + /*...*/ + } + + __jp__initConfig() { + /*...*/ + } + + __jp__initUtils() { + /*...*/ + } + + setSearchItem() { + /*...*/ + } + + fetchProject() { + /*...*/ + } + + handleProjectSearch() { + /*...*/ + } + + handleProjectChange(id) { + this.setSearchItem({ + channel_id: id, + }); + } + + fetchUser() { + /*...*/ + } + + handleUserSearch() { + /*...*/ + } + + handleUserChange(user) { + console.log('debug user', user); + this.setSearchItem({ + user_id: user, + }); + } + + fetchPkgs() { + /*...*/ + } + + onPageChange(pageIndex, pageSize) { + this.pageParams = { + pageIndex, + pageSize, + }; + this.fetchPkgs(); + } + + renderTime(time) { + return this.$utils.moment(time).format('YYYY-MM-DD HH:mm'); + } + + renderUserName(user) { + return user.user_name; + } + + reload() { + /*...*/ + } + + handleResult() { + /*...*/ + } + + handleDetail() { + /*...*/ + } + + onResultCancel() { + /*...*/ + } + + formatResult() { + /*...*/ + } + + handleDownload() { + /*...*/ + } + + onFinish() { + /*...*/ + } + + componentDidMount() { + this.$ds.resolve('PROJECTS'); + if (this.userTimeout) { + clearTimeout(this.userTimeout); + this.userTimeout = null; + } + if (this.projectTimeout) { + clearTimeout(this.projectTimeout); + this.projectTimeout = null; + } + } + + render() { + const __$$context = this._context || this; + const { state } = __$$context; + return ( + <div + ref={this._refsManager.linkRef('outterView')} + style={{ height: '100%' }} + > + <Modal + title="查看结果" + visible={__$$eval(() => this.state.resultVisible)} + footer={ + <Button + type="primary" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onResultCancel', + }, + ], + eventList: [{ name: 'onClick', disabled: true }], + }} + onClick={function () { + this.onResultCancel.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + 确定 + </Button> + } + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onCancel', + relatedEventName: 'onResultCancel', + }, + ], + eventList: [ + { name: 'onCancel', disabled: true }, + { name: 'onOk', disabled: false }, + ], + }} + onCancel={function () { + this.onResultCancel.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + width="720px" + centered={true} + closable={true} + keyboard={true} + mask={true} + maskClosable={true} + > + <AliAutoDivDefault style={{ width: '100%' }}> + {!!__$$eval( + () => this.state.results && this.state.results.length > 0 + ) && ( + <AliAutoDivDefault + style={{ + width: '100%', + textAlign: 'left', + marginBottom: '16px', + }} + > + <Button + type="primary" + size="small" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'handleDownload', + }, + ], + eventList: [{ name: 'onClick', disabled: true }], + }} + onClick={function () { + this.handleDownload.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + > + 下载全部 + </Button> + </AliAutoDivDefault> + )} + {__$$evalArray(() => this.state.results).map((item, index) => + ((__$$context) => ( + <AliAutoDivDefault style={{ width: '100%', marginTop: '10px' }}> + <Typography.Text> + {__$$eval(() => __$$context.formatResult(item))} + </Typography.Text> + {!!__$$eval(() => item.download_link) && ( + <Typography.Link + href={__$$eval(() => item.download_link)} + target="_blank" + > + {' '} + - 点击下载 + </Typography.Link> + )} + {!!__$$eval(() => item.release_notes) && ( + <Typography.Link + href={__$$eval(() => item.release_notes)} + target="_blank" + > + {' '} + - 跳转发布节点 + </Typography.Link> + )} + </AliAutoDivDefault> + ))(__$$createChildContext(__$$context, { item, index })) + )} + </AliAutoDivDefault> + </Modal> + <NextPage + columns={12} + headerDivider={true} + placeholderStyle={{ gridRowEnd: 'span 1', gridColumnEnd: 'span 12' }} + placeholder="页面主体内容:拖拽Block布局组件到这里" + header={null} + headerProps={{ background: 'surface', style: { padding: '' } }} + footer={null} + minHeight="100vh" + contentProps={{ noPadding: false, background: 'transparent' }} + > + <NextBlock childTotalColumns={12}> + <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}> + <NextP + wrap={false} + type="body2" + verAlign="middle" + textSpacing={true} + align="left" + flex={true} + > + <AliAutoDivDefault style={{ width: '100%', display: 'flex' }}> + <AliAutoDivDefault style={{ flex: '1' }}> + <Form + labelCol={{ span: 10 }} + wrapperCol={{ span: 14 }} + onFinish={function () { + this.onFinish.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + name="basic" + layout="inline" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onFinish', + relatedEventName: 'onFinish', + }, + ], + eventList: [ + { name: 'onFinish', disabled: true }, + { name: 'onFinishFailed', disabled: false }, + { name: 'onFieldsChange', disabled: false }, + { name: 'onValuesChange', disabled: false }, + ], + }} + colon={true} + labelAlign="right" + preserve={true} + scrollToFirstError={true} + size="middle" + values={__$$eval(() => this.state.searchValues)} + > + <Form.Item + label="项目名称/渠道号" + name="channel_id" + labelAlign="right" + colon={true} + > + <Select + style={{ width: '320px' }} + options={__$$eval(() => this.state.projects)} + showArrow={false} + tokenSeparators={[]} + showSearch={true} + defaultActiveFirstOption={true} + size="middle" + bordered={true} + filterOption={true} + optionFilterProp="label" + allowClear={true} + placeholder="请输入项目名称/渠道号" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onChange', + relatedEventName: 'handleProjectChange', + }, + { + type: 'componentEvent', + name: 'onSearch', + relatedEventName: 'handleProjectSearch', + }, + ], + eventList: [ + { name: 'onBlur', disabled: false }, + { name: 'onChange', disabled: true }, + { name: 'onDeselect', disabled: false }, + { name: 'onFocus', disabled: false }, + { name: 'onInputKeyDown', disabled: false }, + { name: 'onMouseEnter', disabled: false }, + { name: 'onMouseLeave', disabled: false }, + { name: 'onPopupScroll', disabled: false }, + { name: 'onSearch', disabled: true }, + { name: 'onSelect', disabled: false }, + { + name: 'onDropdownVisibleChange', + disabled: false, + }, + ], + }} + onChange={function () { + this.handleProjectChange.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + onSearch={function () { + this.handleProjectSearch.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + /> + </Form.Item> + <Form.Item label="版本号" name="buildId"> + <Input + placeholder="请输入版本号" + style={{ width: '180px' }} + size="middle" + bordered={true} + /> + </Form.Item> + <Form.Item label="构建人" name="user_id"> + <Select + style={{ width: '210px' }} + options={__$$eval(() => this.state.userOptions)} + showSearch={true} + defaultActiveFirstOption={false} + size="middle" + bordered={true} + filterOption={true} + optionFilterProp="label" + notFoundContent={__$$eval( + () => this.userNotFoundContent + )} + showArrow={false} + placeholder="请输入构建人" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onChange', + relatedEventName: 'handleUserChange', + }, + { + type: 'componentEvent', + name: 'onSearch', + relatedEventName: 'handleUserSearch', + }, + ], + eventList: [ + { name: 'onBlur', disabled: false }, + { name: 'onChange', disabled: true }, + { name: 'onDeselect', disabled: false }, + { name: 'onFocus', disabled: false }, + { name: 'onInputKeyDown', disabled: false }, + { name: 'onMouseEnter', disabled: false }, + { name: 'onMouseLeave', disabled: false }, + { name: 'onPopupScroll', disabled: false }, + { name: 'onSearch', disabled: true }, + { name: 'onSelect', disabled: false }, + { + name: 'onDropdownVisibleChange', + disabled: false, + }, + ], + }} + onChange={function () { + this.handleUserChange.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + onSearch={function () { + this.handleUserSearch.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this)} + allowClear={true} + /> + </Form.Item> + <Form.Item + label="ID" + name="id" + labelAlign="right" + colon={true} + > + <Input + placeholder="请输入ID" + style={{ width: '180px' }} + bordered={true} + size="middle" + /> + </Form.Item> + <Form.Item + wrapperCol={{ offset: 6 }} + labelAlign="right" + colon={true} + style={{ flex: '1', textAlign: 'right' }} + > + <Button + type="primary" + htmlType="submit" + shape="default" + size="middle" + > + 查询 + </Button> + </Form.Item> + </Form> + </AliAutoDivDefault> + <AliAutoDivDefault style={{}}> + <Button + type="link" + htmlType="button" + shape="default" + size="middle" + > + 新增打包 + </Button> + </AliAutoDivDefault> + </AliAutoDivDefault> + </NextP> + </NextBlockCell> + </NextBlock> + <NextBlock + childTotalColumns={12} + mode="inset" + layoutmode="O" + autolayout="(12|1)" + > + <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}> + <NextP + wrap={false} + type="body2" + verAlign="middle" + textSpacing={true} + align="left" + flex={true} + > + {!!__$$eval( + () => + !this.state.isSearch || + (this.state.isSearch && this.state.pkgs.length > 0) + ) && ( + <AliAutoSearchTableDefault + rowKey="key" + dataSource={__$$eval(() => this.state.pkgs)} + columns={[ + { title: 'ID', dataIndex: 'id', key: 'name', width: 80 }, + { + title: '渠道号', + dataIndex: 'channels', + key: 'age', + width: 142, + render: (text, record, index) => + ((__$$context) => + __$$evalArray(() => text.split(',')).map( + (item, index) => + ((__$$context) => ( + <Typography.Text style={{ display: 'block' }}> + {__$$eval(() => item)} + </Typography.Text> + ))( + __$$createChildContext(__$$context, { + item, + index, + }) + ) + ))( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + }, + { + title: '版本号', + dataIndex: 'dic_version', + key: 'address', + render: (text, record, index) => + ((__$$context) => ( + <Tooltip + title={__$$evalArray(() => text || []).map( + (item, index) => + ((__$$context) => ( + <Typography.Text + style={{ + display: 'block', + color: '#FFFFFF', + }} + > + {__$$eval( + () => + item.channelId + ' / ' + item.version + )} + </Typography.Text> + ))( + __$$createChildContext(__$$context, { + item, + index, + }) + ) + )} + > + <Typography.Text> + {__$$eval(() => text[0].version)} + </Typography.Text> + </Tooltip> + ))( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + width: 120, + }, + { title: '构建Job', dataIndex: 'job_name', width: 180 }, + { + title: '构建类型', + dataIndex: 'packaging_type', + width: 94, + }, + { + title: '构建状态', + dataIndex: 'status', + render: (text, record, index) => + ((__$$context) => [ + <Typography.Text> + {__$$eval(() => __$$context.statusDesc[text])} + </Typography.Text>, + !!__$$eval(() => text === 2) && ( + <Icon + type="SyncOutlined" + size={16} + spin={true} + style={{ marginLeft: '10px' }} + /> + ), + ])( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + width: 100, + }, + { + title: '构建时间', + dataIndex: 'start_time', + render: function () { + return this.renderTime.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this), + width: 148, + }, + { + title: '构建人', + dataIndex: 'user', + render: function () { + return this.renderUserName.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this), + width: 80, + }, + { + title: 'Jenkins 链接', + dataIndex: 'jenkins_link', + render: (text, record, index) => + ((__$$context) => [ + !!__$$eval(() => text) && ( + <Typography.Link + href={__$$eval(() => text)} + target="_blank" + > + 查看 + </Typography.Link> + ), + !!__$$eval(() => !text) && ( + <Typography.Text>暂无</Typography.Text> + ), + ])( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + width: 120, + }, + { + title: '测试平台链接', + dataIndex: 'is_run_testing', + width: 120, + render: (text, record, index) => + ((__$$context) => [ + !!__$$eval(() => text) && ( + <Typography.Link + href="http://rivermap.alibaba.net/dashboard/testExecute" + target="_blank" + > + 查看 + </Typography.Link> + ), + !!__$$eval(() => !text) && ( + <Typography.Text>暂无</Typography.Text> + ), + ])( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + }, + { title: '触发源', dataIndex: 'source', width: 120 }, + { + title: '详情', + dataIndex: 'id', + render: (text, record, index) => + ((__$$context) => ( + <Button + type="link" + size="small" + style={{ padding: '0px' }} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'handleDetail', + }, + ], + eventList: [ + { name: 'onClick', disabled: true }, + ], + }} + onClick={function () { + this.handleDetail.apply( + this, + Array.prototype.slice + .call(arguments) + .concat([]) + ); + }.bind(__$$context)} + > + 查看 + </Button> + ))( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + width: 80, + fixed: 'right', + }, + { + title: '结果', + dataIndex: 'id', + render: (text, record, index) => + ((__$$context) => ( + <Button + type="link" + size="small" + style={{ padding: '0px' }} + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'handleResult', + paramStr: 'this.text', + }, + ], + eventList: [ + { name: 'onClick', disabled: true }, + ], + }} + onClick={function () { + this.handleResult.apply( + this, + Array.prototype.slice + .call(arguments) + .concat([]) + ); + }.bind(__$$context)} + ghost={false} + href={__$$eval(() => text)} + > + 查看 + </Button> + ))( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + width: 80, + fixed: 'right', + }, + { + title: '重新执行', + dataIndex: 'id', + width: 92, + render: (text, record, index) => + ((__$$context) => ( + <Button + type="text" + children="" + icon={ + <Icon + type="ReloadOutlined" + size={14} + color="#0593d3" + style={{ + padding: '3px', + border: '1px solid #0593d3', + borderRadius: '14px', + cursor: 'pointer', + height: '22px', + }} + spin={false} + /> + } + shape="circle" + __events={{ + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'reload', + }, + ], + eventList: [ + { name: 'onClick', disabled: true }, + ], + }} + onClick={function () { + this.reload.apply( + this, + Array.prototype.slice + .call(arguments) + .concat([]) + ); + }.bind(__$$context)} + /> + ))( + __$$createChildContext(__$$context, { + text, + record, + index, + }) + ), + fixed: 'right', + }, + ]} + actions={[]} + pagination={{ + total: __$$eval(() => this.state.total), + defaultPageSize: 10, + onPageChange: function () { + return this.onPageChange.apply( + this, + Array.prototype.slice.call(arguments).concat([]) + ); + }.bind(this), + defaultPageIndex: 1, + }} + scrollX={1200} + isPagination={true} + /> + )} + </NextP> + </NextBlockCell> + </NextBlock> + <NextBlock + childTotalColumns={12} + mode="inset" + layoutmode="O" + autolayout="(12|1)" + > + <NextBlockCell isAutoContainer={true} colSpan={12} rowSpan={1}> + <NextP + wrap={false} + type="body2" + verAlign="middle" + textSpacing={true} + align="left" + flex={true} + > + {!!__$$eval( + () => this.state.pkgs.length < 1 && this.state.isSearch + ) && <Empty description="暂无数据" />} + </NextP> + </NextBlockCell> + </NextBlock> + </NextPage> + </div> + ); + } +} + +export default Test$$Page; + +function __$$eval(expr) { + try { + return expr(); + } catch (error) {} +} + +function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; +} + +function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/layout.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/layout.jsx new file mode 100644 index 0000000000..50fbb2d1f1 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/pages/layout.jsx @@ -0,0 +1,10 @@ +import { Outlet } from 'ice'; +import BasicLayout from '@/layouts/BasicLayout'; + +export default function Layout() { + return ( + <BasicLayout> + <Outlet /> + </BasicLayout> + ); +} diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/typings.d.ts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/typings.d.ts new file mode 100644 index 0000000000..a9f8de7ceb --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/typings.d.ts @@ -0,0 +1,9 @@ +/// <reference types="@ice/app/types" /> + +export {}; +declare global { + interface Window { + g_config: Record<string, any>; + } +} + \ No newline at end of file diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/utils.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/utils.js new file mode 100644 index 0000000000..1190717924 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/utils.js @@ -0,0 +1,47 @@ +import { createRef } from 'react'; + +export class RefsManager { + constructor() { + this.refInsStore = {}; + } + + clearNullRefs() { + Object.keys(this.refInsStore).forEach((refName) => { + const filteredInsList = this.refInsStore[refName].filter( + (insRef) => !!insRef.current + ); + if (filteredInsList.length > 0) { + this.refInsStore[refName] = filteredInsList; + } else { + delete this.refInsStore[refName]; + } + }); + } + + get(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName][0].current; + } + + return null; + } + + getAll(refName) { + this.clearNullRefs(); + if (this.refInsStore[refName] && this.refInsStore[refName].length > 0) { + return this.refInsStore[refName].map((i) => i.current); + } + + return []; + } + + linkRef(refName) { + const refIns = createRef(); + this.refInsStore[refName] = this.refInsStore[refName] || []; + this.refInsStore[refName].push(refIns); + return refIns; + } +} + +export default {}; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/schema.json5 b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/schema.json5 new file mode 100644 index 0000000000..2bd00adda3 --- /dev/null +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/schema.json5 @@ -0,0 +1,1457 @@ +{ + version: '1.0.0', + componentsMap: [ + { + devMode: 'lowcode', + componentName: 'Slot', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.11.0', + exportName: 'Button', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Button', + }, + { + package: '@alife/mc-assets-1935', + version: '0.1.43', + exportName: 'AliAutoDiv', + main: 'build/lowcode/index.js', + destructuring: true, + subName: 'default', + componentName: 'AliAutoDivDefault', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.11.0', + exportName: 'Typography', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + subName: 'Text', + componentName: 'Typography.Text', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.11.0', + exportName: 'Typography', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + subName: 'Link', + componentName: 'Typography.Link', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.11.0', + exportName: 'Modal', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Modal', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.11.0', + exportName: 'Select', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Select', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.11.0', + exportName: 'Form', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + subName: 'Item', + componentName: 'Form.Item', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.11.0', + exportName: 'Input', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Input', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.11.0', + exportName: 'Form', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Form', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'P', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextP', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Block', + main: 'lib/index.js', + destructuring: true, + subName: 'Cell', + componentName: 'NextBlockCell', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Block', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextBlock', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.11.0', + exportName: 'Tooltip', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Tooltip', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.11.0', + exportName: 'Icon', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Icon', + }, + { + package: '@alife/mc-assets-1935', + version: '0.1.43', + exportName: 'AliAutoSearchTable', + main: 'build/lowcode/index.js', + destructuring: true, + subName: 'default', + componentName: 'AliAutoSearchTableDefault', + }, + { + package: '@alilc/antd-lowcode-materials', + version: '0.11.0', + exportName: 'Empty', + main: 'dist/antd-lowcode.esm.js', + destructuring: true, + componentName: 'Empty', + }, + { + package: '@alife/container', + version: '0.3.7', + exportName: 'Page', + main: 'lib/index.js', + destructuring: true, + subName: '', + componentName: 'NextPage', + }, + { + devMode: 'lowcode', + componentName: 'Page', + }, + ], + componentsTree: [ + { + componentName: 'Page', + id: 'node_dockcviv8fo1', + props: { + ref: 'outterView', + style: { + height: '100%', + }, + }, + fileName: 'test', + dataSource: { + list: [], + }, + css: 'body {\n font-size: 12px;\n}\n\n.botton {\n width: 100px;\n color: #ff00ff\n}', + lifeCycles: { + constructor: { + type: 'JSFunction', + value: "function() {\n this.__jp__init();\n this.statusDesc = {\n 0: '失败',\n 1: '成功',\n 2: '构建中',\n 3: '构建超时',\n };\n this.pageParams = {};\n this.searchParams = {};\n this.userTimeout = null;\n this.currentUser = null;\n this.notFoundContent = null;\n this.projectTimeout = null;\n this.currentProject = null;\n }", + }, + componentDidMount: { + type: 'JSFunction', + value: "function() {\n this.$ds.resolve('PROJECTS');\n if (this.userTimeout) {\n clearTimeout(this.userTimeout);\n this.userTimeout = null;\n }\n if (this.projectTimeout) {\n clearTimeout(this.projectTimeout);\n this.projectTimeout = null;\n }\n }", + }, + componentDidUpdate: { + type: 'JSFunction', + value: 'function(prevProps, prevState, snapshot) {}', + }, + componentWillUnmount: { + type: 'JSFunction', + value: 'function() {}', + }, + }, + methods: { + __jp__init: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + __jp__initRouter: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + __jp__initDataSource: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + __jp__initEnv: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + __jp__initConfig: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + __jp__initUtils: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + setSearchItem: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + fetchProject: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + handleProjectSearch: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + handleProjectChange: { + type: 'JSFunction', + value: 'function(id) {\n this.setSearchItem({\n channel_id: id,\n });\n }', + }, + fetchUser: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + handleUserSearch: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + handleUserChange: { + type: 'JSFunction', + value: "function(user) {\n console.log('debug user', user);\n this.setSearchItem({\n user_id: user,\n });\n }", + }, + fetchPkgs: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + onPageChange: { + type: 'JSFunction', + value: 'function(pageIndex, pageSize) {\n this.pageParams = {\n pageIndex,\n pageSize,\n };\n this.fetchPkgs();\n }', + }, + renderTime: { + type: 'JSFunction', + value: "function(time) {\n return this.$utils.moment(time).format('YYYY-MM-DD HH:mm');\n }", + }, + renderUserName: { + type: 'JSFunction', + value: 'function(user) {\n return user.user_name;\n }', + }, + reload: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + handleResult: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + handleDetail: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + onResultCancel: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + formatResult: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + handleDownload: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + onFinish: { + type: 'JSFunction', + value: 'function() { /*...*/ }', + }, + }, + state: { + pkgs: [], + total: 0, + isSearch: false, + projects: [], + results: [], + resultVisible: false, + userOptions: [], + searchValues: { + user_id: '', + channel_id: '', + }, + }, + children: [ + { + componentName: 'Modal', + id: 'node_ocksh9yppxb', + props: { + title: '查看结果', + visible: { + type: 'JSExpression', + value: 'this.state.resultVisible', + }, + footer: { + type: 'JSSlot', + value: [ + { + componentName: 'Button', + id: 'node_ocksh9yppxf', + props: { + type: 'primary', + children: '确定', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'onResultCancel', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onCancel', + relatedEventName: 'onResultCancel', + }, + ], + eventList: [ + { + name: 'onCancel', + disabled: true, + }, + { + name: 'onOk', + disabled: false, + }, + ], + }, + onCancel: { + type: 'JSFunction', + value: 'function(){this.onResultCancel.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + width: '720px', + centered: true, + closable: true, + keyboard: true, + mask: true, + maskClosable: true, + }, + hidden: true, + children: [ + { + componentName: 'AliAutoDivDefault', + id: 'node_ockshazuxa4', + props: { + style: { + width: '100%', + }, + }, + children: [ + { + componentName: 'AliAutoDivDefault', + id: 'node_ockshazuxai', + props: { + style: { + width: '100%', + textAlign: 'left', + marginBottom: '16px', + }, + }, + condition: { + type: 'JSExpression', + value: 'this.state.results && this.state.results.length > 0', + }, + children: [ + { + componentName: 'Button', + id: 'node_ockshazuxah', + props: { + type: 'primary', + children: '下载全部', + size: 'small', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'handleDownload', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.handleDownload.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + { + componentName: 'AliAutoDivDefault', + id: 'node_ockt2muyfi4', + props: { + style: { + width: '100%', + marginTop: '10px', + }, + }, + loop: { + type: 'JSExpression', + value: 'this.state.results', + }, + children: [ + { + componentName: 'Typography.Text', + id: 'node_ockshazuxa5', + props: { + children: { + type: 'JSExpression', + value: 'this.formatResult(this.item)', + }, + }, + }, + { + componentName: 'Typography.Link', + id: 'node_ockshazuxa6', + props: { + href: { + type: 'JSExpression', + value: 'this.item.download_link', + }, + target: '_blank', + children: ' - 点击下载', + }, + condition: { + type: 'JSExpression', + value: 'this.item.download_link', + }, + }, + { + componentName: 'Typography.Link', + id: 'node_ockshazuxa7', + props: { + href: { + type: 'JSExpression', + value: 'this.item.release_notes', + }, + target: '_blank', + children: ' - 跳转发布节点', + }, + condition: { + type: 'JSExpression', + value: 'this.item.release_notes', + }, + }, + ], + }, + ], + }, + ], + }, + { + componentName: 'NextPage', + id: 'node_ocko19zplh1', + props: { + columns: 12, + headerDivider: true, + placeholderStyle: { + gridRowEnd: 'span 1', + gridColumnEnd: 'span 12', + }, + placeholder: '页面主体内容:拖拽Block布局组件到这里', + header: { + type: 'JSSlot', + title: 'header', + }, + headerProps: { + background: 'surface', + style: { + padding: '', + }, + }, + footer: { + type: 'JSSlot', + title: 'footer', + }, + minHeight: '100vh', + contentProps: { + noPadding: false, + background: 'transparent', + }, + }, + title: '页面', + children: [ + { + componentName: 'NextBlock', + id: 'node_ockt3t4q8565', + props: { + childTotalColumns: 12, + }, + title: '区块', + children: [ + { + componentName: 'NextBlockCell', + id: 'node_ockt3t4q8566', + props: { + isAutoContainer: true, + colSpan: 12, + rowSpan: 1, + }, + title: '子区块', + children: [ + { + componentName: 'NextP', + id: 'node_ockt3t4q8567', + props: { + wrap: false, + type: 'body2', + verAlign: 'middle', + textSpacing: true, + align: 'left', + flex: true, + }, + title: '段落', + children: [ + { + componentName: 'AliAutoDivDefault', + id: 'node_ockt3t4q8568', + props: { + style: { + width: '100%', + display: 'flex', + }, + }, + children: [ + { + componentName: 'AliAutoDivDefault', + id: 'node_ockt3t4q857a', + props: { + style: { + flex: '1', + }, + }, + children: [ + { + componentName: 'Form', + id: 'node_ocks8dtt1mt', + props: { + labelCol: { + span: 10, + }, + wrapperCol: { + span: 14, + }, + onFinish: { + type: 'JSFunction', + value: 'function(){this.onFinish.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + name: 'basic', + layout: 'inline', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onFinish', + relatedEventName: 'onFinish', + }, + ], + eventList: [ + { + name: 'onFinish', + disabled: true, + }, + { + name: 'onFinishFailed', + disabled: false, + }, + { + name: 'onFieldsChange', + disabled: false, + }, + { + name: 'onValuesChange', + disabled: false, + }, + ], + }, + colon: true, + labelAlign: 'right', + preserve: true, + scrollToFirstError: true, + size: 'middle', + values: { + type: 'JSExpression', + value: 'this.state.searchValues', + }, + }, + children: [ + { + componentName: 'Form.Item', + id: 'node_ocks8dtt1mz', + props: { + label: '项目名称/渠道号', + name: 'channel_id', + labelAlign: 'right', + colon: true, + }, + children: [ + { + componentName: 'Select', + id: 'node_ocksfuhwhsd', + props: { + style: { + width: '320px', + }, + options: { + type: 'JSExpression', + value: 'this.state.projects', + }, + showArrow: false, + tokenSeparators: [], + showSearch: true, + defaultActiveFirstOption: true, + size: 'middle', + bordered: true, + filterOption: true, + optionFilterProp: 'label', + allowClear: true, + placeholder: '请输入项目名称/渠道号', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onChange', + relatedEventName: 'handleProjectChange', + }, + { + type: 'componentEvent', + name: 'onSearch', + relatedEventName: 'handleProjectSearch', + }, + ], + eventList: [ + { + name: 'onBlur', + disabled: false, + }, + { + name: 'onChange', + disabled: true, + }, + { + name: 'onDeselect', + disabled: false, + }, + { + name: 'onFocus', + disabled: false, + }, + { + name: 'onInputKeyDown', + disabled: false, + }, + { + name: 'onMouseEnter', + disabled: false, + }, + { + name: 'onMouseLeave', + disabled: false, + }, + { + name: 'onPopupScroll', + disabled: false, + }, + { + name: 'onSearch', + disabled: true, + }, + { + name: 'onSelect', + disabled: false, + }, + { + name: 'onDropdownVisibleChange', + disabled: false, + }, + ], + }, + onChange: { + type: 'JSFunction', + value: 'function(){this.handleProjectChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + onSearch: { + type: 'JSFunction', + value: 'function(){this.handleProjectSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ocks8dtt1m12', + props: { + label: '版本号', + name: 'buildId', + }, + children: [ + { + componentName: 'Input', + id: 'node_ocksfuhwhs3', + props: { + placeholder: '请输入版本号', + style: { + width: '180px', + }, + size: 'middle', + bordered: true, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ocks8dtt1m18', + props: { + label: '构建人', + name: 'user_id', + }, + children: [ + { + componentName: 'Select', + id: 'node_ocksfuhwhsi', + props: { + style: { + width: '210px', + }, + options: { + type: 'JSExpression', + value: 'this.state.userOptions', + }, + showSearch: true, + defaultActiveFirstOption: false, + size: 'middle', + bordered: true, + filterOption: true, + optionFilterProp: 'label', + notFoundContent: { + type: 'JSExpression', + value: 'this.userNotFoundContent', + }, + showArrow: false, + placeholder: '请输入构建人', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onChange', + relatedEventName: 'handleUserChange', + }, + { + type: 'componentEvent', + name: 'onSearch', + relatedEventName: 'handleUserSearch', + }, + ], + eventList: [ + { + name: 'onBlur', + disabled: false, + }, + { + name: 'onChange', + disabled: true, + }, + { + name: 'onDeselect', + disabled: false, + }, + { + name: 'onFocus', + disabled: false, + }, + { + name: 'onInputKeyDown', + disabled: false, + }, + { + name: 'onMouseEnter', + disabled: false, + }, + { + name: 'onMouseLeave', + disabled: false, + }, + { + name: 'onPopupScroll', + disabled: false, + }, + { + name: 'onSearch', + disabled: true, + }, + { + name: 'onSelect', + disabled: false, + }, + { + name: 'onDropdownVisibleChange', + disabled: false, + }, + ], + }, + onChange: { + type: 'JSFunction', + value: 'function(){this.handleUserChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + onSearch: { + type: 'JSFunction', + value: 'function(){this.handleUserSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + allowClear: true, + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ocks8dtt1m19', + props: { + label: 'ID', + name: 'id', + labelAlign: 'right', + colon: true, + }, + children: [ + { + componentName: 'Input', + id: 'node_ocksfuhwhs8', + props: { + placeholder: '请输入ID', + style: { + width: '180px', + }, + bordered: true, + size: 'middle', + }, + }, + ], + }, + { + componentName: 'Form.Item', + id: 'node_ocks8dtt1mw', + props: { + wrapperCol: { + offset: 6, + }, + labelAlign: 'right', + colon: true, + style: { + flex: '1', + textAlign: 'right', + }, + }, + children: [ + { + componentName: 'Button', + id: 'node_ocks8dtt1mx', + props: { + type: 'primary', + children: '查询', + htmlType: 'submit', + shape: 'default', + size: 'middle', + }, + }, + ], + }, + ], + }, + ], + }, + { + componentName: 'AliAutoDivDefault', + id: 'node_ockt3t4q856b', + props: { + style: {}, + }, + children: [ + { + componentName: 'Button', + id: 'node_ockt3t4q85y', + props: { + type: 'link', + children: '新增打包', + htmlType: 'button', + shape: 'default', + size: 'middle', + }, + condition: true, + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + { + componentName: 'NextBlock', + id: 'node_ockshc4ifn1b', + props: { + childTotalColumns: 12, + mode: 'inset', + layoutmode: 'O', + autolayout: '(12|1)', + }, + title: '区块', + children: [ + { + componentName: 'NextBlockCell', + id: 'node_ockshc4ifn1c', + props: { + isAutoContainer: true, + colSpan: 12, + rowSpan: 1, + }, + title: '子区块', + children: [ + { + componentName: 'NextP', + id: 'node_ockshc4ifn1d', + props: { + wrap: false, + type: 'body2', + verAlign: 'middle', + textSpacing: true, + align: 'left', + flex: true, + }, + title: '段落', + children: [ + { + componentName: 'AliAutoSearchTableDefault', + id: 'node_ocksfuhwhsx', + props: { + rowKey: 'key', + dataSource: { + type: 'JSExpression', + value: 'this.state.pkgs', + }, + columns: [ + { + title: 'ID', + dataIndex: 'id', + key: 'name', + width: 80, + }, + { + title: '渠道号', + dataIndex: 'channels', + key: 'age', + width: 142, + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Typography.Text', + id: 'node_ocksh2bq0428', + props: { + children: { + type: 'JSExpression', + value: 'this.item', + }, + style: { + display: 'block', + }, + }, + loop: { + type: 'JSExpression', + value: "this.text.split(',')", + }, + }, + ], + }, + }, + { + title: '版本号', + dataIndex: 'dic_version', + key: 'address', + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Tooltip', + id: 'node_ocksts0jqgj', + props: { + title: { + type: 'JSSlot', + value: [ + { + componentName: 'Typography.Text', + id: 'node_ocksts0jqgn', + props: { + children: { + type: 'JSExpression', + value: "this.item. channelId + ' / ' + this.item.version", + }, + style: { + display: 'block', + color: '#FFFFFF', + }, + }, + loop: { + type: 'JSExpression', + value: 'this.text || []', + }, + }, + ], + }, + }, + children: [ + { + componentName: 'Typography.Text', + id: 'node_ocksts0jqgm', + props: { + children: { + type: 'JSExpression', + value: 'this.text[0].version', + }, + }, + }, + ], + }, + ], + }, + width: 120, + }, + { + title: '构建Job', + dataIndex: 'job_name', + width: 180, + }, + { + title: '构建类型', + dataIndex: 'packaging_type', + width: 94, + }, + { + title: '构建状态', + dataIndex: 'status', + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Typography.Text', + id: 'node_ocksh3jkxzw', + props: { + children: { + type: 'JSExpression', + value: 'this.statusDesc[this.text]', + }, + }, + }, + { + componentName: 'Icon', + id: 'node_ocksh3jkxzx', + props: { + type: 'SyncOutlined', + size: 16, + spin: true, + style: { + marginLeft: '10px', + }, + }, + condition: { + type: 'JSExpression', + value: 'this.text === 2', + }, + }, + ], + }, + width: 100, + }, + { + title: '构建时间', + dataIndex: 'start_time', + render: { + type: 'JSFunction', + value: 'function(){ return this.renderTime.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + width: 148, + }, + { + title: '构建人', + dataIndex: 'user', + render: { + type: 'JSFunction', + value: 'function(){ return this.renderUserName.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + width: 80, + }, + { + title: 'Jenkins 链接', + dataIndex: 'jenkins_link', + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Typography.Link', + id: 'node_ocksh64kbx21', + props: { + href: { + type: 'JSExpression', + value: 'this.text', + }, + target: '_blank', + children: '查看', + }, + condition: { + type: 'JSExpression', + value: 'this.text', + }, + }, + { + componentName: 'Typography.Text', + id: 'node_ocksh64kbx22', + props: { + children: '暂无', + }, + condition: { + type: 'JSExpression', + value: '!this.text', + }, + }, + ], + }, + width: 120, + }, + { + title: '测试平台链接', + dataIndex: 'is_run_testing', + width: 120, + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Typography.Link', + id: 'node_ocksh3jkxz3e', + props: { + href: 'http://rivermap.alibaba.net/dashboard/testExecute', + target: '_blank', + children: '查看', + }, + condition: { + type: 'JSExpression', + value: 'this.text', + }, + }, + { + componentName: 'Typography.Text', + id: 'node_ocksh3jkxz3f', + props: { + children: '暂无', + }, + condition: { + type: 'JSExpression', + value: '!this.text', + }, + }, + ], + }, + }, + { + title: '触发源', + dataIndex: 'source', + width: 120, + }, + { + title: '详情', + dataIndex: 'id', + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Button', + id: 'node_ocksh8yryw7', + props: { + type: 'link', + children: '查看', + size: 'small', + style: { + padding: '0px', + }, + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'handleDetail', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.handleDetail.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + width: 80, + fixed: 'right', + }, + { + title: '结果', + dataIndex: 'id', + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Button', + id: 'node_ocksh9v6jw7', + props: { + type: 'link', + children: '查看', + size: 'small', + style: { + padding: '0px', + }, + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'handleResult', + paramStr: 'this.text', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.handleResult.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + ghost: false, + href: { + type: 'JSExpression', + value: 'this.text', + }, + }, + }, + ], + }, + width: 80, + fixed: 'right', + }, + { + title: '重新执行', + dataIndex: 'id', + width: 92, + render: { + type: 'JSSlot', + params: ['text', 'record', 'index'], + value: [ + { + componentName: 'Button', + id: 'node_ocksh96rad1g', + props: { + type: 'text', + children: '', + icon: { + type: 'JSSlot', + value: [ + { + componentName: 'Icon', + id: 'node_ocksh96rad1j', + props: { + type: 'ReloadOutlined', + size: 14, + color: '#0593d3', + style: { + padding: '3px', + border: '1px solid #0593d3', + borderRadius: '14px', + cursor: 'pointer', + height: '22px', + }, + spin: false, + }, + }, + ], + }, + shape: 'circle', + __events: { + eventDataList: [ + { + type: 'componentEvent', + name: 'onClick', + relatedEventName: 'reload', + }, + ], + eventList: [ + { + name: 'onClick', + disabled: true, + }, + ], + }, + onClick: { + type: 'JSFunction', + value: 'function(){this.reload.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + }, + }, + ], + }, + fixed: 'right', + }, + ], + actions: [], + pagination: { + total: { + type: 'JSExpression', + value: 'this.state.total', + }, + defaultPageSize: 10, + onPageChange: { + type: 'JSFunction', + value: 'function(){ return this.onPageChange.apply(this,Array.prototype.slice.call(arguments).concat([])) }', + }, + defaultPageIndex: 1, + }, + scrollX: 1200, + isPagination: true, + }, + condition: { + type: 'JSExpression', + value: '!this.state.isSearch || (this.state.isSearch && this.state.pkgs.length > 0)', + }, + }, + ], + }, + ], + }, + ], + }, + { + componentName: 'NextBlock', + id: 'node_ocksk6f8fa3b', + props: { + childTotalColumns: 12, + mode: 'inset', + layoutmode: 'O', + autolayout: '(12|1)', + }, + title: '区块', + children: [ + { + componentName: 'NextBlockCell', + id: 'node_ocksk6f8fa3c', + props: { + isAutoContainer: true, + colSpan: 12, + rowSpan: 1, + }, + title: '子区块', + children: [ + { + componentName: 'NextP', + id: 'node_ocksk6f8fa3d', + props: { + wrap: false, + type: 'body2', + verAlign: 'middle', + textSpacing: true, + align: 'left', + flex: true, + }, + title: '段落', + children: [ + { + componentName: 'Empty', + id: 'node_ocksk6f8fa3e', + props: { + description: '暂无数据', + }, + condition: { + type: 'JSExpression', + value: 'this.state.pkgs.length < 1 && this.state.isSearch', + }, + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + i18n: {}, +} diff --git a/modules/code-generator/tests/public/solutions/icejs3-app.test.ts b/modules/code-generator/tests/public/solutions/icejs3-app.test.ts new file mode 100644 index 0000000000..3d3ec4eac6 --- /dev/null +++ b/modules/code-generator/tests/public/solutions/icejs3-app.test.ts @@ -0,0 +1,63 @@ +import 'jest'; +import fs from 'fs'; +import glob from 'glob'; +import JSON from 'json5'; +import path from 'path'; + +import { + getSubDirectoriesSync, + removeActualDirRecursiveSync, + createDiskPublisher, +} from '../../helpers/solutionHelper'; + +import CodeGenerator from '../../../src'; + +import type { IPublicTypeProjectSchema } from '@alilc/lowcode-types'; + +jest.setTimeout(15 * 1000); + +const TEST_CASES_DIR = path.join(__dirname, '../../fixtures/test-cases/icejs3-app'); +const SHOULD_UPDATE_EXPECTED = process.env.UPDATE_EXPECTED === 'true'; + +getSubDirectoriesSync(TEST_CASES_DIR).forEach(defineTest); + +function defineTest(caseDirName: string) { + test(`react-app (icejs 3)/${caseDirName} should works`, async () => { + try { + const caseFullDir = path.join(TEST_CASES_DIR, caseDirName); + const schema = JSON.parse(fs.readFileSync(path.join(caseFullDir, 'schema.json5'), 'utf-8')); + const actualDir = path.join(caseFullDir, SHOULD_UPDATE_EXPECTED ? 'expected' : 'actual'); + + removeActualDirRecursiveSync(actualDir, caseFullDir); + + await exportProject(schema, actualDir, 'demo-project'); + + const actualFiles = glob.sync('**/*.{js,jsx,json,ts,tsx,less,css,scss,sass}', { + cwd: actualDir, + }); + + expect(actualFiles.length > 0).toBeTruthy(); + + // runPrettierSync(actualFiles, actualDir); + + if (!SHOULD_UPDATE_EXPECTED) { + expect(caseFullDir).toBeSameFileContents(); + } + } catch (e) { + throw e; // just for debugger + } + }); +} + +async function exportProject(schemaJson: IPublicTypeProjectSchema, targetPath: string, projectName: string) { + const icejs3AppBuilder = CodeGenerator.solutions.icejs3(); + const result = await icejs3AppBuilder.generateProject(schemaJson); + + const publisher = createDiskPublisher(); + await publisher.publish({ + project: result, + outputPath: targetPath, + projectSlug: projectName, + createProjectFolder: true, + }); +} From caa2009ac06b4e3df353b6b40d891d9519809e95 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 30 Mar 2023 10:00:34 +0800 Subject: [PATCH 081/469] chore(docs): publish docs 1.0.24 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 791dd88c27..026c67009e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.23", + "version": "1.0.24", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From a0b51d7407ff4943205643dd99e79251b9e308e4 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 30 Mar 2023 14:16:17 +0800 Subject: [PATCH 082/469] fix: fix object being wrappedReactClass --- packages/utils/src/build-components.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/build-components.ts b/packages/utils/src/build-components.ts index e3b1797df7..909248524f 100644 --- a/packages/utils/src/build-components.ts +++ b/packages/utils/src/build-components.ts @@ -121,7 +121,7 @@ export function buildComponents(libraryMap: LibraryMap, } else { component = findComponent(libraryMap, componentName, component); if (component) { - if (!acceptsRef(component)) { + if (!acceptsRef(component) && isReactComponent(component)) { component = wrapReactClass(component as FunctionComponent); } components[componentName] = component; From e0ed17a16a91a9ae8d232ab27877d8cf343a3ff6 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 30 Mar 2023 10:51:17 +0800 Subject: [PATCH 083/469] docs: update SettingField and SettingTopEntry docs --- docs/docs/api/index.md | 7 +- docs/docs/api/init.md | 2 +- docs/docs/api/model/config.md | 113 ------------------ docs/docs/api/model/setting-field.md | 74 ++++++------ docs/docs/api/model/setting-top-entry.md | 16 +-- packages/shell/src/api/canvas.ts | 5 +- packages/shell/src/api/common.tsx | 6 +- packages/shell/src/{model => api}/config.ts | 0 packages/shell/src/api/index.ts | 3 +- packages/shell/src/api/workspace.ts | 2 +- packages/shell/src/index.ts | 2 +- packages/shell/src/model/document-model.ts | 2 +- packages/shell/src/model/drag-object.ts | 8 +- packages/shell/src/model/index.ts | 1 - packages/shell/src/model/node-children.ts | 4 +- packages/shell/src/model/node.ts | 8 +- packages/types/src/shell/api/common.ts | 8 +- packages/types/src/shell/model/drag-object.ts | 12 +- 18 files changed, 92 insertions(+), 181 deletions(-) delete mode 100644 docs/docs/api/model/config.md rename packages/shell/src/{model => api}/config.ts (100%) diff --git a/docs/docs/api/index.md b/docs/docs/api/index.md index 993c39e881..383b2952ce 100644 --- a/docs/docs/api/index.md +++ b/docs/docs/api/index.md @@ -29,12 +29,17 @@ sidebar_position: 0 - node-children 节点孩子 - props 属性集 - prop 属性 -- setting-prop-entry 设置属性 +- setting-field 设置属性 - setting-top-entry 设置属性集 - component-meta 物料元数据 - selection 画布选中 - detecting 画布 hover - history 操作历史 +- window 低代码设计器窗口模型 +- detecting 画布节点悬停模型 +- modal-nodes-manager 模态节点管理器模型 +- plugin-instance 插件实例 +- drop-location 拖拽放置位置模型 ## API 设计约定 diff --git a/docs/docs/api/init.md b/docs/docs/api/init.md index f8bf2cdbe3..9917d1f72d 100644 --- a/docs/docs/api/init.md +++ b/docs/docs/api/init.md @@ -9,7 +9,7 @@ sidebar_position: 10 ## 模块简介 提供 init 等方法 ## 方法 -#### 1. init +#### init 初始化引擎 **方法定义** diff --git a/docs/docs/api/model/config.md b/docs/docs/api/model/config.md deleted file mode 100644 index 854aa1a04f..0000000000 --- a/docs/docs/api/model/config.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: Config -sidebar_position: 16 ---- -> **@types** [IPublicModelEngineConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/engine-config.ts)<br/> -> **@since** v1.1.3 - -## 方法 -### has - -判断指定 key 是否有值 - -```typescript -/** - * 判断指定 key 是否有值 - * check if config has certain key configed - * @param key - * @returns - */ -has(key: string): boolean; -``` - -### get - -获取指定 key 的值 - -```typescript -/** - * 获取指定 key 的值 - * get value by key - * @param key - * @param defaultValue - * @returns - */ -get(key: string, defaultValue?: any): any; -``` - -### set - -设置指定 key 的值 - -```typescript -/** - * 设置指定 key 的值 - * set value for certain key - * @param key - * @param value - */ -set(key: string, value: any): void; -``` - -### setConfig -批量设值,set 的对象版本 - -```typescript -/** - * 批量设值,set 的对象版本 - * set multiple config key-values - * @param config - */ -setConfig(config: { [key: string]: any }): void; -``` - -### 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) - -## 事件 - -### 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): IPublicTypeDisposable; -``` - -相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) - -### onceGot -获取指定 key 的值,若此时还未赋值,则等待,若已有值,则直接返回值 -> 注:此函数返回 Promise 实例,只会执行(fullfill)一次 - -```typescript -/** - * 获取指定 key 的值,若此时还未赋值,则等待,若已有值,则直接返回值 - * 注:此函数返回 Promise 实例,只会执行(fullfill)一次 - * wait until value of certain key is set, will only be - * triggered once. - * @param key - * @returns - */ -onceGot(key: string): Promise<any>; -``` diff --git a/docs/docs/api/model/setting-field.md b/docs/docs/api/model/setting-field.md index abf99db375..226a0c7e5b 100644 --- a/docs/docs/api/model/setting-field.md +++ b/docs/docs/api/model/setting-field.md @@ -4,68 +4,68 @@ sidebar_position: 6 --- > **@types** [IPublicModelSettingField](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-field.ts)<br/> -# 基本介绍 +## 基本介绍 setter 设置器操作对象 -# 属性 +## 属性 -## isGroup +#### isGroup 获取设置属性的 isGroup `@type {boolean}` -## id +#### id 获取设置属性的 id `@type {string}` -## name +#### name 获取设置属性的 name `@type {string | number | undefined}` -## key +#### key 获取设置属性的 key `@type {string | number | undefined}` -## path +#### path 获取设置属性的 path `@type {(string | number)[]}` -## title +#### title 获取设置属性的 title `@type {string}` -## setter +#### setter 获取设置属性的 setter `@type {IPublicTypeSetterType | null}` -## expanded +#### expanded 获取设置属性的 expanded `@type {boolean}` -## extraProps +#### extraProps 获取设置属性的 extraProps `@type {IPublicTypeFieldExtraProps}` -## props +#### props `@type {IPublicModelSettingTopEntry}` @@ -73,14 +73,14 @@ setter 设置器操作对象 相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts) -## node +#### node 获取设置属性对应的节点实例 `@type {IPublicModelNode | null}` -## parent +#### parent 获取设置属性的父设置属性 @@ -90,7 +90,7 @@ setter 设置器操作对象 相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts) -## top +#### top 获取顶级设置属性 @@ -100,19 +100,19 @@ setter 设置器操作对象 相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts) -## isSettingField +#### isSettingField 是否是 SettingField 实例 `@type {boolean}` -## componentMeta +#### componentMeta `@type {IPublicModelComponentMeta}` 相关类型:[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts) -## items +#### items 获取设置属性的 items @@ -120,9 +120,9 @@ setter 设置器操作对象 相关类型:[IPublicTypeCustomView](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/custom-view.ts) -# 方法 +## 方法 -## setKey +#### setKey 设置 key 值 @@ -134,7 +134,7 @@ setter 设置器操作对象 setKey(key: string | number): void; ``` -## setValue +#### setValue 设置值 @@ -150,7 +150,7 @@ setValue(val: IPublicTypeCompositeValue, extraOptions?: IPublicTypeSetValueOptio - [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 +#### setPropValue 设置子级属性值 @@ -163,7 +163,7 @@ setValue(val: IPublicTypeCompositeValue, extraOptions?: IPublicTypeSetValueOptio setPropValue(propName: string | number, value: any): void; ``` -## clearPropValue +#### clearPropValue 清空指定属性值 @@ -175,7 +175,7 @@ setPropValue(propName: string | number, value: any): void; clearPropValue(propName: string | number): void; ``` -## getDefaultValue +#### getDefaultValue 获取配置的默认值 @@ -187,7 +187,7 @@ clearPropValue(propName: string | number): void; getDefaultValue(): any; ``` -## getValue +#### getValue 获取值 @@ -199,7 +199,7 @@ getDefaultValue(): any; getValue(): any; ``` -## getPropValue +#### getPropValue 获取子级属性值 @@ -212,7 +212,7 @@ getValue(): any; getPropValue(propName: string | number): any; ``` -## getExtraPropValue +#### getExtraPropValue 获取顶层附属属性值 @@ -223,7 +223,7 @@ getPropValue(propName: string | number): any; getExtraPropValue(propName: string): any; ``` -## setExtraPropValue +#### setExtraPropValue 设置顶层附属属性值 @@ -234,7 +234,7 @@ getExtraPropValue(propName: string): any; setExtraPropValue(propName: string, value: any): void; ``` -## getProps +#### getProps 获取设置属性集 @@ -250,7 +250,7 @@ getProps(): IPublicModelSettingTopEntry; 相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts) -## isUseVariable +#### isUseVariable 是否绑定了变量 @@ -262,7 +262,7 @@ getProps(): IPublicModelSettingTopEntry; isUseVariable(): boolean; ``` -## setUseVariable +#### setUseVariable 设置绑定变量 @@ -274,7 +274,7 @@ isUseVariable(): boolean; setUseVariable(flag: boolean): void; ``` -## createField +#### createField 创建一个设置 field 实例 @@ -289,7 +289,7 @@ createField(config: IPublicTypeFieldConfig): IPublicModelSettingField; 相关类型:[IPublicTypeFieldConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/field-config.ts) -## getMockOrValue +#### getMockOrValue 获取值,当为变量时,返回 mock @@ -302,7 +302,7 @@ getMockOrValue(): any; ``` -## purge +#### purge 销毁当前 field 实例 @@ -313,7 +313,7 @@ getMockOrValue(): any; purge(): void; ``` -## remove +#### remove 移除当前 field 实例 @@ -324,7 +324,9 @@ purge(): void; remove(): void; ``` -## onEffect +## 事件 + +#### onEffect 设置 autorun diff --git a/docs/docs/api/model/setting-top-entry.md b/docs/docs/api/model/setting-top-entry.md index 0a925c3a9e..2e2cad52be 100644 --- a/docs/docs/api/model/setting-top-entry.md +++ b/docs/docs/api/model/setting-top-entry.md @@ -4,21 +4,21 @@ sidebar_position: 6 --- > **@types** [IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)<br/> -# 基本介绍 +## 基本介绍 setter 设置器顶层操作对象 -# 属性 +## 属性 -## node +#### node 返回所属的节点实例 `@type {IPublicModelNode | null}` -# 方法 +## 方法 -## get +#### get 获取子级属性对象 @@ -35,7 +35,7 @@ get(propName: string | number): IPublicModelSettingField | null; 相关类型:[IPublicModelSettingField](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-field.ts) -## getPropValue +#### getPropValue 获取指定 propName 的值 @@ -48,7 +48,7 @@ get(propName: string | number): IPublicModelSettingField | null; getPropValue(propName: string | number): any; ``` -## setPropValue +#### setPropValue 设置指定 propName 的值 @@ -61,7 +61,7 @@ getPropValue(propName: string | number): any; setPropValue(propName: string | number, value: any): void; ``` -## clearPropValue +#### clearPropValue 清除指定 propName 的值 diff --git a/packages/shell/src/api/canvas.ts b/packages/shell/src/api/canvas.ts index d20ebd9d92..48acbc487a 100644 --- a/packages/shell/src/api/canvas.ts +++ b/packages/shell/src/api/canvas.ts @@ -20,6 +20,7 @@ import { DropLocation as ShellDropLocation, ActiveTracker as ShellActiveTracker, Clipboard as ShellClipboard, + DropLocation, } from '../model'; const clipboardInstanceSymbol = Symbol('clipboardInstace'); @@ -66,10 +67,10 @@ export class Canvas implements IPublicApiCanvas { * 创建插入位置,考虑放到 dragon 中 */ createLocation(locationData: IPublicTypeLocationData): IPublicModelDropLocation { - return this[designerSymbol].createLocation({ + return new DropLocation(this[designerSymbol].createLocation({ ...locationData, target: (locationData.target as any)[nodeSymbol], - }); + })); } /** diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx index 9954fdfe6d..6a44dc82e7 100644 --- a/packages/shell/src/api/common.tsx +++ b/packages/shell/src/api/common.tsx @@ -59,7 +59,7 @@ import { observer as innerObserver, } from '@alilc/lowcode-editor-core'; import { Dragon as ShellDragon } from '../model'; -import { ReactNode, Component } from 'react'; +import { ReactNode } from 'react'; class DesignerCabin implements IPublicApiCommonDesignerCabin { private readonly [editorSymbol]: Editor; @@ -246,7 +246,7 @@ class EditorCabin implements IPublicApiCommonEditorCabin { * Title 组件 * @experimental unstable API, pay extra caution when trying to use this */ - get Title(): Component { + get Title() { return InnerTitle; } @@ -254,7 +254,7 @@ class EditorCabin implements IPublicApiCommonEditorCabin { * Tip 组件 * @experimental unstable API, pay extra caution when trying to use this */ - get Tip(): Component { + get Tip() { return InnerTip; } diff --git a/packages/shell/src/model/config.ts b/packages/shell/src/api/config.ts similarity index 100% rename from packages/shell/src/model/config.ts rename to packages/shell/src/api/config.ts diff --git a/packages/shell/src/api/index.ts b/packages/shell/src/api/index.ts index 9274571c56..4114926e19 100644 --- a/packages/shell/src/api/index.ts +++ b/packages/shell/src/api/index.ts @@ -9,4 +9,5 @@ export * from './setters'; export * from './simulator-host'; export * from './skeleton'; export * from './canvas'; -export * from './workspace'; \ No newline at end of file +export * from './workspace'; +export * from './config'; \ No newline at end of file diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index ae4bc65aad..21015431f9 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -1,8 +1,8 @@ import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; import { IWorkspace } from '@alilc/lowcode-workspace'; -import { Plugins } from '@alilc/lowcode-shell'; import { workspaceSymbol } from '../symbols'; import { Resource as ShellResource, Window as ShellWindow } from '../model'; +import { Plugins } from './plugins'; export class Workspace implements IPublicApiWorkspace { readonly [workspaceSymbol]: IWorkspace; diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index 30eb32adaf..7017ca2894 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -9,7 +9,6 @@ import { Dragon, SettingTopEntry, Clipboard, - Config, SettingField, } from './model'; import { @@ -26,6 +25,7 @@ import { Canvas, Workspace, SimulatorHost, + Config, } from './api'; export * from './symbols'; diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts index b8698ebf74..68252e3a55 100644 --- a/packages/shell/src/model/document-model.ts +++ b/packages/shell/src/model/document-model.ts @@ -196,7 +196,7 @@ export class DocumentModel implements IPublicModelDocumentModel { * @param data * @returns */ - createNode(data: IPublicTypeNodeSchema): IPublicModelNode | null { + createNode<IPublicModelNode>(data: IPublicTypeNodeSchema): IPublicModelNode | null { return ShellNode.create(this[documentSymbol].createNode(data)); } diff --git a/packages/shell/src/model/drag-object.ts b/packages/shell/src/model/drag-object.ts index dc4157bd2a..064680fdee 100644 --- a/packages/shell/src/model/drag-object.ts +++ b/packages/shell/src/model/drag-object.ts @@ -1,5 +1,5 @@ import { dragObjectSymbol } from '../symbols'; -import { IPublicModelDragObject, IPublicModelDragObject as InnerDragObject, IPublicTypeDragNodeDataObject } from '@alilc/lowcode-types'; +import { IPublicModelDragObject, IPublicModelDragObject as InnerDragObject, IPublicTypeDragNodeDataObject, IPublicTypeNodeSchema } from '@alilc/lowcode-types'; import { Node } from './node'; export class DragObject implements IPublicModelDragObject { @@ -16,11 +16,11 @@ export class DragObject implements IPublicModelDragObject { return new DragObject(dragObject); } - get type(): any { + get type() { return this[dragObjectSymbol].type; } - get nodes(): any { + get nodes() { const { nodes } = this[dragObjectSymbol]; if (!nodes) { return null; @@ -28,7 +28,7 @@ export class DragObject implements IPublicModelDragObject { return nodes.map(Node.create); } - get data(): any { + get data(): IPublicTypeNodeSchema | IPublicTypeNodeSchema[] { return (this[dragObjectSymbol] as IPublicTypeDragNodeDataObject).data; } } \ No newline at end of file diff --git a/packages/shell/src/model/index.ts b/packages/shell/src/model/index.ts index e747021b79..cd481643e5 100644 --- a/packages/shell/src/model/index.ts +++ b/packages/shell/src/model/index.ts @@ -19,4 +19,3 @@ export * from './active-tracker'; export * from './plugin-instance'; export * from './window'; export * from './clipboard'; -export * from './config'; diff --git a/packages/shell/src/model/node-children.ts b/packages/shell/src/model/node-children.ts index 4d1cc0a222..b6d52e86fe 100644 --- a/packages/shell/src/model/node-children.ts +++ b/packages/shell/src/model/node-children.ts @@ -142,8 +142,8 @@ export class NodeChildren implements IPublicModelNodeChildren { * 类似数组的 map * @param fn */ - map<T>(fn: (node: IPublicModelNode, index: number) => T[]): any[] | null { - return this[nodeChildrenSymbol].map((item: InnerNode, index: number) => { + map<T = any>(fn: (node: IPublicModelNode, index: number) => T): T[] | null { + return this[nodeChildrenSymbol].map<T>((item: InnerNode, index: number): T => { return fn(ShellNode.create(item)!, index); }); } diff --git a/packages/shell/src/model/node.ts b/packages/shell/src/model/node.ts index 249e87f46e..f2cddd1ab8 100644 --- a/packages/shell/src/model/node.ts +++ b/packages/shell/src/model/node.ts @@ -31,6 +31,10 @@ import { ConditionGroup } from './condition-group'; const shellNodeSymbol = Symbol('shellNodeSymbol'); +function isShellNode(node: any): node is IPublicModelNode { + return node[shellNodeSymbol]; +} + export class Node implements IPublicModelNode { private readonly [documentSymbol]: InnerDocumentModel | null; private readonly [nodeSymbol]: InnerNode; @@ -326,12 +330,12 @@ export class Node implements IPublicModelNode { this._id = this[nodeSymbol].id; } - static create(node: InnerNode | null | undefined): IPublicModelNode | null { + static create(node: InnerNode | IPublicModelNode | null | undefined): IPublicModelNode | null { if (!node) { return null; } // @ts-ignore 直接返回已挂载的 shell node 实例 - if (node[shellNodeSymbol]) { + if (isShellNode(node)) { return (node as any)[shellNodeSymbol]; } const shellNode = new Node(node); diff --git a/packages/types/src/shell/api/common.ts b/packages/types/src/shell/api/common.ts index d00a2468b3..60fac1606d 100644 --- a/packages/types/src/shell/api/common.ts +++ b/packages/types/src/shell/api/common.ts @@ -4,6 +4,7 @@ import { IPublicTypeNodeSchema, IPublicTypeTitleContent } from '../type'; import { IPublicEnumTransitionType } from '../enum'; export interface IPublicApiCommonUtils { + /** * 是否为合法的 schema 结构 * check if data is valid NodeSchema @@ -70,6 +71,7 @@ export interface IPublicApiCommonUtils { }; } export interface IPublicApiCommonSkeletonCabin { + /** * 编辑器框架 View * get Workbench Component @@ -78,16 +80,18 @@ export interface IPublicApiCommonSkeletonCabin { } export interface IPublicApiCommonEditorCabin { + /** * Title 组件 * @experimental unstable API, pay extra caution when trying to use this */ - get Tip(): React.FC<{}>; + get Tip(): React.ComponentClass<{}>; + /** * Tip 组件 * @experimental unstable API, pay extra caution when trying to use this */ - get Title(): React.FC<{ + get Title(): React.ComponentClass<{ title: IPublicTypeTitleContent | undefined; match?: boolean; keywords?: string | null; diff --git a/packages/types/src/shell/model/drag-object.ts b/packages/types/src/shell/model/drag-object.ts index af404a2f00..92d92eca35 100644 --- a/packages/types/src/shell/model/drag-object.ts +++ b/packages/types/src/shell/model/drag-object.ts @@ -1,3 +1,11 @@ -import { IPublicTypeDragNodeDataObject, IPublicTypeDragNodeObject } from '../type'; +import { IPublicEnumDragObjectType } from '../enum'; +import { IPublicTypeNodeSchema } from '../type'; +import { IPublicModelNode } from './node'; -export type IPublicModelDragObject = Readonly<IPublicTypeDragNodeObject> | Readonly<IPublicTypeDragNodeDataObject>; +export class IPublicModelDragObject { + type: IPublicEnumDragObjectType.Node | IPublicEnumDragObjectType.NodeData; + + data: IPublicTypeNodeSchema | IPublicTypeNodeSchema[] | null; + + nodes: (IPublicModelNode | null)[] | null; +} From 9b519a198464ed81c49b06b1f37883d286dfdb16 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 30 Mar 2023 16:05:47 +0800 Subject: [PATCH 084/469] chore(docs): publish docs 1.0.25 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 026c67009e..c05ace3105 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.24", + "version": "1.0.25", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 579480c56ca7f3da8f6d8afffd74ba6e7d7aa921 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 31 Mar 2023 10:58:10 +0800 Subject: [PATCH 085/469] chore(release): publish 1.1.5 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 10 +++++----- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 67 insertions(+), 67 deletions(-) diff --git a/lerna.json b/lerna.json index b89c797fc2..8edd610752 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.4", + "version": "1.1.5", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index e4516ebe52..6350d00fb3 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.4", + "version": "1.1.5", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.1.4", - "@alilc/lowcode-types": "1.1.4", - "@alilc/lowcode-utils": "1.1.4", + "@alilc/lowcode-editor-core": "1.1.5", + "@alilc/lowcode-types": "1.1.5", + "@alilc/lowcode-utils": "1.1.5", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 8725765f2f..3110d9dc1b 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.1.4", + "version": "1.1.5", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.4", - "@alilc/lowcode-utils": "1.1.4", + "@alilc/lowcode-types": "1.1.5", + "@alilc/lowcode-utils": "1.1.5", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index dfc83d116a..365400b700 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.1.4", + "version": "1.1.5", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -18,10 +18,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.1.4", - "@alilc/lowcode-editor-core": "1.1.4", - "@alilc/lowcode-types": "1.1.4", - "@alilc/lowcode-utils": "1.1.4", + "@alilc/lowcode-designer": "1.1.5", + "@alilc/lowcode-editor-core": "1.1.5", + "@alilc/lowcode-types": "1.1.5", + "@alilc/lowcode-utils": "1.1.5", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index b46349bd59..723ee40175 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.4", + "version": "1.1.5", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.1.4", - "@alilc/lowcode-editor-core": "1.1.4", - "@alilc/lowcode-editor-skeleton": "1.1.4", + "@alilc/lowcode-designer": "1.1.5", + "@alilc/lowcode-editor-core": "1.1.5", + "@alilc/lowcode-editor-skeleton": "1.1.5", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.4", - "@alilc/lowcode-plugin-outline-pane": "1.1.4", - "@alilc/lowcode-shell": "1.1.4", - "@alilc/lowcode-utils": "1.1.4", - "@alilc/lowcode-workspace": "1.1.4", + "@alilc/lowcode-plugin-designer": "1.1.5", + "@alilc/lowcode-plugin-outline-pane": "1.1.5", + "@alilc/lowcode-shell": "1.1.5", + "@alilc/lowcode-utils": "1.1.5", + "@alilc/lowcode-workspace": "1.1.5", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 40fb88804f..440496f583 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.4", + "version": "1.1.5", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 683fb14b20..1673eab860 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.1.4", + "version": "1.1.5", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.4", - "@alilc/lowcode-editor-core": "1.1.4", - "@alilc/lowcode-utils": "1.1.4", + "@alilc/lowcode-designer": "1.1.5", + "@alilc/lowcode-editor-core": "1.1.5", + "@alilc/lowcode-utils": "1.1.5", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index c71657bdc8..73aaa01b43 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.1.4", + "version": "1.1.5", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,10 +13,10 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-designer": "1.1.4", - "@alilc/lowcode-editor-core": "1.1.4", - "@alilc/lowcode-types": "1.1.4", - "@alilc/lowcode-utils": "1.1.4", + "@alilc/lowcode-designer": "1.1.5", + "@alilc/lowcode-editor-core": "1.1.5", + "@alilc/lowcode-types": "1.1.5", + "@alilc/lowcode-utils": "1.1.5", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 759c1e2f95..366e1673c3 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.1.4", + "version": "1.1.5", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.1.4", - "@alilc/lowcode-utils": "1.1.4", + "@alilc/lowcode-renderer-core": "1.1.5", + "@alilc/lowcode-utils": "1.1.5", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 25c99408b2..87f2290553 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.1.4", + "version": "1.1.5", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.4", - "@alilc/lowcode-rax-renderer": "1.1.4", - "@alilc/lowcode-types": "1.1.4", - "@alilc/lowcode-utils": "1.1.4", + "@alilc/lowcode-designer": "1.1.5", + "@alilc/lowcode-rax-renderer": "1.1.5", + "@alilc/lowcode-types": "1.1.5", + "@alilc/lowcode-utils": "1.1.5", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 2f2e74b150..d0cd2dc2ca 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.1.4", + "version": "1.1.5", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.1.4" + "@alilc/lowcode-renderer-core": "1.1.5" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index faa2a0ca83..43c58581e3 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.1.4", + "version": "1.1.5", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.4", - "@alilc/lowcode-react-renderer": "1.1.4", - "@alilc/lowcode-types": "1.1.4", - "@alilc/lowcode-utils": "1.1.4", + "@alilc/lowcode-designer": "1.1.5", + "@alilc/lowcode-react-renderer": "1.1.5", + "@alilc/lowcode-types": "1.1.5", + "@alilc/lowcode-utils": "1.1.5", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 547385edfa..75c407a202 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.1.4", + "version": "1.1.5", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.1.4", - "@alilc/lowcode-utils": "1.1.4", + "@alilc/lowcode-types": "1.1.5", + "@alilc/lowcode-utils": "1.1.5", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.1.4", + "@alilc/lowcode-designer": "1.1.5", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 04ddc611c5..669bd3de14 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.4", + "version": "1.1.5", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,12 +15,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.4", - "@alilc/lowcode-editor-core": "1.1.4", - "@alilc/lowcode-editor-skeleton": "1.1.4", - "@alilc/lowcode-types": "1.1.4", - "@alilc/lowcode-utils": "1.1.4", - "@alilc/lowcode-workspace": "1.1.4", + "@alilc/lowcode-designer": "1.1.5", + "@alilc/lowcode-editor-core": "1.1.5", + "@alilc/lowcode-editor-skeleton": "1.1.5", + "@alilc/lowcode-types": "1.1.5", + "@alilc/lowcode-utils": "1.1.5", + "@alilc/lowcode-workspace": "1.1.5", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index edabf93d24..42755f5626 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.4", + "version": "1.1.5", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index bb3fecc887..c7fc7140c9 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.4", + "version": "1.1.5", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.4", + "@alilc/lowcode-types": "1.1.5", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 12404ba181..34c7cfa762 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.4", + "version": "1.1.5", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.4", - "@alilc/lowcode-editor-core": "1.1.4", - "@alilc/lowcode-editor-skeleton": "1.1.4", - "@alilc/lowcode-types": "1.1.4", - "@alilc/lowcode-utils": "1.1.4", + "@alilc/lowcode-designer": "1.1.5", + "@alilc/lowcode-editor-core": "1.1.5", + "@alilc/lowcode-editor-skeleton": "1.1.5", + "@alilc/lowcode-types": "1.1.5", + "@alilc/lowcode-utils": "1.1.5", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 122f0b30a03a34f07ab5e748011ba6cb0cad4ecc Mon Sep 17 00:00:00 2001 From: "knight.chen" <knightchen@knx.com.cn> Date: Fri, 31 Mar 2023 09:46:54 +0800 Subject: [PATCH 086/469] feat: optimized lowcode types --- packages/types/src/shell/type/metadata.ts | 6 ++++-- packages/types/src/shell/type/node-data.ts | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/types/src/shell/type/metadata.ts b/packages/types/src/shell/type/metadata.ts index 7ed9dc6be6..2815557a52 100644 --- a/packages/types/src/shell/type/metadata.ts +++ b/packages/types/src/shell/type/metadata.ts @@ -133,11 +133,13 @@ export interface IPublicTypeLiveTextEditingConfig { onSaveContent?: (content: string, prop: any) => any; } -export type ConfigureSupportEvent = string | { +export type ConfigureSupportEvent = string | ConfigureSupportEventConfig; + +export interface ConfigureSupportEventConfig { name: string; propType?: IPublicTypePropType; description?: string; -}; +} /** * 通用扩展面板支持性配置 diff --git a/packages/types/src/shell/type/node-data.ts b/packages/types/src/shell/type/node-data.ts index 745773e604..0447c9e2a7 100644 --- a/packages/types/src/shell/type/node-data.ts +++ b/packages/types/src/shell/type/node-data.ts @@ -1,3 +1,3 @@ -import { IPublicTypeJSExpression, IPublicTypeNodeSchema, IPublicTypeDOMText } from './'; +import { IPublicTypeJSExpression, IPublicTypeNodeSchema, IPublicTypeDOMText, IPublicTypeI18nData } from './'; -export type IPublicTypeNodeData = IPublicTypeNodeSchema | IPublicTypeJSExpression | IPublicTypeDOMText; +export type IPublicTypeNodeData = IPublicTypeNodeSchema | IPublicTypeJSExpression | IPublicTypeDOMText | IPublicTypeI18nData; From 48bc8d7659e332bd2b43c5f86708ae6274af1047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Thu, 30 Mar 2023 16:41:43 +0800 Subject: [PATCH 087/469] fix: compatible with {} in template literals --- docs/docs/guide/expand/runtime/codeGeneration.md | 7 ++++--- docs/docs/specs/lowcode-spec.md | 4 ++-- modules/code-generator/example-schema.json | 2 +- modules/code-generator/example-schema.json5 | 2 +- .../project/framework/icejs3/plugins/buildConfig.ts | 2 +- .../src/layouts/BasicLayout/components/Logo/index.style.ts | 4 ++-- modules/code-generator/src/plugins/project/i18n.ts | 2 +- .../icejs3-app/demo1/expected/demo-project/ice.config.mts | 2 +- .../icejs3-app/demo1/expected/demo-project/src/i18n.js | 2 +- .../layouts/BasicLayout/components/Logo/index.module.scss | 4 ++-- .../expected/demo-project/ice.config.mts | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../layouts/BasicLayout/components/Logo/index.module.scss | 4 ++-- .../icejs3-app/demo2/expected/demo-project/ice.config.mts | 2 +- .../icejs3-app/demo2/expected/demo-project/src/i18n.js | 2 +- .../layouts/BasicLayout/components/Logo/index.module.scss | 4 ++-- .../icejs3-app/demo3/expected/demo-project/ice.config.mts | 2 +- .../icejs3-app/demo3/expected/demo-project/src/i18n.js | 2 +- .../layouts/BasicLayout/components/Logo/index.module.scss | 4 ++-- .../icejs3-app/demo4/expected/demo-project/ice.config.mts | 2 +- .../icejs3-app/demo4/expected/demo-project/src/i18n.js | 2 +- .../layouts/BasicLayout/components/Logo/index.module.scss | 4 ++-- .../icejs3-app/demo5/expected/demo-project/ice.config.mts | 2 +- .../icejs3-app/demo5/expected/demo-project/src/i18n.js | 2 +- .../layouts/BasicLayout/components/Logo/index.module.scss | 4 ++-- .../expected/demo-project/ice.config.mts | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../layouts/BasicLayout/components/Logo/index.module.scss | 4 ++-- .../expected/demo-project/ice.config.mts | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../layouts/BasicLayout/components/Logo/index.module.scss | 4 ++-- .../expected/demo-project/ice.config.mts | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../layouts/BasicLayout/components/Logo/index.module.scss | 4 ++-- .../expected/demo-project/ice.config.mts | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../layouts/BasicLayout/components/Logo/index.module.scss | 4 ++-- .../demo_10-jsslot/expected/demo-project/ice.config.mts | 2 +- .../demo_10-jsslot/expected/demo-project/src/i18n.js | 2 +- .../layouts/BasicLayout/components/Logo/index.module.scss | 4 ++-- .../demo_11-jsslot-2/expected/demo-project/ice.config.mts | 2 +- .../demo_11-jsslot-2/expected/demo-project/src/i18n.js | 2 +- .../layouts/BasicLayout/components/Logo/index.module.scss | 4 ++-- .../rax-app/demo01/expected/demo-project/src/i18n.js | 2 +- .../rax-app/demo02/expected/demo-project/src/i18n.js | 2 +- .../rax-app/demo03/expected/demo-project/src/i18n.js | 2 +- .../rax-app/demo04/expected/demo-project/src/i18n.js | 2 +- .../rax-app/demo05/expected/demo-project/src/i18n.js | 2 +- .../demo06-jsslot/expected/demo-project/src/i18n.js | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../rax-app/demo12-refs/expected/demo-project/src/i18n.js | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../react-app/demo1/expected/demo-project/src/i18n.js | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../react-app/demo2/expected/demo-project/src/i18n.js | 2 +- .../react-app/demo3/expected/demo-project/src/i18n.js | 2 +- .../react-app/demo4/expected/demo-project/src/i18n.js | 2 +- .../react-app/demo5/expected/demo-project/src/i18n.js | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../expected/demo-project/src/i18n.js | 2 +- .../demo_10-jsslot/expected/demo-project/src/i18n.js | 2 +- .../demo_11-jsslot-2/expected/demo-project/src/i18n.js | 2 +- 68 files changed, 85 insertions(+), 84 deletions(-) diff --git a/docs/docs/guide/expand/runtime/codeGeneration.md b/docs/docs/guide/expand/runtime/codeGeneration.md index 5cb63c9f64..71cf81bd1c 100644 --- a/docs/docs/guide/expand/runtime/codeGeneration.md +++ b/docs/docs/guide/expand/runtime/codeGeneration.md @@ -23,9 +23,9 @@ sidebar_position: 1 ## 如何使用 ### 1) 通过命令行快速体验 -欢迎使用命令行工具快速体验:`npx @alilc/lowcode-code-generator -i example-schema.json -o generated -s icejs` +欢迎使用命令行工具快速体验:`npx @alilc/lowcode-code-generator -i example-schema.json -o generated -s icejs3` ---其中 example-schema.json 可以从[这里下载](https://unpkg.com/@alilc/lowcode-code-generator@beta/example-schema.json) +--其中 example-schema.json 可以从[这里下载](https://alifd.alicdn.com/npm/@alilc/lowcode-code-generator@latest/example-schema.json) ### 2) 通过设计器插件快速体验 @@ -112,7 +112,7 @@ await CodeGenerator.init(); ```javascript const result = await CodeGenerator.generateCode({ - solution: 'icejs', // 出码方案 (目前内置有 icejs 和 rax ) + solution: 'icejs', // 出码方案 (目前内置有 icejs、icejs3 和 rax ) schema, // 编排搭建出来的 schema }); @@ -124,6 +124,7 @@ console.log(result); // 出码结果 (默认是递归结构描述的,可以传 ### 5)自定义出码 前端框架灵活多变,默认内置的出码方案很难满足所有人的需求,好在此代码生成器支持非常灵活的插件机制 -- 内置功能大多都是通过插件完成的(在 `src/plugins`下),比如: ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01CEl2Hq1omnH0UCyGF_!!6000000005268-2-tps-457-376.png) + 所以您可以通过添加自己的插件或替换掉默认内置的插件来实现您的自定义功能。 为了方便自定义出码方案,出码模块还提供自定义出码方案的脚手架功能,即执行下面脚本即可生成一个自定义出码方案: ```shell diff --git a/docs/docs/specs/lowcode-spec.md b/docs/docs/specs/lowcode-spec.md index 7deeedc2c9..297381fe69 100644 --- a/docs/docs/specs/lowcode-spec.md +++ b/docs/docs/specs/lowcode-spec.md @@ -1370,11 +1370,11 @@ export const recordEvent = function(logkey, gmkey, gokey, reqMethod) { "i18n": { "zh-CN": { "i18n-hello": "你好", - "i18n-chicken": "我有${count}只鸡" + "i18n-chicken": "我有{count}只鸡" }, "en-US": { "i18n-hello": "Hello", - "i18n-chicken": "I have ${count} chicken" + "i18n-chicken": "I have {count} chicken" } } } diff --git a/modules/code-generator/example-schema.json b/modules/code-generator/example-schema.json index 304cf2927d..f41354514b 100644 --- a/modules/code-generator/example-schema.json +++ b/modules/code-generator/example-schema.json @@ -72,7 +72,7 @@ "lifeCycles": { "componentDidMount": { "type": "JSFunction", - "value": "function() { console.log('componentDidMount'); }" + "value": "function componentDidMount() { console.log('componentDidMount'); }" } }, "dataSource": { diff --git a/modules/code-generator/example-schema.json5 b/modules/code-generator/example-schema.json5 index 13fa019b4b..085af24c17 100644 --- a/modules/code-generator/example-schema.json5 +++ b/modules/code-generator/example-schema.json5 @@ -72,7 +72,7 @@ lifeCycles: { componentDidMount: { type: 'JSFunction', - value: "function() { console.log('componentDidMount'); }", + value: "function componentDidMount() { console.log('componentDidMount'); }", }, }, dataSource: { diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/plugins/buildConfig.ts b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/buildConfig.ts index e5eee83d5b..322796154a 100644 --- a/modules/code-generator/src/plugins/project/framework/icejs3/plugins/buildConfig.ts +++ b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/buildConfig.ts @@ -103,7 +103,7 @@ export default defineConfig(() => ({ importStyle: 'sass', themePackage: '${getThemeInfo(cfg.themePackage).name}', }` : `{ - importStyle: true, + importStyle: 'sass', }`}), locales(), plugin(), diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts index 5ac92b550f..dfd00dd3e0 100644 --- a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/src/layouts/BasicLayout/components/Logo/index.style.ts @@ -10,13 +10,13 @@ export default function getFile(): [string[], ResultFile] { display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/src/plugins/project/i18n.ts b/modules/code-generator/src/plugins/project/i18n.ts index ae568f9724..4c36345a5f 100644 --- a/modules/code-generator/src/plugins/project/i18n.ts +++ b/modules/code-generator/src/plugins/project/i18n.ts @@ -41,7 +41,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => ( typeof msg === 'string' - ? msg.replace(/\\\$\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\\\$?\\{(\\w+)\\}/g, (match, key) => variables?.[key] ?? '') : msg ); diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/ice.config.mts index fe77c9b6cd..e1d8a28141 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/ice.config.mts +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/ice.config.mts @@ -81,7 +81,7 @@ export default defineConfig(() => ({ }, plugins: [ fusion({ - importStyle: true, + importStyle: 'sass', }), locales(), plugin(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss index 1ab56d3945..dad05a263f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -3,13 +3,13 @@ display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/ice.config.mts index fe77c9b6cd..e1d8a28141 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/ice.config.mts +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/ice.config.mts @@ -81,7 +81,7 @@ export default defineConfig(() => ({ }, plugins: [ fusion({ - importStyle: true, + importStyle: 'sass', }), locales(), plugin(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss index 1ab56d3945..dad05a263f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -3,13 +3,13 @@ display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/ice.config.mts index fe77c9b6cd..e1d8a28141 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/ice.config.mts +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/ice.config.mts @@ -81,7 +81,7 @@ export default defineConfig(() => ({ }, plugins: [ fusion({ - importStyle: true, + importStyle: 'sass', }), locales(), plugin(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/i18n.js index 2fa87027f5..e8cb58e640 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/i18n.js @@ -28,7 +28,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss index 1ab56d3945..dad05a263f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -3,13 +3,13 @@ display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/ice.config.mts index fe77c9b6cd..e1d8a28141 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/ice.config.mts +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/ice.config.mts @@ -81,7 +81,7 @@ export default defineConfig(() => ({ }, plugins: [ fusion({ - importStyle: true, + importStyle: 'sass', }), locales(), plugin(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/i18n.js index 2fa87027f5..e8cb58e640 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/i18n.js @@ -28,7 +28,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss index 1ab56d3945..dad05a263f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -3,13 +3,13 @@ display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/ice.config.mts index fe77c9b6cd..e1d8a28141 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/ice.config.mts +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/ice.config.mts @@ -81,7 +81,7 @@ export default defineConfig(() => ({ }, plugins: [ fusion({ - importStyle: true, + importStyle: 'sass', }), locales(), plugin(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss index 1ab56d3945..dad05a263f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -3,13 +3,13 @@ display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/ice.config.mts index fe77c9b6cd..e1d8a28141 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/ice.config.mts +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/ice.config.mts @@ -81,7 +81,7 @@ export default defineConfig(() => ({ }, plugins: [ fusion({ - importStyle: true, + importStyle: 'sass', }), locales(), plugin(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss index 1ab56d3945..dad05a263f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -3,13 +3,13 @@ display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/ice.config.mts index fe77c9b6cd..e1d8a28141 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/ice.config.mts +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/ice.config.mts @@ -81,7 +81,7 @@ export default defineConfig(() => ({ }, plugins: [ fusion({ - importStyle: true, + importStyle: 'sass', }), locales(), plugin(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss index 1ab56d3945..dad05a263f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -3,13 +3,13 @@ display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/ice.config.mts index fe77c9b6cd..e1d8a28141 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/ice.config.mts +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/ice.config.mts @@ -81,7 +81,7 @@ export default defineConfig(() => ({ }, plugins: [ fusion({ - importStyle: true, + importStyle: 'sass', }), locales(), plugin(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss index 1ab56d3945..dad05a263f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -3,13 +3,13 @@ display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/ice.config.mts index fe77c9b6cd..e1d8a28141 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/ice.config.mts +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/ice.config.mts @@ -81,7 +81,7 @@ export default defineConfig(() => ({ }, plugins: [ fusion({ - importStyle: true, + importStyle: 'sass', }), locales(), plugin(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss index 1ab56d3945..dad05a263f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -3,13 +3,13 @@ display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/ice.config.mts index fe77c9b6cd..e1d8a28141 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/ice.config.mts +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/ice.config.mts @@ -81,7 +81,7 @@ export default defineConfig(() => ({ }, plugins: [ fusion({ - importStyle: true, + importStyle: 'sass', }), locales(), plugin(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss index 1ab56d3945..dad05a263f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -3,13 +3,13 @@ display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/ice.config.mts index fe77c9b6cd..e1d8a28141 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/ice.config.mts +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/ice.config.mts @@ -81,7 +81,7 @@ export default defineConfig(() => ({ }, plugins: [ fusion({ - importStyle: true, + importStyle: 'sass', }), locales(), plugin(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss index 1ab56d3945..dad05a263f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -3,13 +3,13 @@ display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/ice.config.mts b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/ice.config.mts index fe77c9b6cd..e1d8a28141 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/ice.config.mts +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/ice.config.mts @@ -81,7 +81,7 @@ export default defineConfig(() => ({ }, plugins: [ fusion({ - importStyle: true, + importStyle: 'sass', }), locales(), plugin(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss index 1ab56d3945..dad05a263f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/layouts/BasicLayout/components/Logo/index.module.scss @@ -3,13 +3,13 @@ display: flex; align-items: center; justify-content: center; - color: $color-text1-1; + color: #FF7300; font-weight: bold; font-size: 14px; line-height: 22px; &:visited, &:link { - color: $color-text1-1; + color: #FF7300; } img { diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/i18n.js index 043df6c791..a5dde6f77d 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo01/expected/demo-project/src/i18n.js @@ -14,7 +14,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/i18n.js index 043df6c791..a5dde6f77d 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo02/expected/demo-project/src/i18n.js @@ -14,7 +14,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/i18n.js index 043df6c791..a5dde6f77d 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo03/expected/demo-project/src/i18n.js @@ -14,7 +14,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/i18n.js index 043df6c791..a5dde6f77d 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo04/expected/demo-project/src/i18n.js @@ -14,7 +14,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/i18n.js index f73870fdb0..1ebb554860 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo05/expected/demo-project/src/i18n.js @@ -21,7 +21,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/i18n.js index f73870fdb0..1ebb554860 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo06-jsslot/expected/demo-project/src/i18n.js @@ -21,7 +21,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/i18n.js index f73870fdb0..1ebb554860 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo07-newline-in-props/expected/demo-project/src/i18n.js @@ -21,7 +21,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/i18n.js index f73870fdb0..1ebb554860 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo08-jsslot-with-multiple-children/expected/demo-project/src/i18n.js @@ -21,7 +21,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/i18n.js index f73870fdb0..1ebb554860 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo09-jsslot-with-conditional-children/expected/demo-project/src/i18n.js @@ -21,7 +21,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/i18n.js index f73870fdb0..1ebb554860 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo10-jsslot-with-loop-children/expected/demo-project/src/i18n.js @@ -21,7 +21,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/i18n.js index 043df6c791..a5dde6f77d 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo11-utils-name-alias/expected/demo-project/src/i18n.js @@ -14,7 +14,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/i18n.js index f73870fdb0..1ebb554860 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo12-refs/expected/demo-project/src/i18n.js @@ -21,7 +21,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/i18n.js index 043df6c791..a5dde6f77d 100644 --- a/modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/rax-app/demo13-datasource-prop/expected/demo-project/src/i18n.js @@ -14,7 +14,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => - typeof msg === 'string' ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; + typeof msg === 'string' ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { const msg = i18nConfig[locale]?.[id] ?? i18nConfig[locale.replace('-', '_')]?.[id] ?? defaultMessage; diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2-utils-name-alias/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/i18n.js index 2fa87027f5..e8cb58e640 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/i18n.js @@ -28,7 +28,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/i18n.js index 2fa87027f5..e8cb58e640 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/i18n.js @@ -28,7 +28,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo4/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo5/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo7-literal-condition2/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo8-datasource-prop/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo_10-jsslot/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js b/modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js index adbbe673dc..1334d2502b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo_11-jsslot-2/expected/demo-project/src/i18n.js @@ -19,7 +19,7 @@ const isEmptyVariables = (variables) => // 按低代码规范里面的要求进行变量替换 const format = (msg, variables) => typeof msg === 'string' - ? msg.replace(/\$\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') + ? msg.replace(/\$?\{(\w+)\}/g, (match, key) => variables?.[key] ?? '') : msg; const i18nFormat = ({ id, defaultMessage, fallback }, variables) => { From d0c3c0f13c10a5e9545c680e4a6b12128c0720c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Thu, 30 Mar 2023 11:35:09 +0800 Subject: [PATCH 088/469] feat: add styleImport plugin which handles style import of some fundamental materials --- modules/code-generator/example-schema.json | 4 +- modules/code-generator/example-schema.json5 | 4 +- modules/code-generator/src/index.ts | 23 +++++--- .../src/plugins/common/styleImport.ts | 54 +++++++++++++++++++ modules/code-generator/src/solutions/icejs.ts | 3 ++ .../code-generator/src/solutions/icejs3.ts | 3 ++ .../demo-project/src/pages/Test/index.jsx | 10 ++++ .../demo-project/src/pages/Test/index.jsx | 10 ++++ .../demo-project/src/pages/Test/index.jsx | 14 +++++ .../demo-project/src/pages/Test/index.jsx | 10 ++++ .../demo-project/src/pages/$/index.jsx | 2 + .../demo-project/src/pages/Test/index.jsx | 10 ++++ .../demo-project/src/pages/Test/index.jsx | 10 ++++ .../demo-project/src/pages/Test/index.jsx | 14 +++++ .../demo-project/src/pages/Test/index.jsx | 10 ++++ .../demo-project/src/pages/$/index.jsx | 2 + 16 files changed, 172 insertions(+), 11 deletions(-) create mode 100644 modules/code-generator/src/plugins/common/styleImport.ts diff --git a/modules/code-generator/example-schema.json b/modules/code-generator/example-schema.json index f41354514b..5e31b1bea9 100644 --- a/modules/code-generator/example-schema.json +++ b/modules/code-generator/example-schema.json @@ -62,12 +62,12 @@ "router": "/" }, "props": { - "ref": "outterView", + "ref": "outerView", "autoLoading": true }, "fileName": "test", "state": { - "text": "outter" + "text": "outer" }, "lifeCycles": { "componentDidMount": { diff --git a/modules/code-generator/example-schema.json5 b/modules/code-generator/example-schema.json5 index 085af24c17..4ab02999ec 100644 --- a/modules/code-generator/example-schema.json5 +++ b/modules/code-generator/example-schema.json5 @@ -62,12 +62,12 @@ router: '/', }, props: { - ref: 'outterView', + ref: 'outerView', autoLoading: true, }, fileName: 'test', state: { - text: 'outter', + text: 'outer', }, lifeCycles: { componentDidMount: { diff --git a/modules/code-generator/src/index.ts b/modules/code-generator/src/index.ts index abe0805577..0c8fdf3849 100644 --- a/modules/code-generator/src/index.ts +++ b/modules/code-generator/src/index.ts @@ -8,7 +8,7 @@ import { createProjectBuilder } from './generator/ProjectBuilder'; import { createModuleBuilder } from './generator/ModuleBuilder'; import { createDiskPublisher } from './publisher/disk'; import { createZipPublisher } from './publisher/zip'; -import createIceJsProjectBuilder, { plugins as reactPlugins } from './solutions/icejs'; +import createIceJsProjectBuilder, { plugins as icejsPlugins } from './solutions/icejs'; import createIce3JsProjectBuilder, { plugins as icejs3Plugins } from './solutions/icejs3'; import createRaxAppProjectBuilder, { plugins as raxPlugins } from './solutions/rax-app'; @@ -19,6 +19,7 @@ import { COMMON_CHUNK_NAME, CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from ' // 引入通用插件组 import esmodule from './plugins/common/esmodule'; import requireUtils from './plugins/common/requireUtils'; +import styleImport from './plugins/common/styleImport'; import css from './plugins/component/style/css'; import constants from './plugins/project/constants'; @@ -63,12 +64,7 @@ export default { esmodule, esModule: esmodule, requireUtils, - }, - react: { - ...reactPlugins, - }, - rax: { - ...raxPlugins, + styleImport, }, style: { css, @@ -78,9 +74,22 @@ export default { i18n, utils, }, + icejs: { + ...icejsPlugins, + }, icejs3: { ...icejs3Plugins, }, + rax: { + ...raxPlugins, + }, + + /** + * @deprecated please use icejs + */ + react: { + ...icejsPlugins, + }, }, postprocessor: { prettier, diff --git a/modules/code-generator/src/plugins/common/styleImport.ts b/modules/code-generator/src/plugins/common/styleImport.ts new file mode 100644 index 0000000000..c340900eab --- /dev/null +++ b/modules/code-generator/src/plugins/common/styleImport.ts @@ -0,0 +1,54 @@ +import changeCase from 'change-case'; +import { + FileType, + BuilderComponentPluginFactory, + BuilderComponentPlugin, + ICodeStruct, + IWithDependency, + ChunkType, +} from '../../types'; + +import { COMMON_CHUNK_NAME } from '../../const/generator'; + +const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { + const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => { + const next: ICodeStruct = { + ...pre, + }; + + const ir = next.ir as IWithDependency; + const { chunks } = next; + + if (ir && ir.deps && ir.deps.length > 0) { + let lowcodeMaterialsStyleAdded = false; + let nextStyleAddedMap: Record<string, boolean> = {}; + ir.deps.forEach((dep: any) => { + if (dep.package === '@alifd/next' && !nextStyleAddedMap[dep.exportName]) { + chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: `import '@alifd/next/lib/${changeCase.paramCase(dep.exportName)}/style';`, + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + nextStyleAddedMap[dep.exportName] = true; + } else if (dep.package === '@alilc/lowcode-materials' && !lowcodeMaterialsStyleAdded) { + chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: 'import \'@alilc/lowcode-materials/lib/style\';', + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + lowcodeMaterialsStyleAdded = true; + } + }); + } + + return next; + }; + + return plugin; +}; + +export default pluginFactory; diff --git a/modules/code-generator/src/solutions/icejs.ts b/modules/code-generator/src/solutions/icejs.ts index 1b3dec4af7..6f5bdde599 100644 --- a/modules/code-generator/src/solutions/icejs.ts +++ b/modules/code-generator/src/solutions/icejs.ts @@ -3,6 +3,7 @@ import { IProjectBuilder, IProjectBuilderOptions } from '../types'; import { createProjectBuilder } from '../generator/ProjectBuilder'; import esmodule from '../plugins/common/esmodule'; +import styleImport from '../plugins/common/styleImport'; import containerClass from '../plugins/component/react/containerClass'; import containerInitState from '../plugins/component/react/containerInitState'; import containerInjectContext from '../plugins/component/react/containerInjectContext'; @@ -38,6 +39,7 @@ export default function createIceJsProjectBuilder( esmodule({ fileType: 'jsx', }), + styleImport(), containerClass(), containerInjectContext(), containerInjectUtils(), @@ -61,6 +63,7 @@ export default function createIceJsProjectBuilder( esmodule({ fileType: 'jsx', }), + styleImport(), containerClass(), containerInjectContext(), containerInjectUtils(), diff --git a/modules/code-generator/src/solutions/icejs3.ts b/modules/code-generator/src/solutions/icejs3.ts index 26128a9eb9..c6870dfd07 100644 --- a/modules/code-generator/src/solutions/icejs3.ts +++ b/modules/code-generator/src/solutions/icejs3.ts @@ -3,6 +3,7 @@ import { IProjectBuilder, IProjectBuilderOptions } from '../types'; import { createProjectBuilder } from '../generator/ProjectBuilder'; import esmodule from '../plugins/common/esmodule'; +import styleImport from '../plugins/common/styleImport'; import containerClass from '../plugins/component/react/containerClass'; import containerInitState from '../plugins/component/react/containerInitState'; import containerInjectContext from '../plugins/component/react/containerInjectContext'; @@ -38,6 +39,7 @@ export default function createIceJsProjectBuilder( esmodule({ fileType: 'jsx', }), + styleImport(), containerClass(), containerInjectContext(), containerInjectUtils(), @@ -61,6 +63,7 @@ export default function createIceJsProjectBuilder( esmodule({ fileType: 'jsx', }), + styleImport(), containerClass(), containerInjectContext(), containerInjectUtils(), diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.jsx index 070020b746..794ad46a48 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/pages/Test/index.jsx @@ -10,6 +10,16 @@ import { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowc import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime'; +import '@alifd/next/lib/form/style'; + +import '@alifd/next/lib/input/style'; + +import '@alifd/next/lib/number-picker/style'; + +import '@alifd/next/lib/select/style'; + +import '@alifd/next/lib/button/style'; + import utils, { RefsManager } from '../../utils'; import * as __$$i18n from '../../i18n'; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.jsx index 6cb430b1b8..080c4245b6 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/pages/Test/index.jsx @@ -4,6 +4,16 @@ import React from 'react'; import { Form, Input, NumberPicker, Select, Button } from '@alifd/next'; +import '@alifd/next/lib/form/style'; + +import '@alifd/next/lib/input/style'; + +import '@alifd/next/lib/number-picker/style'; + +import '@alifd/next/lib/select/style'; + +import '@alifd/next/lib/button/style'; + import utils, { RefsManager } from '../../utils'; import * as __$$i18n from '../../i18n'; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.jsx index 18c5e0a57a..2f0a6efa9a 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/pages/Test/index.jsx @@ -13,6 +13,20 @@ import Super, { import SuperOther from '@alifd/next'; +import '@alifd/next/lib/super/style'; + +import '@alifd/next/lib/button/style'; + +import '@alifd/next/lib/input/style'; + +import '@alifd/next/lib/form/style'; + +import '@alifd/next/lib/number-picker/style'; + +import '@alifd/next/lib/select/style'; + +import '@alifd/next/lib/search-table/style'; + import utils from '../../utils'; import * as __$$i18n from '../../i18n'; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx index c27cce1532..515940c334 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx @@ -10,6 +10,16 @@ import { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowc import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime'; +import '@alifd/next/lib/form/style'; + +import '@alifd/next/lib/input/style'; + +import '@alifd/next/lib/number-picker/style'; + +import '@alifd/next/lib/select/style'; + +import '@alifd/next/lib/button/style'; + import utils, { RefsManager } from '../../utils'; import * as __$$i18n from '../../i18n'; diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx index 1f2bf90418..799ca0d28f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx @@ -8,6 +8,8 @@ import { createJsonpHandler as __$$createJsonpRequestHandler } from '@alilc/lowc import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime'; +import '@alifd/next/lib/switch/style'; + import utils from '../../utils'; import * as __$$i18n from '../../i18n'; diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/pages/Test/index.jsx index 070020b746..794ad46a48 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo1/expected/demo-project/src/pages/Test/index.jsx @@ -10,6 +10,16 @@ import { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowc import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime'; +import '@alifd/next/lib/form/style'; + +import '@alifd/next/lib/input/style'; + +import '@alifd/next/lib/number-picker/style'; + +import '@alifd/next/lib/select/style'; + +import '@alifd/next/lib/button/style'; + import utils, { RefsManager } from '../../utils'; import * as __$$i18n from '../../i18n'; diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/pages/Test/index.jsx index 6cb430b1b8..080c4245b6 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo2/expected/demo-project/src/pages/Test/index.jsx @@ -4,6 +4,16 @@ import React from 'react'; import { Form, Input, NumberPicker, Select, Button } from '@alifd/next'; +import '@alifd/next/lib/form/style'; + +import '@alifd/next/lib/input/style'; + +import '@alifd/next/lib/number-picker/style'; + +import '@alifd/next/lib/select/style'; + +import '@alifd/next/lib/button/style'; + import utils, { RefsManager } from '../../utils'; import * as __$$i18n from '../../i18n'; diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/pages/Test/index.jsx index 18c5e0a57a..2f0a6efa9a 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo3/expected/demo-project/src/pages/Test/index.jsx @@ -13,6 +13,20 @@ import Super, { import SuperOther from '@alifd/next'; +import '@alifd/next/lib/super/style'; + +import '@alifd/next/lib/button/style'; + +import '@alifd/next/lib/input/style'; + +import '@alifd/next/lib/form/style'; + +import '@alifd/next/lib/number-picker/style'; + +import '@alifd/next/lib/select/style'; + +import '@alifd/next/lib/search-table/style'; + import utils from '../../utils'; import * as __$$i18n from '../../i18n'; diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx index c27cce1532..515940c334 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo6-literal-condition/expected/demo-project/src/pages/Test/index.jsx @@ -10,6 +10,16 @@ import { createFetchHandler as __$$createFetchRequestHandler } from '@alilc/lowc import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime'; +import '@alifd/next/lib/form/style'; + +import '@alifd/next/lib/input/style'; + +import '@alifd/next/lib/number-picker/style'; + +import '@alifd/next/lib/select/style'; + +import '@alifd/next/lib/button/style'; + import utils, { RefsManager } from '../../utils'; import * as __$$i18n from '../../i18n'; diff --git a/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx b/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx index 1f2bf90418..799ca0d28f 100644 --- a/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx +++ b/modules/code-generator/tests/fixtures/test-cases/react-app/demo9-datasource-engine/expected/demo-project/src/pages/$/index.jsx @@ -8,6 +8,8 @@ import { createJsonpHandler as __$$createJsonpRequestHandler } from '@alilc/lowc import { create as __$$createDataSourceEngine } from '@alilc/lowcode-datasource-engine/runtime'; +import '@alifd/next/lib/switch/style'; + import utils from '../../utils'; import * as __$$i18n from '../../i18n'; From d64da1e065aa814d221317beead9c9e32f874472 Mon Sep 17 00:00:00 2001 From: eternalsky <wsj7552715@hotmail.com> Date: Fri, 31 Mar 2023 15:12:39 +0800 Subject: [PATCH 089/469] feat: improve lowcode component error state in simulator renderer (#1818) * feat: improve lowcode component error state in simulator renderer * chore: use faultComponentMap instead of ComponentRender.FaultComponent --- .eslintrc.js | 4 +- .../designer/src/builtin-simulator/host.ts | 4 ++ .../src/renderer-view.tsx | 1 + .../react-simulator-renderer/src/renderer.ts | 2 + packages/renderer-core/src/renderer/base.tsx | 8 ++-- .../renderer-core/src/renderer/renderer.tsx | 42 ++++++++++++------- packages/renderer-core/src/types/index.ts | 6 +++ packages/renderer-core/src/utils/common.ts | 37 ++++++++++++++-- 8 files changed, 82 insertions(+), 22 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 4d573688f5..972882ce73 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -52,6 +52,8 @@ module.exports = { 'error', { default: ['signature', 'field', 'constructor', 'method'] } ], - '@typescript-eslint/no-unused-vars': ['error'] + '@typescript-eslint/no-unused-vars': ['error'], + 'no-redeclare': 0, + '@typescript-eslint/no-redeclare': 1, }, }; diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 91ab1a17b5..fdf26c06c1 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -234,6 +234,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp return engineConfig.get('faultComponent') ?? null; } + get faultComponentMap(): any { + return engineConfig.get('faultComponentMap') ?? null; + } + @computed get componentsAsset(): Asset | undefined { return this.get('componentsAsset'); } diff --git a/packages/react-simulator-renderer/src/renderer-view.tsx b/packages/react-simulator-renderer/src/renderer-view.tsx index e8c7ce52e6..aa1683cd22 100644 --- a/packages/react-simulator-renderer/src/renderer-view.tsx +++ b/packages/react-simulator-renderer/src/renderer-view.tsx @@ -195,6 +195,7 @@ class Renderer extends Component<{ thisRequiredInJSE={host.thisRequiredInJSE} notFoundComponent={host.notFoundComponent} faultComponent={host.faultComponent} + faultComponentMap={host.faultComponentMap} customCreateElement={(Component: any, props: any, children: any) => { const { __id, ...viewProps } = props; viewProps.componentId = __id; diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index b3ba1df247..efebeda040 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -465,6 +465,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { rendererName: 'LowCodeRenderer', thisRequiredInJSE: host.thisRequiredInJSE, faultComponent: host.faultComponent, + faultComponentMap: host.faultComponentMap, customCreateElement: (Comp: any, props: any, children: any) => { const componentMeta = host.currentDocument?.getComponentMeta(Comp.displayName); if (componentMeta?.isModal) { @@ -629,6 +630,7 @@ function getLowCodeComponentProps(props: any) { } newProps[k] = props[k]; }); + newProps['componentName'] = props['_componentName']; return newProps; } diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index a965549086..56f58599b0 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -161,7 +161,9 @@ export default function baseRendererFactory(): IBaseRenderComponent { constructor(props: IBaseRendererProps, context: IBaseRendererContext) { super(props, context); this.context = context; - this.__parseExpression = props?.thisRequiredInJSE ? parseThisRequiredExpression : parseExpression; + this.__parseExpression = (str: string, self: any) => { + return parseExpression({ str, self, thisRequired: props?.thisRequiredInJSE, logScope: props.componentName }); + }; this.__beforeInit(props); this.__init(props); this.__afterInit(props); @@ -299,8 +301,8 @@ export default function baseRendererFactory(): IBaseRenderComponent { }; __parseData = (data: any, ctx?: Record<string, any>) => { - const { __ctx, thisRequiredInJSE } = this.props; - return parseData(data, ctx || __ctx || this, { thisRequiredInJSE }); + const { __ctx, thisRequiredInJSE, componentName } = this.props; + return parseData(data, ctx || __ctx || this, { thisRequiredInJSE, logScope: componentName }); }; __initDataSource = (props: IBaseRendererProps) => { diff --git a/packages/renderer-core/src/renderer/renderer.tsx b/packages/renderer-core/src/renderer/renderer.tsx index 4968f269a2..88cc0ce025 100644 --- a/packages/renderer-core/src/renderer/renderer.tsx +++ b/packages/renderer-core/src/renderer/renderer.tsx @@ -21,7 +21,7 @@ export default function rendererFactory(): IRenderComponent { class FaultComponent extends PureComponent<IPublicTypeNodeSchema | any> { render() { - logger.error(`%c组件渲染异常, 异常原因: ${this.props.error?.message || this.props.error || '未知'}`, 'color: #ff0000;'); + logger.error(`%c${this.props.componentName || ''} 组件渲染异常, 异常原因: ${this.props.error?.message || this.props.error || '未知'}`, 'color: #ff0000;'); return createElement(Div, { style: { width: '100%', @@ -159,7 +159,25 @@ export default function rendererFactory(): IRenderComponent { } getFaultComponent() { - return this.props.faultComponent || FaultComponent; + const { faultComponent, faultComponentMap, schema } = this.props; + if (faultComponentMap) { + const { componentName } = schema; + return faultComponentMap[componentName] || faultComponent || FaultComponent; + } + return faultComponent || FaultComponent; + } + + getComp() { + const { schema, components } = this.props; + const { componentName } = schema; + const allComponents = { ...RENDERER_COMPS, ...components }; + let Comp = allComponents[componentName] || RENDERER_COMPS[`${componentName}Renderer`]; + if (Comp && Comp.prototype) { + if (!(Comp.prototype instanceof BaseRenderer)) { + Comp = RENDERER_COMPS[`${componentName}Renderer`]; + } + } + return Comp; } render() { @@ -173,14 +191,8 @@ export default function rendererFactory(): IRenderComponent { return '模型结构异常'; } debug('entry.render'); - const { componentName } = schema; const allComponents = { ...RENDERER_COMPS, ...components }; - let Comp = allComponents[componentName] || RENDERER_COMPS[`${componentName}Renderer`]; - if (Comp && Comp.prototype) { - if (!(Comp.prototype instanceof BaseRenderer)) { - Comp = RENDERER_COMPS[`${componentName}Renderer`]; - } - } + let Comp = this.getComp(); if (this.state && this.state.engineRenderError) { return createElement(this.getFaultComponent(), { @@ -190,11 +202,13 @@ export default function rendererFactory(): IRenderComponent { } if (Comp) { - return createElement(AppContext.Provider, { value: { - appHelper, - components: allComponents, - engine: this, - } }, createElement(ConfigProvider, { + return createElement(AppContext.Provider, { + value: { + appHelper, + components: allComponents, + engine: this, + }, + }, createElement(ConfigProvider, { device: this.props.device, locale: this.props.locale, }, createElement(Comp, { diff --git a/packages/renderer-core/src/types/index.ts b/packages/renderer-core/src/types/index.ts index 067bf21533..a49fe89920 100644 --- a/packages/renderer-core/src/types/index.ts +++ b/packages/renderer-core/src/types/index.ts @@ -160,6 +160,11 @@ export interface IRendererProps { /** 当组件渲染异常时,显示的组件 */ faultComponent?: IGeneralComponent; + /** */ + faultComponentMap?: { + [prop: string]: IGeneralComponent; + }; + /** 设备信息 */ device?: string; @@ -208,6 +213,7 @@ export interface IBaseRendererProps { * 设备类型,默认值:'default' */ device?: 'default' | 'mobile' | string; + componentName?: string; } export interface INodeInfo { diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts index f2cfc1300b..29381b5473 100644 --- a/packages/renderer-core/src/utils/common.ts +++ b/packages/renderer-core/src/utils/common.ts @@ -157,6 +157,7 @@ export function canAcceptsRef(Comp: any) { // eslint-disable-next-line max-len return Comp?.$$typeof === REACT_FORWARD_REF_TYPE || Comp?.prototype?.isReactComponent || Comp?.prototype?.setState || Comp._forwardRef; } + /** * transform array to a object * @param arr array to be transformed @@ -207,7 +208,6 @@ export function checkPropTypes(value: any, name: string, rule: any, componentNam return !err; } - /** * transform string to a function * @param str function in string form @@ -230,7 +230,26 @@ export function transformStringToFunction(str: string) { * @param self scope object * @returns funtion */ -export function parseExpression(str: any, self: any, thisRequired = false) { + +function parseExpression(options: { + str: any; self: any; thisRequired?: boolean; logScope?: string; +}): any; +function parseExpression(str: any, self: any, thisRequired?: boolean): any; +function parseExpression(a: any, b?: any, c = false) { + let str; + let self; + let thisRequired; + let logScope; + if (typeof a === 'object' && b === undefined) { + str = a.str; + self = a.self; + thisRequired = a.thisRequired; + logScope = a.logScope; + } else { + str = a; + self = b; + thisRequired = c; + } try { const contextArr = ['"use strict";', 'var __self = arguments[0];']; contextArr.push('return '); @@ -250,11 +269,15 @@ export function parseExpression(str: any, self: any, thisRequired = false) { const code = `with(${thisRequired ? '{}' : '$scope || {}'}) { ${tarStr} }`; return new Function('$scope', code)(self); } catch (err) { - logger.error('parseExpression.error', err, str, self?.__self ?? self); + logger.error(`${logScope || ''} parseExpression.error`, err, str, self?.__self ?? self); return undefined; } } +export { + parseExpression, +}; + export function parseThisRequiredExpression(str: any, self: any) { return parseExpression(str, self, true); } @@ -320,11 +343,17 @@ export function forEach(targetObj: any, fn: any, context?: any) { interface IParseOptions { thisRequiredInJSE?: boolean; + logScope?: string; } export function parseData(schema: unknown, self: any, options: IParseOptions = {}): any { if (isJSExpression(schema)) { - return parseExpression(schema, self, options.thisRequiredInJSE); + return parseExpression({ + str: schema, + self, + thisRequired: options.thisRequiredInJSE, + logScope: options.logScope, + }); } else if (isI18nData(schema)) { return parseI18n(schema, self); } else if (typeof schema === 'string') { From 4bb4296229586617736ef684c35148a09b394776 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 31 Mar 2023 10:58:55 +0800 Subject: [PATCH 090/469] fix: when the setting-field value is array, the observer invalid --- .../designer/src/document/node/props/prop.ts | 15 ++++- .../designer/setting/setting-field.test.ts | 61 +++++++++++++++++++ packages/designer/tests/fixtures/window.ts | 2 +- 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 74e93c1063..7678ee3468 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -162,12 +162,21 @@ export class Prop implements IProp, IPropParent { return runInAction(() => { let items: IProp[] | null = null; if (this._type === 'list') { + const maps = new Map<string, IProp>(); const data = this._value; data.forEach((item: any, idx: number) => { items = items || []; - items.push(new Prop(this, item, idx)); + let prop; + if (this._prevMaps?.has(idx.toString())) { + prop = this._prevMaps.get(idx.toString())!; + prop.setValue(item); + } else { + prop = new Prop(this, item, idx); + } + maps.set(idx.toString(), prop); + items.push(prop); }); - this._maps = null; + this._maps = maps; } else if (this._type === 'map') { const data = this._value; const maps = new Map<string, IProp>(); @@ -377,6 +386,8 @@ export class Prop implements IProp, IPropParent { } this.dispose(); + // setValue 的时候,如果不重新建立 items,items 的 setValue 没有触发,会导致子项的响应式逻辑不能被触发 + this.setupItems(); if (oldValue !== this._value) { const propsInfo = { diff --git a/packages/designer/tests/designer/setting/setting-field.test.ts b/packages/designer/tests/designer/setting/setting-field.test.ts index 9114d2577a..f79bc98764 100644 --- a/packages/designer/tests/designer/setting/setting-field.test.ts +++ b/packages/designer/tests/designer/setting/setting-field.test.ts @@ -182,5 +182,66 @@ describe('setting-field 测试', () => { expect(mockFn).toHaveBeenCalled(); }); + + it('autorun', async () => { + const settingEntry = mockNode.settingEntry as SettingTopEntry; + const arrField = settingEntry.get('columns'); + const subArrField = arrField.createField({ + name: 0, + title: 'sub', + }); + const objSubField = subArrField.createField({ + name: 'objSub', + title: 'objSub', + }); + const mockFnArrField = jest.fn(); + const mockFnSubArrField = jest.fn(); + const mockFnObjSubField = jest.fn(); + + arrField.setValue([{ objSub: "subMock0.Index.0" }]); + // 这里需要 setValue 两遍,触发 prop 的 purge 方法,使 purged 为 true,之后的 purge 方法不会正常执行,prop 才能正常缓存,autorun 才能正常执行 + // TODO: 该机制后续得研究一下,再确定是否要修改 + arrField.setValue([{ objSub: "subMock0.Index.0" }]); + + arrField.onEffect(() => { + mockFnArrField(arrField.getValue()); + }); + arrField.onEffect(() => { + mockFnSubArrField(subArrField.getValue()); + }); + arrField.onEffect(() => { + mockFnObjSubField(objSubField.getValue()); + }); + + await delayObxTick(); + + expect(mockFnObjSubField).toHaveBeenCalledWith('subMock0.Index.0'); + expect(mockFnSubArrField).toHaveBeenCalledWith({ objSub: "subMock0.Index.0" }); + expect(mockFnArrField).toHaveBeenCalledWith([{ objSub: "subMock0.Index.0" }]); + + arrField.setValue([{ objSub: "subMock0.Index.1" }]); + + await delayObxTick(); + + expect(mockFnObjSubField).toHaveBeenCalledWith('subMock0.Index.1'); + expect(mockFnSubArrField).toHaveBeenCalledWith({ objSub: "subMock0.Index.1" }); + expect(mockFnArrField).toHaveBeenCalledWith([{ objSub: "subMock0.Index.1" }]); + + subArrField.setValue({ objSub: "subMock0.Index.2" }); + + await delayObxTick(); + + expect(mockFnObjSubField).toHaveBeenCalledWith('subMock0.Index.2'); + expect(mockFnSubArrField).toHaveBeenCalledWith({ objSub: "subMock0.Index.2" }); + expect(mockFnArrField).toHaveBeenCalledWith([{ objSub: "subMock0.Index.2" }]); + + objSubField.setValue('subMock0.Index.3'); + + await delayObxTick(); + + expect(mockFnObjSubField).toHaveBeenCalledWith('subMock0.Index.3'); + expect(mockFnSubArrField).toHaveBeenCalledWith({ objSub: "subMock0.Index.3" }); + expect(mockFnArrField).toHaveBeenCalledWith([{ objSub: "subMock0.Index.3" }]); + }) }); }); diff --git a/packages/designer/tests/fixtures/window.ts b/packages/designer/tests/fixtures/window.ts index 6f3e03a884..c57fcb6869 100644 --- a/packages/designer/tests/fixtures/window.ts +++ b/packages/designer/tests/fixtures/window.ts @@ -22,7 +22,7 @@ window.console.warn = () => {}; const originalLog = window.console.log; window.console.log = (...args) => { // suppress boring warnings - if (args[0].includes('@babel/plugin-proposal-private-property-in-object')) return; + if (args[0]?.includes && args[0].includes('@babel/plugin-proposal-private-property-in-object')) return; originalLog.apply(window.console, args); }; window.React = window.React || {}; From aafd57cae2438c936c019934cd572648a79c3e1c Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 31 Mar 2023 17:04:49 +0800 Subject: [PATCH 091/469] feat: JSSlot prop export result add id --- packages/designer/src/document/node/props/prop.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 7678ee3468..b1fd1aec48 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -302,6 +302,7 @@ export class Prop implements IProp, IPropParent { type: 'JSSlot', params: schema.params, value: schema, + id: schema.id, }; } return { @@ -310,6 +311,7 @@ export class Prop implements IProp, IPropParent { value: schema.children, title: schema.title, name: schema.name, + id: schema.id, }; } From 4f7a0b984c50b133807352a953437dcac757fa40 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 31 Mar 2023 18:00:43 +0800 Subject: [PATCH 092/469] fix: change autorun params to IPublicModelSettingField --- packages/designer/jest.config.js | 2 ++ packages/designer/src/designer/setting/utils.ts | 4 ++-- packages/designer/src/document/node/node.ts | 3 +-- packages/designer/tests/document/node/node.test.ts | 11 ++++++++++- packages/engine/src/inner-plugins/builtin-hotkey.ts | 9 ++++----- packages/types/src/shell/type/metadata.ts | 4 ++-- 6 files changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index 05347a0c95..82c76fad88 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -17,6 +17,8 @@ const jestConfig = { // testMatch: ['(/tests?/.*(test))\\.[jt]s$'], // testMatch: ['**/document/node/node.add.test.ts'], // testMatch: ['**/setting-field.test.ts'], + // testMatch: ['**/node.test.ts'], + // testMatch: ['**/builtin-hotkey.test.ts'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], diff --git a/packages/designer/src/designer/setting/utils.ts b/packages/designer/src/designer/setting/utils.ts index 98e5d3b6be..1e061f20ae 100644 --- a/packages/designer/src/designer/setting/utils.ts +++ b/packages/designer/src/designer/setting/utils.ts @@ -2,7 +2,7 @@ import { isValidElement } from 'react'; import { IPublicTypeFieldConfig, IPublicTypeSetterConfig } from '@alilc/lowcode-types'; import { isSetterConfig, isDynamicSetter } from '@alilc/lowcode-utils'; -import { SettingField } from './setting-field'; +import { ISettingField } from './setting-field'; function getHotterFromSetter(setter) { return setter && (setter.Hotter || (setter.type && setter.type.Hotter)) || []; // eslint-disable-line @@ -35,7 +35,7 @@ export class Transducer { context: any; - constructor(context: SettingField, config: { setter: IPublicTypeFieldConfig['setter'] }) { + constructor(context: ISettingField, config: { setter: IPublicTypeFieldConfig['setter'] }) { let { setter } = config; // 1. validElement diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index e1dce17dda..456595b048 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -30,7 +30,6 @@ import type { IExclusiveGroup } from './exclusive-group'; import { includeSlot, removeSlot } from '../../utils/slot'; import { foreachReverse } from '../../utils/tree'; import { NodeRemoveOptions, EDITOR_EVENT } from '../../types'; -import { Prop as ShellProp } from '@alilc/lowcode-shell'; export interface NodeStatus { locking: boolean; @@ -432,7 +431,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> } this.autoruns = autoruns.map((item) => { return autorun(() => { - item.autorun(ShellProp.create(this.props.get(item.name, true))!); + item.autorun(this.props.getNode().settingEntry.get(item.name)?.internalToShellField()); }); }); } diff --git a/packages/designer/tests/document/node/node.test.ts b/packages/designer/tests/document/node/node.test.ts index e0be159ff7..c4717b3a02 100644 --- a/packages/designer/tests/document/node/node.test.ts +++ b/packages/designer/tests/document/node/node.test.ts @@ -1,8 +1,13 @@ // @ts-nocheck import '../../fixtures/window'; import { set } from '../../utils'; -import { Editor } from '@alilc/lowcode-editor-core'; +import { + Editor, + globalContext, + Setters as InnerSetters, +} from '@alilc/lowcode-editor-core'; import { Project } from '../../../src/project/project'; +import { Workspace as InnerWorkspace } from '@alilc/lowcode-workspace'; import { DocumentModel } from '../../../src/document/document-model'; import { isRootNode, @@ -23,6 +28,7 @@ import rootContentMetadata from '../../fixtures/component-metadata/root-content' import rootFooterMetadata from '../../fixtures/component-metadata/root-footer'; import { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory'; import { isNode } from '@alilc/lowcode-utils'; +import { Setters } from '@alilc/lowcode-shell'; describe('Node 方法测试', () => { let editor: Editor; @@ -35,6 +41,9 @@ describe('Node 方法测试', () => { designer = new Designer({ editor, shellModelFactory }); project = designer.project; doc = new DocumentModel(project, formSchema); + editor.set('setters', new Setters(new InnerSetters())); + !globalContext.has(Editor) && globalContext.register(editor, Editor); + !globalContext.has('workspace') && globalContext.register(new InnerWorkspace(), 'workspace'); }); afterEach(() => { diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index 73aac64aab..692773a756 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -176,10 +176,9 @@ function getSuitablePlaceForNode(targetNode: IPublicModelNode, node: IPublicMode if (node?.componentMeta?.isModal) { return { container: focusNode, ref }; } - const canDropInFn = document.checkNesting; if (!ref && focusNode && targetNode.contains(focusNode)) { - if (canDropInFn(focusNode, dragNodeObject)) { + if (document.checkNesting(focusNode, dragNodeObject)) { return { container: focusNode }; } @@ -191,7 +190,7 @@ function getSuitablePlaceForNode(targetNode: IPublicModelNode, node: IPublicMode if (!c.isContainerNode) { return false; } - if (canDropInFn(c, dragNodeObject)) { + if (document.checkNesting(c, dragNodeObject)) { return true; } return false; @@ -201,7 +200,7 @@ function getSuitablePlaceForNode(targetNode: IPublicModelNode, node: IPublicMode return { container: dropElement, ref }; } - if (canDropInFn(targetNode, dragNodeObject)) { + if (document.checkNesting(targetNode, dragNodeObject)) { return { container: targetNode, ref }; } @@ -209,7 +208,7 @@ function getSuitablePlaceForNode(targetNode: IPublicModelNode, node: IPublicMode } if (targetNode.isContainerNode) { - if (canDropInFn(targetNode, dragNodeObject)) { + if (document.checkNesting(targetNode, dragNodeObject)) { return { container: targetNode, ref }; } } diff --git a/packages/types/src/shell/type/metadata.ts b/packages/types/src/shell/type/metadata.ts index 2815557a52..3122ab7d7d 100644 --- a/packages/types/src/shell/type/metadata.ts +++ b/packages/types/src/shell/type/metadata.ts @@ -1,6 +1,6 @@ import { MouseEvent } from 'react'; import { IPublicTypePropType, IPublicTypeComponentAction } from './'; -import { IPublicModelNode, IPublicModelProp, IPublicModelSettingField } from '../model'; +import { IPublicModelNode, IPublicModelSettingField } from '../model'; /** * 嵌套控制函数 @@ -102,7 +102,7 @@ export interface IPublicTypeFilterItem { } export interface IPublicTypeAutorunItem { name: string; - autorun: (prop: IPublicModelProp) => any; + autorun: (target: IPublicModelSettingField | null) => any; } // thinkof Array From e1864fdf711821f1c581c61f40e4f07e08f0a647 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 3 Apr 2023 17:15:22 +0800 Subject: [PATCH 093/469] feat: field suport change JSExpression value --- .../src/designer/setting/setting-field.ts | 54 +++++++++++-------- .../designer/setting/setting-field.test.ts | 34 ++++++++++++ 2 files changed, 67 insertions(+), 21 deletions(-) diff --git a/packages/designer/src/designer/setting/setting-field.ts b/packages/designer/src/designer/setting/setting-field.ts index 139373c0bf..1a63fb7a40 100644 --- a/packages/designer/src/designer/setting/setting-field.ts +++ b/packages/designer/src/designer/setting/setting-field.ts @@ -16,7 +16,7 @@ import type { import { Transducer } from './utils'; import { ISettingPropEntry, SettingPropEntry } from './setting-prop-entry'; import { computed, obx, makeObservable, action, untracked, intl } from '@alilc/lowcode-editor-core'; -import { cloneDeep, isCustomView, isDynamicSetter } from '@alilc/lowcode-utils'; +import { cloneDeep, isCustomView, isDynamicSetter, isJSExpression } from '@alilc/lowcode-utils'; import { ISettingTopEntry } from './setting-top-entry'; import { IComponentMeta, INode } from '@alilc/lowcode-designer'; @@ -38,28 +38,28 @@ export interface ISettingField extends ISettingPropEntry, Omit<IBaseModelSetting IComponentMeta, INode >, 'setValue' | 'key' | 'node'> { - get items(): Array<ISettingField | IPublicTypeCustomView>; - - get title(): string | ReactNode | undefined; - readonly isSettingField: true; - purge(): void; + readonly isRequired: boolean; + + readonly isGroup: boolean; extraProps: IPublicTypeFieldExtraProps; - get setter(): IPublicTypeSetterType | null; + get items(): Array<ISettingField | IPublicTypeCustomView>; - get expanded(): boolean; + get title(): string | ReactNode | undefined; - readonly isRequired: boolean; + get setter(): IPublicTypeSetterType | null; - readonly isGroup: boolean; + get expanded(): boolean; get valueState(): number; setExpanded(value: boolean): void; + purge(): void; + setValue( val: any, isHotValue?: boolean, @@ -271,16 +271,29 @@ export class SettingField extends SettingPropEntry implements ISettingField { } if (this.isUseVariable()) { const oldValue = this.getValue(); - this.setValue( - { - type: 'JSExpression', - value: oldValue.value, - mock: value, - }, - false, - false, - options, - ); + if (isJSExpression(value)) { + this.setValue( + { + type: 'JSExpression', + value: value.value, + mock: oldValue.mock, + }, + false, + false, + options, + ); + } else { + this.setValue( + { + type: 'JSExpression', + value: oldValue.value, + mock: value, + }, + false, + false, + options, + ); + } } else { this.setValue(value, false, false, options); } @@ -297,7 +310,6 @@ export class SettingField extends SettingPropEntry implements ISettingField { return this.designer!.autorun(action, true); } - internalToShellField() { return this.designer!.shellModelFactory.createSettingField(this); } diff --git a/packages/designer/tests/designer/setting/setting-field.test.ts b/packages/designer/tests/designer/setting/setting-field.test.ts index f79bc98764..53ed2829df 100644 --- a/packages/designer/tests/designer/setting/setting-field.test.ts +++ b/packages/designer/tests/designer/setting/setting-field.test.ts @@ -168,6 +168,40 @@ describe('setting-field 测试', () => { expect(arrField.getHotValue()).toEqual([undefined, {name: '2'}, {name: '3'}]); }); + it('js expression setValue / setHotValue', () => { + const settingEntry = mockNode.settingEntry; + const field = settingEntry.get('behavior'); + + const subField = field.createField({ + name: 'sub', + title: 'sub', + }); + subField.setValue({ + type: 'JSExpression', + value: 'state.a', + mock: 'haha', + }); + + subField.setHotValue({ + type: 'JSExpression', + value: 'state.b', + }); + + expect(subField.getValue()).toEqual({ + type: 'JSExpression', + value: 'state.b', + mock: 'haha', + }); + + subField.setHotValue('mock02'); + + expect(subField.getValue()).toEqual({ + type: 'JSExpression', + value: 'state.b', + mock: 'mock02', + }); + }); + it('onEffect', async () => { const settingEntry = mockNode.settingEntry as SettingTopEntry; const field = settingEntry.get('behavior'); From ed252fa13577301c4d66ed7cb54959874c21981f Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 4 Apr 2023 11:07:42 +0800 Subject: [PATCH 094/469] fix: fix composeTitle returns redundant icons --- .github/workflows/test packages.yml | 18 ++++++- packages/editor-skeleton/build.test.json | 9 ++++ packages/editor-skeleton/jest.config.js | 29 ++++++++++ packages/editor-skeleton/package.json | 1 + packages/editor-skeleton/src/widget/utils.ts | 2 +- .../tests/widget/utils.test.ts | 54 +++++++++++++++++++ .../src/shell/type/widget-base-config.ts | 10 ++++ 7 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 packages/editor-skeleton/build.test.json create mode 100644 packages/editor-skeleton/jest.config.js create mode 100644 packages/editor-skeleton/tests/widget/utils.test.ts diff --git a/.github/workflows/test packages.yml b/.github/workflows/test packages.yml index cc05742d54..484ef849a2 100644 --- a/.github/workflows/test packages.yml +++ b/.github/workflows/test packages.yml @@ -41,4 +41,20 @@ jobs: run: npm i && npm run setup:skip-build - name: test - run: cd packages/designer && npm test \ No newline at end of file + run: cd packages/designer && npm test + + 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 \ No newline at end of file diff --git a/packages/editor-skeleton/build.test.json b/packages/editor-skeleton/build.test.json new file mode 100644 index 0000000000..45f0dbdfd3 --- /dev/null +++ b/packages/editor-skeleton/build.test.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + "build-plugin-component", + "@alilc/lowcode-test-mate/plugin/index.ts" + ], + "babelPlugins": [ + ["@babel/plugin-proposal-private-property-in-object", { "loose": true }] + ] +} diff --git a/packages/editor-skeleton/jest.config.js b/packages/editor-skeleton/jest.config.js new file mode 100644 index 0000000000..8a9b2000ca --- /dev/null +++ b/packages/editor-skeleton/jest.config.js @@ -0,0 +1,29 @@ +const fs = require('fs'); +const { join } = require('path'); +const esModules = [].join('|'); +const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.')); + +const jestConfig = { + // transform: { + // '^.+\\.[jt]sx?$': 'babel-jest', + // // '^.+\\.(ts|tsx)$': 'ts-jest', + // // '^.+\\.(js|jsx)$': 'babel-jest', + // }, + transformIgnorePatterns: [ + `/node_modules/(?!${esModules})/`, + ], + moduleFileExtensions: ['ts', 'tsx', 'js', 'json'], + collectCoverage: false, + collectCoverageFrom: [ + 'src/**/*.ts', + '!src/**/*.d.ts', + '!**/node_modules/**', + '!**/vendor/**', + ], +}; + +// 只对本仓库内的 pkg 做 mapping +jestConfig.moduleNameMapper = {}; +jestConfig.moduleNameMapper[`^@alilc/lowcode\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src'; + +module.exports = jestConfig; \ No newline at end of file diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 365400b700..654472bbbc 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -10,6 +10,7 @@ "es" ], "scripts": { + "test": "build-scripts test --config build.test.json", "build": "build-scripts build --skip-demo" }, "keywords": [ diff --git a/packages/editor-skeleton/src/widget/utils.ts b/packages/editor-skeleton/src/widget/utils.ts index c4096d2e26..bec41333c8 100644 --- a/packages/editor-skeleton/src/widget/utils.ts +++ b/packages/editor-skeleton/src/widget/utils.ts @@ -45,7 +45,7 @@ export function composeTitle(title?: IPublicTypeTitleContent, icon?: IPublicType } } if (isTitleConfig(_title) && noIcon) { - if (!isValidElement(title)) { + if (!isValidElement(_title)) { _title.icon = undefined; } } diff --git a/packages/editor-skeleton/tests/widget/utils.test.ts b/packages/editor-skeleton/tests/widget/utils.test.ts new file mode 100644 index 0000000000..2836e86db5 --- /dev/null +++ b/packages/editor-skeleton/tests/widget/utils.test.ts @@ -0,0 +1,54 @@ +import { composeTitle } from '../../src/widget/utils'; +import * as React from 'react'; + +const label = React.createElement('div'); + +describe('composeTitle 测试', () => { + it('基础能力测试', () => { + expect(composeTitle(undefined)).toEqual({ + label: undefined, + }); + + expect(composeTitle(undefined, undefined, 'tips', true, true)).toEqual({ + icon: undefined, + label: 'tips', + }); + + expect(composeTitle(undefined, undefined, label, true, true)).toEqual({ + icon: undefined, + label, + }); + + expect(composeTitle({ + icon: undefined, + label, + }, undefined, '')).toEqual({ + icon: undefined, + label, + }); + + expect(composeTitle('settingsPane')).toEqual('settingsPane'); + + expect(composeTitle(label, undefined, '物料面板', true, true)).toEqual({ + icon: undefined, + label, + tip: '物料面板', + }); + + expect(composeTitle(label, undefined, label, true, true)).toEqual({ + icon: undefined, + label, + tip: label, + }); + + expect(composeTitle({ + label: "物料面板", + icon: undefined, + tip: null, + })).toEqual({ + label: "物料面板", + icon: undefined, + tip: null, + }) + }); +}) \ No newline at end of file diff --git a/packages/types/src/shell/type/widget-base-config.ts b/packages/types/src/shell/type/widget-base-config.ts index 8a8cda24f3..f8268628bc 100644 --- a/packages/types/src/shell/type/widget-base-config.ts +++ b/packages/types/src/shell/type/widget-base-config.ts @@ -23,6 +23,9 @@ export interface IPublicTypePanelDockConfig extends IPublicTypeWidgetBaseConfig panelProps?: IPublicTypePanelDockPanelProps; props?: IPublicTypePanelDockProps; + + /** 面板 name, 当没有 props.title 时, 会使用 name 作为标题 */ + name?: string; } export interface IPublicTypePanelDockProps { @@ -32,12 +35,19 @@ export interface IPublicTypePanelDockProps { className?: string; + /** 详细描述,hover 时在标题上方显示的 tips 内容 */ description?: TipContent; onClick?: () => void; + /** + * 面板标题前的 icon + */ icon?: IPublicTypeIconType; + /** + * 面板标题 + */ title?: IPublicTypeTitleContent; } From 5df3ed368d2f498a6f815bf3af91ed9d79912ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Tue, 4 Apr 2023 14:54:02 +0800 Subject: [PATCH 095/469] =?UTF-8?q?docs:=20add=20=E3=80=8C=E4=BB=80?= =?UTF-8?q?=E4=B9=88=EF=BC=9F=E4=BD=8E=E4=BB=A3=E7=A0=81=E5=BC=95=E6=93=8E?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E5=BC=80=E5=8F=91=E5=BA=94=E7=94=A8=E4=BA=86?= =?UTF-8?q?=E3=80=8D=20article?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/article/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index 44823653a8..8ff76ff476 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -3,6 +3,7 @@ title: 低代码引擎相关文章资料 --- ## 官方文章 +- [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) From 779edf783bac1ef71668fb74eaba44527c99a0f5 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 11 Apr 2023 15:38:28 +0800 Subject: [PATCH 096/469] chore(release): publish 1.1.6 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 10 +++++----- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 67 insertions(+), 67 deletions(-) diff --git a/lerna.json b/lerna.json index 8edd610752..dd7f87e45e 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.5", + "version": "1.1.6", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 6350d00fb3..61190a3be7 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.5", + "version": "1.1.6", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.1.5", - "@alilc/lowcode-types": "1.1.5", - "@alilc/lowcode-utils": "1.1.5", + "@alilc/lowcode-editor-core": "1.1.6", + "@alilc/lowcode-types": "1.1.6", + "@alilc/lowcode-utils": "1.1.6", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 3110d9dc1b..c4272a0ab2 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.1.5", + "version": "1.1.6", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.5", - "@alilc/lowcode-utils": "1.1.5", + "@alilc/lowcode-types": "1.1.6", + "@alilc/lowcode-utils": "1.1.6", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 654472bbbc..7e64d81665 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.1.5", + "version": "1.1.6", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.1.5", - "@alilc/lowcode-editor-core": "1.1.5", - "@alilc/lowcode-types": "1.1.5", - "@alilc/lowcode-utils": "1.1.5", + "@alilc/lowcode-designer": "1.1.6", + "@alilc/lowcode-editor-core": "1.1.6", + "@alilc/lowcode-types": "1.1.6", + "@alilc/lowcode-utils": "1.1.6", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 723ee40175..99b185db00 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.5", + "version": "1.1.6", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.1.5", - "@alilc/lowcode-editor-core": "1.1.5", - "@alilc/lowcode-editor-skeleton": "1.1.5", + "@alilc/lowcode-designer": "1.1.6", + "@alilc/lowcode-editor-core": "1.1.6", + "@alilc/lowcode-editor-skeleton": "1.1.6", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.5", - "@alilc/lowcode-plugin-outline-pane": "1.1.5", - "@alilc/lowcode-shell": "1.1.5", - "@alilc/lowcode-utils": "1.1.5", - "@alilc/lowcode-workspace": "1.1.5", + "@alilc/lowcode-plugin-designer": "1.1.6", + "@alilc/lowcode-plugin-outline-pane": "1.1.6", + "@alilc/lowcode-shell": "1.1.6", + "@alilc/lowcode-utils": "1.1.6", + "@alilc/lowcode-workspace": "1.1.6", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 440496f583..7fa6ab0730 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.5", + "version": "1.1.6", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 1673eab860..0f64b70f19 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.1.5", + "version": "1.1.6", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.5", - "@alilc/lowcode-editor-core": "1.1.5", - "@alilc/lowcode-utils": "1.1.5", + "@alilc/lowcode-designer": "1.1.6", + "@alilc/lowcode-editor-core": "1.1.6", + "@alilc/lowcode-utils": "1.1.6", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 73aaa01b43..ec4738cd76 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.1.5", + "version": "1.1.6", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,10 +13,10 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-designer": "1.1.5", - "@alilc/lowcode-editor-core": "1.1.5", - "@alilc/lowcode-types": "1.1.5", - "@alilc/lowcode-utils": "1.1.5", + "@alilc/lowcode-designer": "1.1.6", + "@alilc/lowcode-editor-core": "1.1.6", + "@alilc/lowcode-types": "1.1.6", + "@alilc/lowcode-utils": "1.1.6", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 366e1673c3..489cf14093 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.1.5", + "version": "1.1.6", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.1.5", - "@alilc/lowcode-utils": "1.1.5", + "@alilc/lowcode-renderer-core": "1.1.6", + "@alilc/lowcode-utils": "1.1.6", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 87f2290553..76954ff362 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.1.5", + "version": "1.1.6", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.5", - "@alilc/lowcode-rax-renderer": "1.1.5", - "@alilc/lowcode-types": "1.1.5", - "@alilc/lowcode-utils": "1.1.5", + "@alilc/lowcode-designer": "1.1.6", + "@alilc/lowcode-rax-renderer": "1.1.6", + "@alilc/lowcode-types": "1.1.6", + "@alilc/lowcode-utils": "1.1.6", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index d0cd2dc2ca..862f69d015 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.1.5", + "version": "1.1.6", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.1.5" + "@alilc/lowcode-renderer-core": "1.1.6" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 43c58581e3..fce8d866eb 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.1.5", + "version": "1.1.6", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.5", - "@alilc/lowcode-react-renderer": "1.1.5", - "@alilc/lowcode-types": "1.1.5", - "@alilc/lowcode-utils": "1.1.5", + "@alilc/lowcode-designer": "1.1.6", + "@alilc/lowcode-react-renderer": "1.1.6", + "@alilc/lowcode-types": "1.1.6", + "@alilc/lowcode-utils": "1.1.6", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 75c407a202..84a63aa9a2 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.1.5", + "version": "1.1.6", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.1.5", - "@alilc/lowcode-utils": "1.1.5", + "@alilc/lowcode-types": "1.1.6", + "@alilc/lowcode-utils": "1.1.6", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.1.5", + "@alilc/lowcode-designer": "1.1.6", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 669bd3de14..9b9cc04168 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.5", + "version": "1.1.6", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,12 +15,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.5", - "@alilc/lowcode-editor-core": "1.1.5", - "@alilc/lowcode-editor-skeleton": "1.1.5", - "@alilc/lowcode-types": "1.1.5", - "@alilc/lowcode-utils": "1.1.5", - "@alilc/lowcode-workspace": "1.1.5", + "@alilc/lowcode-designer": "1.1.6", + "@alilc/lowcode-editor-core": "1.1.6", + "@alilc/lowcode-editor-skeleton": "1.1.6", + "@alilc/lowcode-types": "1.1.6", + "@alilc/lowcode-utils": "1.1.6", + "@alilc/lowcode-workspace": "1.1.6", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 42755f5626..6d90338869 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.5", + "version": "1.1.6", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index c7fc7140c9..8043a9e109 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.5", + "version": "1.1.6", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.5", + "@alilc/lowcode-types": "1.1.6", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 34c7cfa762..c1b1e25a57 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.5", + "version": "1.1.6", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.5", - "@alilc/lowcode-editor-core": "1.1.5", - "@alilc/lowcode-editor-skeleton": "1.1.5", - "@alilc/lowcode-types": "1.1.5", - "@alilc/lowcode-utils": "1.1.5", + "@alilc/lowcode-designer": "1.1.6", + "@alilc/lowcode-editor-core": "1.1.6", + "@alilc/lowcode-editor-skeleton": "1.1.6", + "@alilc/lowcode-types": "1.1.6", + "@alilc/lowcode-utils": "1.1.6", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 217db5a6f14ab1f096657ce886478b6d9c691a9e Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 11 Apr 2023 15:43:06 +0800 Subject: [PATCH 097/469] chore(docs): publish 1.0.26 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index c05ace3105..4c8cfc1619 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.25", + "version": "1.0.26", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 4133b2f714d8ae013be4533e11d48089f147aa57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BD=B6=E6=A9=99?= <664108365@qq.com> Date: Mon, 10 Apr 2023 16:20:21 +0800 Subject: [PATCH 098/469] Update setters.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 写错了 --- docs/docs/api/setters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/api/setters.md b/docs/docs/api/setters.md index 92d24f4e16..cc7b6d429c 100644 --- a/docs/docs/api/setters.md +++ b/docs/docs/api/setters.md @@ -145,7 +145,7 @@ export default class AltStringSetter extends React.PureComponent<AltStringSetter ```typescript import AltStringSetter from './AltStringSetter'; import { setters } from '@alilc/lowcode-engine'; -const { registerSetter } = registerSetter; +const { registerSetter } = setters; registerSetter('AltStringSetter', AltStringSetter); ``` 注册之后,我们就可以在物料中使用了,其中核心配置如下: From c23f16d646605d1857e392e232e31de27c6e7acf Mon Sep 17 00:00:00 2001 From: duoduo <1162256166@qq.com> Date: Thu, 6 Apr 2023 11:22:24 +0800 Subject: [PATCH 099/469] refactor: Change let to const --- packages/designer/src/component-actions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/designer/src/component-actions.ts b/packages/designer/src/component-actions.ts index 793bbdc203..a7a690a44d 100644 --- a/packages/designer/src/component-actions.ts +++ b/packages/designer/src/component-actions.ts @@ -56,8 +56,8 @@ export class ComponentActions { const { isRGL, rglNode } = node.getRGL(); if (isRGL) { // 复制 layout 信息 - let layout = rglNode.getPropValue('layout') || []; - let curLayout = layout.filter((item) => item.i === node.getPropValue('fieldId')); + const layout = rglNode.getPropValue('layout') || []; + const curLayout = layout.filter((item) => item.i === node.getPropValue('fieldId')); if (curLayout && curLayout[0]) { layout.push({ ...curLayout[0], From 3d470cad69afb1c761da16dcdadb9bdd6b9c1d19 Mon Sep 17 00:00:00 2001 From: eternalsky <wsj7552715@hotmail.com> Date: Tue, 11 Apr 2023 20:38:45 +0800 Subject: [PATCH 100/469] feat: add componentRenderer lifeCycles log --- .../renderer-core/src/renderer/component.tsx | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/packages/renderer-core/src/renderer/component.tsx b/packages/renderer-core/src/renderer/component.tsx index 4be33f5c19..f9f6e8f96e 100644 --- a/packages/renderer-core/src/renderer/component.tsx +++ b/packages/renderer-core/src/renderer/component.tsx @@ -47,11 +47,25 @@ export default function componentRendererFactory(): IBaseRenderComponent { return this.__renderComp(Component, this.__renderContextProvider({ compContext: this })); } + getComponentName() { + return this.props?.componentName; + } + /** 需要重载下面几个方法,如果在低代码组件中绑定了对应的生命周期时会出现死循环 */ - componentDidMount() {} - getSnapshotBeforeUpdate() {} - componentDidUpdate() {} - componentWillUnmount() {} - componentDidCatch() {} + componentDidMount() { + this.__debug(`componentDidMount - ${this.getComponentName()}`); + } + getSnapshotBeforeUpdate() { + this.__debug(`getSnapshotBeforeUpdate - ${this.getComponentName()}`); + } + componentDidUpdate() { + this.__debug(`componentDidUpdate - ${this.getComponentName()}`); + } + componentWillUnmount() { + this.__debug(`componentWillUnmount - ${this.getComponentName()}`); + } + componentDidCatch() { + this.__debug(`componentDidCatch - ${this.getComponentName()}`); + } }; } From 33fd6bf6426f3300a1e95c80b3021fed26656872 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 13 Apr 2023 11:33:39 +0800 Subject: [PATCH 101/469] feat: added features in workspace mode --- .../src/builtin-simulator/create-simulator.ts | 2 + .../src/builtin-simulator/host-view.tsx | 5 +- packages/designer/src/plugin/plugin-types.ts | 2 + .../tests/builtin-simulator/host.test.ts | 14 +++++- .../src/components/settings/settings-pane.tsx | 29 ++++++----- packages/engine/src/engine-core.ts | 27 +++++++--- packages/renderer-core/src/hoc/leaf.tsx | 9 ++-- packages/shell/src/api/common.tsx | 7 +-- packages/shell/src/api/project.ts | 19 ++++--- packages/shell/src/api/setters.ts | 7 +++ packages/shell/src/api/workspace.ts | 4 +- packages/shell/src/index.ts | 2 + packages/shell/src/model/document-model.ts | 2 +- packages/types/src/shell/api/workspace.ts | 2 +- .../workspace/src/context/base-context.ts | 4 ++ packages/workspace/src/layouts/workbench.less | 3 ++ packages/workspace/src/resource.ts | 2 +- packages/workspace/src/window.ts | 16 +++++- packages/workspace/src/workspace.ts | 49 ++++++++++++++++--- 19 files changed, 155 insertions(+), 50 deletions(-) diff --git a/packages/designer/src/builtin-simulator/create-simulator.ts b/packages/designer/src/builtin-simulator/create-simulator.ts index e465821805..15ab3507b5 100644 --- a/packages/designer/src/builtin-simulator/create-simulator.ts +++ b/packages/designer/src/builtin-simulator/create-simulator.ts @@ -20,7 +20,9 @@ export function createSimulator( ): Promise<BuiltinSimulatorRenderer> { const win: any = iframe.contentWindow; const doc = iframe.contentDocument!; + const innerPlugins = host.designer.editor.get('innerPlugins'); + win.AliLowCodeEngine = innerPlugins._getLowCodePluginContext({}); win.LCSimulatorHost = host; win._ = window._; diff --git a/packages/designer/src/builtin-simulator/host-view.tsx b/packages/designer/src/builtin-simulator/host-view.tsx index a7943ea9fa..21e0079306 100644 --- a/packages/designer/src/builtin-simulator/host-view.tsx +++ b/packages/designer/src/builtin-simulator/host-view.tsx @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { observer, globalContext } from '@alilc/lowcode-editor-core'; +import { observer } from '@alilc/lowcode-editor-core'; import { BuiltinSimulatorHost, BuiltinSimulatorProps } from './host'; import { BemTools } from './bem-tools'; import { Project } from '../project'; @@ -76,8 +76,7 @@ class Content extends Component<{ host: BuiltinSimulatorHost }> { private dispose?: () => void; componentDidMount() { - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); + const editor = this.props.host.designer.editor; const onEnableEvents = (type: boolean) => { this.setState({ disabledEvents: type, diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index f76e20827d..23aac2849d 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -16,6 +16,7 @@ import { IPublicApiWorkspace, IPublicTypePluginMeta, IPublicTypePluginRegisterOptions, + IPublicModelWindow, } from '@alilc/lowcode-types'; import PluginContext from './plugin-context'; @@ -56,6 +57,7 @@ export interface ILowCodePluginContextPrivate { set pluginEvent(event: IPublicApiEvent); set canvas(canvas: IPublicApiCanvas); set workspace(workspace: IPublicApiWorkspace); + set editorWindow(window: IPublicModelWindow); } export interface ILowCodePluginContextApiAssembler { assembleApis( diff --git a/packages/designer/tests/builtin-simulator/host.test.ts b/packages/designer/tests/builtin-simulator/host.test.ts index 61ae61742b..57e74be579 100644 --- a/packages/designer/tests/builtin-simulator/host.test.ts +++ b/packages/designer/tests/builtin-simulator/host.test.ts @@ -1,3 +1,4 @@ +import { IPublicTypePluginMeta } from './../../../../lib/packages/types/src/shell/type/plugin-meta.d'; import '../fixtures/window'; import { Editor, @@ -22,6 +23,7 @@ import { BuiltinSimulatorHost } from '../../src/builtin-simulator/host'; import { fireEvent } from '@testing-library/react'; import { shellModelFactory } from '../../../engine/src/modules/shell-model-factory'; import { Setters, Workspace } from '@alilc/lowcode-shell'; +import { ILowCodePluginContextApiAssembler, ILowCodePluginContextPrivate, LowCodePluginManager } from '@alilc/lowcode-designer'; describe('Host 测试', () => { let editor: Editor; @@ -32,10 +34,20 @@ describe('Host 测试', () => { beforeAll(() => { editor = new Editor(); - const innerWorkspace = new InnerWorkspace(); + const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + assembleApis: (context: ILowCodePluginContextPrivate, pluginName: string, meta: IPublicTypePluginMeta) => { + context.project = project; + const eventPrefix = meta?.eventPrefix || 'common'; + context.workspace = workspace; + }, + }; + const innerPlugins = new LowCodePluginManager(pluginContextApiAssembler); + const innerWorkspace = new InnerWorkspace(() => {}, {}); const workspace = new Workspace(innerWorkspace); editor.set('innerHotkey', new InnerHotkey()) editor.set('setters', new Setters(new InnerSetters())); + editor.set('innerPlugins' as any, innerPlugins); !globalContext.has(Editor) && globalContext.register(editor, Editor); !globalContext.has('workspace') && globalContext.register(innerWorkspace, 'workspace'); }); diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index 46b188acc5..31ea78cced 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -1,5 +1,5 @@ import { Component, MouseEvent, Fragment } from 'react'; -import { shallowIntl, observer, obx, engineConfig, runInAction, globalContext } from '@alilc/lowcode-editor-core'; +import { shallowIntl, observer, obx, engineConfig, runInAction } from '@alilc/lowcode-editor-core'; import { createContent, isJSSlot, isSetterConfig } from '@alilc/lowcode-utils'; import { Skeleton, Stage } from '@alilc/lowcode-editor-skeleton'; import { IPublicTypeCustomView } from '@alilc/lowcode-types'; @@ -40,7 +40,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView stageName: string | undefined; - setters: Setters; + setters?: Setters; constructor(props: SettingFieldViewProps) { super(props); @@ -49,10 +49,10 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView const { extraProps } = field; const { display } = extraProps; - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); - const { stages } = editor.get('skeleton') as Skeleton; - this.setters = editor.get('setters'); + const editor = field.designer?.editor; + const skeleton = editor?.get('skeleton') as Skeleton; + const { stages } = skeleton || {}; + this.setters = editor?.get('setters'); let stageName; if (display === 'entry') { runInAction(() => { @@ -291,9 +291,8 @@ class SettingGroupView extends Component<SettingGroupViewProps> { const { field } = this.props; const { extraProps } = field; const { display } = extraProps; - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); - const { stages } = editor.get('skeleton') as Skeleton; + const editor = this.props.field.designer?.editor; + const { stages } = editor?.get('skeleton') as Skeleton; // const items = field.items; let stageName; @@ -343,15 +342,15 @@ class SettingGroupView extends Component<SettingGroupViewProps> { } } -export function createSettingFieldView(item: ISettingField | IPublicTypeCustomView, field: ISettingEntry, index?: number) { - if (isSettingField(item)) { - if (item.isGroup) { - return <SettingGroupView field={item} key={item.id} />; +export function createSettingFieldView(field: ISettingField | IPublicTypeCustomView, fieldEntry: ISettingEntry, index?: number) { + if (isSettingField(field)) { + if (field.isGroup) { + return <SettingGroupView field={field} key={field.id} />; } else { - return <SettingFieldView field={item} key={item.id} />; + return <SettingFieldView field={field} key={field.id} />; } } else { - return createContent(item, { key: index, field }); + return createContent(field, { key: index, field: fieldEntry }); } } diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index b038df8188..7148bb38ae 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -14,6 +14,7 @@ import { IPublicTypeEngineOptions, IPublicModelDocumentModel, IPublicTypePluginMeta, + IPublicTypeDisposable, } from '@alilc/lowcode-types'; import { Designer, @@ -60,14 +61,26 @@ export * from './modules/skeleton-types'; export * from './modules/designer-types'; export * from './modules/lowcode-types'; -async function registryInnerPlugin(designer: Designer, editor: Editor, plugins: Plugins) { +async function registryInnerPlugin(designer: Designer, editor: Editor, plugins: Plugins): Promise<IPublicTypeDisposable> { // 注册一批内置插件 + const componentMetaParserPlugin = componentMetaParser(designer); + const defaultPanelRegistryPlugin = defaultPanelRegistry(editor); await plugins.register(OutlinePlugin, {}, { autoInit: true }); - await plugins.register(componentMetaParser(designer)); + await plugins.register(componentMetaParserPlugin); await plugins.register(setterRegistry, {}); - await plugins.register(defaultPanelRegistry(editor)); + await plugins.register(defaultPanelRegistryPlugin); await plugins.register(builtinHotkey); await plugins.register(registerDefaults, {}, { autoInit: true }); + + return () => { + plugins.delete(OutlinePlugin.pluginName); + plugins.delete(componentMetaParserPlugin.pluginName); + plugins.delete(setterRegistry.pluginName); + plugins.delete(defaultPanelRegistryPlugin.pluginName); + plugins.delete(defaultPanelRegistryPlugin.pluginName); + plugins.delete(builtinHotkey.pluginName); + plugins.delete(registerDefaults.pluginName); + }; } const innerWorkspace = new InnerWorkspace(registryInnerPlugin, shellModelFactory); @@ -158,7 +171,7 @@ let engineContainer: HTMLElement; export const version = VERSION_PLACEHOLDER; engineConfig.set('ENGINE_VERSION', version); -registryInnerPlugin(designer, editor, plugins); +const pluginPromise = registryInnerPlugin(designer, editor, plugins); export async function init( container?: HTMLElement, @@ -183,10 +196,10 @@ export async function init( } engineConfig.setEngineOptions(engineOptions as any); - await plugins.init(pluginPreference as any); - const { Workbench } = common.skeletonCabin; if (options && options.enableWorkspaceMode) { + const disposeFun = await pluginPromise; + disposeFun && disposeFun(); render( createElement(WorkSpaceWorkbench, { workspace: innerWorkspace, @@ -202,6 +215,8 @@ export async function init( return; } + await plugins.init(pluginPreference as any); + render( createElement(Workbench, { skeleton: innerSkeleton, diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index 5df9880485..98b2674750 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -102,6 +102,9 @@ function initRerenderEvent({ return; } cache.event.get(schema.id)?.dispose.forEach((disposeFn: any) => disposeFn && disposeFn()); + const debounceRerender = debounce(() => { + container.rerender(); + }, 20); cache.event.set(schema.id, { clear: false, leaf, @@ -111,21 +114,21 @@ function initRerenderEvent({ return; } __debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onPropsChange make rerender`); - container.rerender(); + debounceRerender(); }), leaf?.onChildrenChange?.(() => { if (!container.autoRepaintNode) { return; } __debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onChildrenChange make rerender`); - container.rerender(); + debounceRerender(); }) as Function, leaf?.onVisibleChange?.(() => { if (!container.autoRepaintNode) { return; } __debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onVisibleChange make rerender`); - container.rerender(); + debounceRerender(); }), ], }); diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx index 6a44dc82e7..d9009ff8eb 100644 --- a/packages/shell/src/api/common.tsx +++ b/packages/shell/src/api/common.tsx @@ -1,4 +1,4 @@ -import { editorSymbol, skeletonSymbol, designerCabinSymbol, designerSymbol } from '../symbols'; +import { editorSymbol, skeletonSymbol, designerCabinSymbol, designerSymbol, settingFieldSymbol } from '../symbols'; import { isFormEvent as innerIsFormEvent, compatibleLegaoSchema as innerCompatibleLegaoSchema, @@ -25,6 +25,7 @@ import { IPublicTypeLocationDetailType as InnerLocationDetailType, IPublicApiCommonEditorCabin, IPublicModelDragon, + IPublicModelSettingField, } from '@alilc/lowcode-types'; import { SettingField as InnerSettingField, @@ -168,8 +169,8 @@ class SkeletonCabin implements IPublicApiCommonSkeletonCabin { /** * @deprecated */ - createSettingFieldView(item: any, field: any) { - return innerCreateSettingFieldView(item, field); + createSettingFieldView(field: IPublicModelSettingField, fieldEntry: any) { + return innerCreateSettingFieldView((field as any)[settingFieldSymbol] || field, fieldEntry); } /** diff --git a/packages/shell/src/api/project.ts b/packages/shell/src/api/project.ts index ed45701b3c..e33a038b91 100644 --- a/packages/shell/src/api/project.ts +++ b/packages/shell/src/api/project.ts @@ -18,6 +18,9 @@ import { import { DocumentModel as ShellDocumentModel } from '../model'; import { SimulatorHost } from './simulator-host'; import { editorSymbol, projectSymbol, simulatorHostSymbol, documentSymbol } from '../symbols'; +import { getLogger } from '@alilc/lowcode-utils'; + +const logger = getLogger({ level: 'warn', bizName: 'shell-project' }); const innerProjectSymbol = Symbol('innerProject'); export class Project implements IPublicApiProject { @@ -29,6 +32,10 @@ export class Project implements IPublicApiProject { } const workspace = globalContext.get('workspace'); if (workspace.isActive) { + if (!workspace.window.innerProject) { + logger.error('project api 调用时机出现问题,请检查'); + return this[innerProjectSymbol]; + } return workspace.window.innerProject; } @@ -43,8 +50,8 @@ export class Project implements IPublicApiProject { this[innerProjectSymbol] = project; } - static create(project: InnerProject) { - return new Project(project); + static create(project: InnerProject, workspaceMode: boolean = false) { + return new Project(project, workspaceMode); } /** @@ -225,15 +232,15 @@ export class Project implements IPublicApiProject { */ setConfig<T extends keyof IPublicTypeAppConfig>(key: T, value: IPublicTypeAppConfig[T]): void; setConfig(value: IPublicTypeAppConfig): void; - setConfig(...params: any[]): void{ - if(params.length === 2) { + setConfig(...params: any[]): void { + if (params.length === 2) { const oldConfig = this[projectSymbol].get('config'); this[projectSymbol].set('config', { ...oldConfig, [params[0]]: params[1], - }) + }); } else { - this[projectSymbol].set('config', params[0]) + this[projectSymbol].set('config', params[0]); } } } diff --git a/packages/shell/src/api/setters.ts b/packages/shell/src/api/setters.ts index 553f32c4e9..72d29c8a8b 100644 --- a/packages/shell/src/api/setters.ts +++ b/packages/shell/src/api/setters.ts @@ -1,10 +1,13 @@ import { IPublicTypeCustomView, IPublicApiSetters, IPublicTypeRegisteredSetter } from '@alilc/lowcode-types'; import { Setters as InnerSetters, globalContext } from '@alilc/lowcode-editor-core'; import { ReactNode } from 'react'; +import { getLogger } from '@alilc/lowcode-utils'; const innerSettersSymbol = Symbol('setters'); const settersSymbol = Symbol('setters'); +const logger = getLogger({ level: 'warn', bizName: 'shell-setters' }); + export class Setters implements IPublicApiSetters { readonly [innerSettersSymbol]: InnerSetters; @@ -15,6 +18,10 @@ export class Setters implements IPublicApiSetters { const workspace = globalContext.get('workspace'); if (workspace.isActive) { + if (!workspace.window.innerSetters) { + logger.error('setter api 调用时机出现问题,请检查'); + return this[innerSettersSymbol]; + } return workspace.window.innerSetters; } diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index 21015431f9..aa56d0d37d 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -35,8 +35,8 @@ export class Workspace implements IPublicApiWorkspace { this[workspaceSymbol].registerResourceType(resourceTypeModel); } - openEditorWindow(resourceName: string, title: string, extra: object, viewName?: string) { - this[workspaceSymbol].openEditorWindow(resourceName, title, extra, viewName); + openEditorWindow(resourceName: string, title: string, extra: object, viewName?: string, sleep?: boolean): void { + this[workspaceSymbol].openEditorWindow(resourceName, title, extra, viewName, sleep); } openEditorWindowById(id: string) { diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index 7017ca2894..b3fca90b0a 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -10,6 +10,7 @@ import { SettingTopEntry, Clipboard, SettingField, + Window, } from './model'; import { Project, @@ -50,6 +51,7 @@ export { Selection, Setters, Hotkey, + Window, Skeleton, SettingField as SettingPropEntry, SettingTopEntry, diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts index 68252e3a55..06f3cebcd9 100644 --- a/packages/shell/src/model/document-model.ts +++ b/packages/shell/src/model/document-model.ts @@ -90,7 +90,7 @@ export class DocumentModel implements IPublicModelDocumentModel { * @returns */ get project(): IPublicApiProject { - return ShellProject.create(this[documentSymbol].project); + return ShellProject.create(this[documentSymbol].project, true); } /** diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index 8c19846f70..4422dde4e3 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -30,7 +30,7 @@ export interface IPublicApiWorkspace< registerResourceType(resourceTypeModel: IPublicTypeResourceType): void; /** 打开视图窗口 */ - openEditorWindow(resourceName: string, title: string, extra: Object, viewName?: string): void; + openEditorWindow(resourceName: string, title: string, extra: Object, viewName?: string, sleep?: boolean): void; /** 通过视图 id 打开窗口 */ openEditorWindowById(id: string): void; diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index e74ae2ffb4..57a38712b9 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -30,6 +30,7 @@ import { Common, Logger, Workspace, + Window, Canvas, } from '@alilc/lowcode-shell'; import { @@ -164,6 +165,9 @@ export class BasicContext implements IBasicContext { context.plugins = plugins; context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.canvas = canvas; + if (editorWindow) { + context.editorWindow = new Window(editorWindow); + } }, }; diff --git a/packages/workspace/src/layouts/workbench.less b/packages/workspace/src/layouts/workbench.less index 95574871a7..c8c89d6f0f 100644 --- a/packages/workspace/src/layouts/workbench.less +++ b/packages/workspace/src/layouts/workbench.less @@ -368,6 +368,9 @@ body { right: 0; bottom: 0; left: 0; + flex-direction: column; + display: flex; + align-content: stretch; } .engine-actionitem { diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index 10cb7f0a15..222cb1162e 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -39,7 +39,7 @@ export class Resource implements IResource { } get viewName() { - return this.resourceData.viewName || (this.resourceData as any).viewType; + return this.resourceData.viewName || (this.resourceData as any).viewType || this.defaultViewType; } get description() { diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index 96707dcb84..1b9bec410d 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -10,6 +10,7 @@ interface IWindowCOnfig { title: string | undefined; options?: Object; viewType?: string | undefined; + sleep?: boolean; } export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'changeViewType'> { @@ -18,6 +19,12 @@ export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'chan editorViews: Map<string, Context>; changeViewType: (name: string, ignoreEmit?: boolean) => void; + + initReady: boolean; + + sleep?: boolean; + + init(): void; } export class EditorWindow implements IEditorWindow { @@ -36,11 +43,16 @@ export class EditorWindow implements IEditorWindow { @obx initReady = false; + sleep: boolean | undefined; + constructor(readonly resource: IResource, readonly workspace: IWorkspace, private config: IWindowCOnfig) { makeObservable(this); - this.init(); this.title = config.title; this.icon = resource.icon; + this.sleep = config.sleep; + if (!config.sleep) { + this.init(); + } } async importSchema(schema: any) { @@ -73,6 +85,8 @@ export class EditorWindow implements IEditorWindow { this.url = await this.resource.url(); this.setDefaultViewType(); this.initReady = true; + this.workspace.checkWindowQueue(); + this.sleep = false; } initViewTypes = async () => { diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index d959c55eb8..30c8fcdade 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -30,6 +30,8 @@ export interface IWorkspace extends Omit<IPublicApiWorkspace< getResourceList(): IResource[]; getResourceType(resourceName: string): IResourceType; + + checkWindowQueue(): void; } export class Workspace implements IWorkspace { @@ -69,6 +71,13 @@ export class Workspace implements IWorkspace { @obx.ref window: IEditorWindow; + windowQueue: { + name: string; + title: string; + options: Object; + viewType?: string; + }[] = []; + constructor( readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise<void>, readonly shellModelFactory: any, @@ -77,6 +86,17 @@ export class Workspace implements IWorkspace { makeObservable(this); } + checkWindowQueue() { + if (!this.windowQueue || !this.windowQueue.length) { + return; + } + + const windowInfo = this.windowQueue.shift(); + if (windowInfo) { + this.openEditorWindow(windowInfo.name, windowInfo.title, windowInfo.options, windowInfo.viewType); + } + } + init() { this.initWindow(); this.context = new BasicContext(this, ''); @@ -86,13 +106,13 @@ export class Workspace implements IWorkspace { if (!this.defaultResourceType) { return; } - const title = this.defaultResourceType.name; + const resourceName = this.defaultResourceType.name; const resource = new Resource({ - resourceName: title, + resourceName, options: {}, }, this.defaultResourceType, this); this.window = new EditorWindow(resource, this, { - title, + title: resource.title, }); this.editorWindowMap.set(this.window.id, this.window); this.windows.push(this.window); @@ -167,7 +187,13 @@ export class Workspace implements IWorkspace { } } - openEditorWindow(name: string, title: string, options: Object, viewType?: string) { + openEditorWindow(name: string, title: string, options: Object, viewType?: string, sleep?: boolean) { + if (!this.window?.initReady && !sleep) { + this.windowQueue.push({ + name, title, options, viewType, + }); + return; + } const resourceType = this.resourceTypeMap.get(name); if (!resourceType) { console.error(`${name} resourceType is not available`); @@ -176,6 +202,11 @@ export class Workspace implements IWorkspace { const filterWindows = this.windows.filter(d => (d.resource?.name === name && d.resource.title == title)); if (filterWindows && filterWindows.length) { this.window = filterWindows[0]; + if (!sleep && this.window.sleep) { + this.window.init(); + } else { + this.checkWindowQueue(); + } this.emitChangeActiveWindow(); return; } @@ -184,13 +215,17 @@ export class Workspace implements IWorkspace { title, options, }, resourceType, this); - this.window = new EditorWindow(resource, this, { + const window = new EditorWindow(resource, this, { title, options, viewType, + sleep, }); - this.windows = [...this.windows, this.window]; - this.editorWindowMap.set(this.window.id, this.window); + this.windows = [...this.windows, window]; + this.editorWindowMap.set(window.id, window); + if (!sleep) { + this.window = window; + } this.emitChangeWindow(); this.emitChangeActiveWindow(); } From f1ff1a07065160a61f103b249c108709976c9589 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 13 Apr 2023 14:58:08 +0800 Subject: [PATCH 102/469] fix: fix that the outline tree does not respond to modal addition/deletion related operations --- .../src/views/tree-node.tsx | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx index 712dc20fac..331397a0bd 100644 --- a/packages/plugin-outline-pane/src/views/tree-node.tsx +++ b/packages/plugin-outline-pane/src/views/tree-node.tsx @@ -9,6 +9,8 @@ import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicTypeDi class ModalTreeNodeView extends PureComponent<{ treeNode: TreeNode; pluginContext: IPublicModelPluginContext; +}, { + treeChildren: TreeNode[] | null; }> { private modalNodesManager: IPublicModelModalNodesManager | undefined | null; readonly pluginContext: IPublicModelPluginContext; @@ -20,18 +22,36 @@ class ModalTreeNodeView extends PureComponent<{ this.pluginContext = props.pluginContext; const { project } = this.pluginContext; this.modalNodesManager = project.currentDocument?.modalNodesManager; + this.state = { + treeChildren: this.rootTreeNode.children, + }; } hideAllNodes() { this.modalNodesManager?.hideModalNodes(); } - render() { + componentDidMount(): void { + const rootTreeNode = this.rootTreeNode; + rootTreeNode.onExpandableChanged(() => { + this.setState({ + treeChildren: rootTreeNode.children, + }); + }); + } + + get rootTreeNode() { const { treeNode } = this.props; // 当指定了新的根节点时,要从原始的根节点去获取模态节点 const { project } = this.pluginContext; const rootNode = project.currentDocument?.root; const rootTreeNode = treeNode.tree.getTreeNode(rootNode!); + + return rootTreeNode; + } + + render() { + const rootTreeNode = this.rootTreeNode; const { expanded } = rootTreeNode; const hasVisibleModalNode = !!this.modalNodesManager?.getVisibleModalNode(); @@ -49,7 +69,7 @@ class ModalTreeNodeView extends PureComponent<{ <div className="tree-pane-modal-content"> <TreeBranches treeNode={rootTreeNode} - treeChildren={rootTreeNode.children} + treeChildren={this.state.treeChildren} expanded={expanded} isModal pluginContext={this.pluginContext} From 6160056139a044e6b32b2ab0573694fef7f38453 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 17 Apr 2023 11:31:19 +0800 Subject: [PATCH 103/469] fix(utils): isReactComponent not including react.memo --- .github/workflows/cov packages.yml | 4 +- .github/workflows/test packages.yml | 52 ++++++++++++++++++- packages/renderer-core/jest.config.js | 1 + .../renderer-core/tests/utils/common.test.ts | 2 +- packages/utils/jest.config.js | 17 ++++-- packages/utils/src/is-react.ts | 11 +++- .../build-components/buildComponents.test.ts | 10 +++- packages/utils/test/src/is-react.test.ts | 38 ++++++++++++++ 8 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 packages/utils/test/src/is-react.test.ts diff --git a/.github/workflows/cov packages.yml b/.github/workflows/cov packages.yml index 499750282d..7f92e1009c 100644 --- a/.github/workflows/cov packages.yml +++ b/.github/workflows/cov packages.yml @@ -73,7 +73,7 @@ jobs: package-manager: yarn annotations: none -cov-utils: + 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' }} @@ -91,6 +91,6 @@ cov-utils: - uses: ArtiomTr/jest-coverage-report-action@v2 with: working-directory: packages/utils - test-script: npm test + test-script: npm test -- --jest-ci --jest-json --jest-coverage --jest-testLocationInResults --jest-outputFile=report.json package-manager: yarn annotations: none \ No newline at end of file diff --git a/.github/workflows/test packages.yml b/.github/workflows/test packages.yml index 484ef849a2..5d1ee89076 100644 --- a/.github/workflows/test packages.yml +++ b/.github/workflows/test packages.yml @@ -43,7 +43,7 @@ jobs: - name: test run: cd packages/designer && npm test - editor-skeleton: + test-editor-skeleton: runs-on: ubuntu-latest steps: - name: checkout @@ -57,4 +57,52 @@ jobs: run: npm i && npm run setup:skip-build - name: test - run: cd packages/editor-skeleton && npm test \ No newline at end of file + 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 \ No newline at end of file diff --git a/packages/renderer-core/jest.config.js b/packages/renderer-core/jest.config.js index 652a76e708..2489490fa2 100644 --- a/packages/renderer-core/jest.config.js +++ b/packages/renderer-core/jest.config.js @@ -11,6 +11,7 @@ const jestConfig = { // }, // testMatch: ['(/tests?/.*(test))\\.[jt]s$'], // testMatch: ['**/*/base.test.tsx'], + // testMatch: ['**/utils/common.test.ts'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], diff --git a/packages/renderer-core/tests/utils/common.test.ts b/packages/renderer-core/tests/utils/common.test.ts index 6fac55024f..995e55642e 100644 --- a/packages/renderer-core/tests/utils/common.test.ts +++ b/packages/renderer-core/tests/utils/common.test.ts @@ -374,7 +374,7 @@ describe('test parseThisRequiredExpression', () => { }; const fn = logger.error = jest.fn(); parseThisRequiredExpression(mockExpression, { state: { text: 'text' } }); - expect(fn).toBeCalledWith('parseExpression.error', new ReferenceError('state is not defined'), {"type": "JSExpression", "value": "state.text"}, {"state": {"text": "text"}}); + expect(fn).toBeCalledWith(' parseExpression.error', new ReferenceError('state is not defined'), {"type": "JSExpression", "value": "state.text"}, {"state": {"text": "text"}}); }); it('[success] JSExpression handle without this use scopeValue', () => { diff --git a/packages/utils/jest.config.js b/packages/utils/jest.config.js index 0e05687d78..328ea622eb 100644 --- a/packages/utils/jest.config.js +++ b/packages/utils/jest.config.js @@ -1,9 +1,20 @@ -module.exports = { +const fs = require('fs'); +const { join } = require('path'); +const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.')); + +const jestConfig = { moduleFileExtensions: ['ts', 'tsx', 'js', 'json'], - collectCoverage: true, + collectCoverage: false, collectCoverageFrom: [ - 'src/**/*.{ts,tsx}', + 'src/**/*.ts', + '!src/**/*.d.ts', '!**/node_modules/**', '!**/vendor/**', ], }; + +// 只对本仓库内的 pkg 做 mapping +jestConfig.moduleNameMapper = {}; +jestConfig.moduleNameMapper[`^@alilc/lowcode\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src'; + +module.exports = jestConfig; \ No newline at end of file diff --git a/packages/utils/src/is-react.ts b/packages/utils/src/is-react.ts index 1f17f9afc2..07568db981 100644 --- a/packages/utils/src/is-react.ts +++ b/packages/utils/src/is-react.ts @@ -3,6 +3,7 @@ import { cloneEnumerableProperty } from './clone-enumerable-property'; const hasSymbol = typeof Symbol === 'function' && Symbol.for; const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; +const REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; export function isReactClass(obj: any): obj is ComponentClass<any> { return obj && obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component); @@ -16,8 +17,16 @@ function isForwardRefType(obj: any): boolean { return obj?.$$typeof && obj?.$$typeof === REACT_FORWARD_REF_TYPE; } +function isMemoType(obj: any): boolean { + return obj?.$$typeof && obj.$$typeof === REACT_MEMO_TYPE; +} + export function isReactComponent(obj: any): obj is ComponentType<any> { - return obj && (isReactClass(obj) || typeof obj === 'function' || isForwardRefType(obj)); + if (!obj) { + return false; + } + + return Boolean(isReactClass(obj) || typeof obj === 'function' || isForwardRefType(obj) || isMemoType(obj)); } export function wrapReactClass(view: FunctionComponent) { diff --git a/packages/utils/test/src/build-components/buildComponents.test.ts b/packages/utils/test/src/build-components/buildComponents.test.ts index 5662aa12c9..e854890da4 100644 --- a/packages/utils/test/src/build-components/buildComponents.test.ts +++ b/packages/utils/test/src/build-components/buildComponents.test.ts @@ -309,8 +309,14 @@ describe('build-component', () => { )) .toEqual({ Button: { - componentName: 'Component', - schema: {}, + componentsMap: [], + componentsTree: [ + { + componentName: 'Component', + schema: {}, + } + ], + version: "", }, }); }) diff --git a/packages/utils/test/src/is-react.test.ts b/packages/utils/test/src/is-react.test.ts new file mode 100644 index 0000000000..74c88c9330 --- /dev/null +++ b/packages/utils/test/src/is-react.test.ts @@ -0,0 +1,38 @@ +import React from "react"; +import { isReactComponent, wrapReactClass } from "../../src/is-react"; + +class reactDemo extends React.Component { + +} + +const reactMemo = React.memo(reactDemo); + +const reactForwardRef = React.forwardRef((props, ref): any => { + return ''; +}); + +describe('is-react-ut', () => { + it('isReactComponent', () => { + expect(isReactComponent(null)).toBeFalsy(); + expect(isReactComponent(() => {})).toBeTruthy(); + expect(isReactComponent({ + $$typeof: Symbol.for('react.memo') + })).toBeTruthy(); + expect(isReactComponent({ + $$typeof: Symbol.for('react.forward_ref') + })).toBeTruthy(); + expect(isReactComponent(reactDemo)).toBeTruthy(); + expect(isReactComponent(reactMemo)).toBeTruthy(); + expect(isReactComponent(reactForwardRef)).toBeTruthy(); + + }); + + it('wrapReactClass', () => { + const wrap = wrapReactClass(() => {}); + expect(isReactComponent(wrap)).toBeTruthy(); + + const fun = () => {}; + fun.displayName = 'mock'; + expect(wrapReactClass(fun).displayName).toBe('mock'); + }) +}) \ No newline at end of file From 016d54bddeb53268bcb36977733fa5fafb656e4d Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 17 Apr 2023 16:35:57 +0800 Subject: [PATCH 104/469] feat(common): add some api to be compatible with old platforms --- packages/shell/src/api/common.tsx | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx index d9009ff8eb..9f38cf1091 100644 --- a/packages/shell/src/api/common.tsx +++ b/packages/shell/src/api/common.tsx @@ -58,6 +58,9 @@ import { untracked as innerUntracked, computed as innerComputed, observer as innerObserver, + action as innerAction, + runInAction as innerRunInAction, + engineConfig as innerEngineConfig, } from '@alilc/lowcode-editor-core'; import { Dragon as ShellDragon } from '../model'; import { ReactNode } from 'react'; @@ -302,6 +305,27 @@ class EditorCabin implements IPublicApiCommonEditorCabin { return innerObx; } + /** + * @deprecated + */ + get action() { + return innerAction; + } + + /** + * @deprecated + */ + get engineConfig() { + return innerEngineConfig; + } + + /** + * @deprecated + */ + get runInAction() { + return innerRunInAction; + } + /** * @deprecated */ From 5c49044a7738713fa5f883f1fa1afa11a898d9bf Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 17 Apr 2023 17:37:33 +0800 Subject: [PATCH 105/469] feat(renderer-core): added log when executing setState --- packages/renderer-core/src/renderer/page.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/renderer-core/src/renderer/page.tsx b/packages/renderer-core/src/renderer/page.tsx index 9ba49c7233..16d55e01be 100644 --- a/packages/renderer-core/src/renderer/page.tsx +++ b/packages/renderer-core/src/renderer/page.tsx @@ -1,6 +1,9 @@ +import { getLogger } from '@alilc/lowcode-utils'; import baseRendererFactory from './base'; import { IBaseRendererProps, IBaseRenderComponent } from '../types'; +const logger = getLogger({ level: 'warn', bizName: 'renderer-core:page' }); + export default function pageRendererFactory(): IBaseRenderComponent { const BaseRenderer = baseRendererFactory(); return class PageRenderer extends BaseRenderer { @@ -29,6 +32,11 @@ export default function pageRendererFactory(): IBaseRenderComponent { super.componentDidUpdate?.(prevProps, _prevState, snapshot); } + setState(state: any, callback?: () => void) { + logger.info('page set state', state); + super.setState(state, callback); + } + render() { const { __schema, __components } = this.props; if (this.__checkSchema(__schema)) { From 2c38c5d9a03dce36f80941e8672d9b1b69562de0 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 17 Apr 2023 17:41:12 +0800 Subject: [PATCH 106/469] feat: remove editor api --- packages/engine/src/engine-core.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 7148bb38ae..a94f192d42 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -152,8 +152,6 @@ export { logger, hotkey, common, - // 兼容原 editor 的事件功能 - event as editor, workspace, canvas, }; From aef10fca0dc73b99ebea76d51ea5dd3d719604ee Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 18 Apr 2023 11:50:23 +0800 Subject: [PATCH 107/469] feat(material): material apis add refreshComponentMetasMap function --- docs/docs/api/material.md | 10 ++++++++++ packages/shell/src/api/material.ts | 11 +++++++++-- packages/types/src/shell/api/material.ts | 6 ++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index b52ad8cb27..5a5502fda6 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -245,6 +245,7 @@ material.getComponentMeta('Input'); ``` #### getComponentMetasMap + 获取所有已注册的物料元数据 ```typescript @@ -264,6 +265,15 @@ import { material } from '@alilc/lowcode-engine'; material.getComponentMetasMap(); ``` +#### refreshComponentMetasMap + +刷新 componentMetasMap,可触发模拟器里的 components 重新构建 + +**@since v1.1.7** + +```typescript + refreshComponentMetasMap(): void; +``` ### 物料元数据管道函数 #### registerMetadataTransducer diff --git a/packages/shell/src/api/material.ts b/packages/shell/src/api/material.ts index e3ebd20ec5..ea9d6e01ba 100644 --- a/packages/shell/src/api/material.ts +++ b/packages/shell/src/api/material.ts @@ -143,9 +143,16 @@ export class Material implements IPublicApiMaterial { * 在设计器辅助层增加一个扩展 action * @param action */ - addBuiltinComponentAction(action: IPublicTypeComponentAction) { + addBuiltinComponentAction = (action: IPublicTypeComponentAction) => { this[designerSymbol].componentActions.addBuiltinComponentAction(action); - } + }; + + /** + * 刷新 componentMetasMap,可触发模拟器里的 components 重新构建 + */ + refreshComponentMetasMap = () => { + this[designerSymbol].refreshComponentMetasMap(); + }; /** * 移除设计器辅助层的指定 action diff --git a/packages/types/src/shell/api/material.ts b/packages/types/src/shell/api/material.ts index 1e9f54996b..d64455eddd 100644 --- a/packages/types/src/shell/api/material.ts +++ b/packages/types/src/shell/api/material.ts @@ -122,4 +122,10 @@ export interface IPublicApiMaterial { * @param fn */ onChangeAssets(fn: () => void): IPublicTypeDisposable; + + /** + * 刷新 componentMetasMap,可触发模拟器里的 components 重新构建 + * @since v1.1.7 + */ + refreshComponentMetasMap(): void; } From 82cdafe07ec57ada9174139ae6f56b5f88c923e1 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 19 Apr 2023 11:55:42 +0800 Subject: [PATCH 108/469] docs(config): add demo for config.getPreference api --- docs/docs/api/config.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/docs/api/config.md b/docs/docs/api/config.md index ea4c7dbfcc..9294b9d289 100644 --- a/docs/docs/api/config.md +++ b/docs/docs/api/config.md @@ -105,6 +105,17 @@ getPreference(): IPublicModelPreference; **@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 From dff06e70ac56466c9c256e54ed95c520dbe41391 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 19 Apr 2023 15:39:31 +0800 Subject: [PATCH 109/469] fix(prop): fix prop.export can not correctly export undefined[] --- packages/designer/src/document/node/props/prop.ts | 6 +----- packages/designer/tests/document/node/props/prop.test.ts | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index b1fd1aec48..5dc1ea5dfe 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -336,13 +336,9 @@ export class Prop implements IProp, IPropParent { if (!this._items) { return this._value; } - const values = this.items!.map((prop) => { + return this.items!.map((prop) => { return prop?.export(stage); }); - if (values.every((val) => val === undefined)) { - return undefined; - } - return values; } } diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 932733b1a2..177bc5247f 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -435,7 +435,7 @@ describe('Prop 类测试', () => { it('should return undefined when all items are undefined', () => { prop = new Prop(mockPropsInst, [undefined, undefined], '___loopArgs___'); - expect(prop.getValue()).toBeUndefined(); + expect(prop.getValue()).toEqual([undefined, undefined]); }); it('迭代器 / map / forEach', () => { From 9b50bc700e18e02d590d7a77591809cdbad8a160 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 19 Apr 2023 15:27:34 +0800 Subject: [PATCH 110/469] feat(workspace): add enableAutoOpenFirstWindow config and onWindowRendererReady function --- packages/editor-core/src/config.ts | 5 +++ packages/engine/src/engine-core.ts | 13 ++++-- packages/shell/src/api/project.ts | 2 +- packages/shell/src/api/skeleton.ts | 7 +++ packages/shell/src/api/workspace.ts | 7 +++ packages/shell/src/model/window.ts | 4 ++ packages/types/src/shell/api/workspace.ts | 8 +++- .../types/src/shell/type/engine-options.ts | 9 ++++ .../workspace/src/context/view-context.ts | 16 +++++-- packages/workspace/src/layouts/workbench.tsx | 2 +- packages/workspace/src/window.ts | 7 +++ packages/workspace/src/workspace.ts | 44 +++++++++++++------ 12 files changed, 101 insertions(+), 23 deletions(-) diff --git a/packages/editor-core/src/config.ts b/packages/editor-core/src/config.ts index ef889e7273..4f0f708e7d 100644 --- a/packages/editor-core/src/config.ts +++ b/packages/editor-core/src/config.ts @@ -145,6 +145,11 @@ const VALID_ENGINE_OPTIONS = { type: 'function', description: '配置指定节点为根组件', }, + enableAutoOpenFirstWindow: { + type: 'boolean', + description: '应用级设计模式下,自动打开第一个窗口', + default: true, + }, }; const getStrictModeValue = (engineOptions: IPublicTypeEngineOptions, defaultValue: boolean): boolean => { diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index a94f192d42..f0c283ec11 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -9,12 +9,15 @@ import { engineConfig, Setters as InnerSetters, Hotkey as InnerHotkey, + IEditor, } from '@alilc/lowcode-editor-core'; import { IPublicTypeEngineOptions, IPublicModelDocumentModel, IPublicTypePluginMeta, IPublicTypeDisposable, + IPublicApiPlugins, + IPublicApiWorkspace, } from '@alilc/lowcode-types'; import { Designer, @@ -22,6 +25,7 @@ import { ILowCodePluginContextPrivate, ILowCodePluginContextApiAssembler, PluginPreference, + IDesigner, } from '@alilc/lowcode-designer'; import { Skeleton as InnerSkeleton, @@ -30,6 +34,7 @@ import { import { Workspace as InnerWorkspace, Workbench as WorkSpaceWorkbench, + IWorkspace, } from '@alilc/lowcode-workspace'; import { @@ -61,7 +66,7 @@ export * from './modules/skeleton-types'; export * from './modules/designer-types'; export * from './modules/lowcode-types'; -async function registryInnerPlugin(designer: Designer, editor: Editor, plugins: Plugins): Promise<IPublicTypeDisposable> { +async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins: IPublicApiPlugins): Promise<IPublicTypeDisposable> { // 注册一批内置插件 const componentMetaParserPlugin = componentMetaParser(designer); const defaultPanelRegistryPlugin = defaultPanelRegistry(editor); @@ -83,8 +88,8 @@ async function registryInnerPlugin(designer: Designer, editor: Editor, plugins: }; } -const innerWorkspace = new InnerWorkspace(registryInnerPlugin, shellModelFactory); -const workspace = new Workspace(innerWorkspace); +const innerWorkspace: IWorkspace = new InnerWorkspace(registryInnerPlugin, shellModelFactory); +const workspace: IPublicApiWorkspace = new Workspace(innerWorkspace); const editor = new Editor(); globalContext.register(editor, Editor); globalContext.register(editor, 'editor'); @@ -207,7 +212,9 @@ export async function init( }), engineContainer, ); + innerWorkspace.enableAutoOpenFirstWindow = engineConfig.get('enableAutoOpenFirstWindow', true); innerWorkspace.setActive(true); + innerWorkspace.initWindow(); innerHotkey.activate(false); await innerWorkspace.plugins.init(pluginPreference); return; diff --git a/packages/shell/src/api/project.ts b/packages/shell/src/api/project.ts index e33a038b91..f005d0af0c 100644 --- a/packages/shell/src/api/project.ts +++ b/packages/shell/src/api/project.ts @@ -32,7 +32,7 @@ export class Project implements IPublicApiProject { } const workspace = globalContext.get('workspace'); if (workspace.isActive) { - if (!workspace.window.innerProject) { + if (!workspace.window?.innerProject) { logger.error('project api 调用时机出现问题,请检查'); return this[innerProjectSymbol]; } diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index 928c55a0de..cb5c8f8aae 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -5,9 +5,12 @@ import { } from '@alilc/lowcode-editor-skeleton'; import { skeletonSymbol } from '../symbols'; import { IPublicApiSkeleton, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; +import { getLogger } from '@alilc/lowcode-utils'; const innerSkeletonSymbol = Symbol('skeleton'); +const logger = getLogger({ level: 'warn', bizName: 'shell-skeleton' }); + export class Skeleton implements IPublicApiSkeleton { private readonly [innerSkeletonSymbol]: ISkeleton; private readonly pluginName: string; @@ -18,6 +21,10 @@ export class Skeleton implements IPublicApiSkeleton { } const workspace = globalContext.get('workspace'); if (workspace.isActive) { + if (!workspace.window.innerSkeleton) { + logger.error('skeleton api 调用时机出现问题,请检查'); + return this[innerSkeletonSymbol]; + } return workspace.window.innerSkeleton; } diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index aa56d0d37d..9676b85222 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -28,9 +28,16 @@ export class Workspace implements IPublicApiWorkspace { } get window() { + if (!this[workspaceSymbol].window) { + return null; + } return new ShellWindow(this[workspaceSymbol].window); } + onWindowRendererReady(fn: () => void): IPublicTypeDisposable { + return this[workspaceSymbol].onWindowRendererReady(fn); + } + registerResourceType(resourceTypeModel: IPublicTypeResourceType): void { this[workspaceSymbol].registerResourceType(resourceTypeModel); } diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index b1263d5415..23bc5c06db 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -41,4 +41,8 @@ export class Window implements IPublicModelWindow { async save() { return await this[windowSymbol].save(); } + + get plugins() { + return this[windowSymbol].plugins; + } } diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index 4422dde4e3..8904a8231c 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -10,7 +10,7 @@ export interface IPublicApiWorkspace< isActive: boolean; /** 当前设计器窗口 */ - window: ModelWindow; + window: ModelWindow | null; plugins: Plugins; @@ -46,4 +46,10 @@ export interface IPublicApiWorkspace< /** active 窗口变更事件 */ onChangeActiveWindow(fn: () => void): IPublicTypeDisposable; + + /** + * window 下的所有视图 renderer ready 事件 + * @since v1.1.7 + */ + onWindowRendererReady(fn: () => void): IPublicTypeDisposable; } \ No newline at end of file diff --git a/packages/types/src/shell/type/engine-options.ts b/packages/types/src/shell/type/engine-options.ts index 195db8912b..f177166530 100644 --- a/packages/types/src/shell/type/engine-options.ts +++ b/packages/types/src/shell/type/engine-options.ts @@ -2,6 +2,7 @@ import { RequestHandlersMap } from '@alilc/lowcode-datasource-types'; import { ComponentType } from 'react'; export interface IPublicTypeEngineOptions { + /** * 是否开启 condition 的能力,默认在设计器中不管 condition 是啥都正常展示 * when this is true, node that configured as conditional not renderring @@ -136,8 +137,10 @@ export interface IPublicTypeEngineOptions { * 与 react-renderer 的 appHelper 一致,https://lowcode-engine.cn/site/docs/guide/expand/runtime/renderer#apphelper */ appHelper?: { + /** 全局公共函数 */ utils?: Record<string, any>; + /** 全局常量 */ constants?: Record<string, any>; }; @@ -168,6 +171,12 @@ export interface IPublicTypeEngineOptions { * 开启应用级设计模式 */ enableWorkspaceMode?: boolean; + + /** + * @default true + * 应用级设计模式下,自动打开第一个窗口 + */ + enableAutoOpenFirstWindow?: boolean; } /** diff --git a/packages/workspace/src/context/view-context.ts b/packages/workspace/src/context/view-context.ts index 38a9e570fa..3939898506 100644 --- a/packages/workspace/src/context/view-context.ts +++ b/packages/workspace/src/context/view-context.ts @@ -17,10 +17,6 @@ export class Context extends BasicContext { @obx isInit: boolean = false; - @computed get active() { - return this._activate; - } - init = flow(function* (this: Context) { if (this.viewType === 'webview') { const url = yield this.instance?.url?.(); @@ -43,6 +39,18 @@ export class Context extends BasicContext { makeObservable(this); } + @computed get active() { + return this._activate; + } + + onSimulatorRendererReady = (): Promise<void> => { + return new Promise((resolve) => { + this.project.onSimulatorRendererReady(() => { + resolve(); + }); + }); + }; + setActivate = (_activate: boolean) => { this._activate = _activate; this.innerHotkey.activate(this._activate); diff --git a/packages/workspace/src/layouts/workbench.tsx b/packages/workspace/src/layouts/workbench.tsx index fe5ef846f6..0c69f9717c 100644 --- a/packages/workspace/src/layouts/workbench.tsx +++ b/packages/workspace/src/layouts/workbench.tsx @@ -47,7 +47,7 @@ export class Workbench extends Component<{ { workspace.windows.map(d => ( <WindowView - active={d.id === workspace.window.id} + active={d.id === workspace.window?.id} window={d} key={d.id} /> diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index 1b9bec410d..37a1622c04 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -82,6 +82,9 @@ export class EditorWindow implements IEditorWindow { async init() { await this.initViewTypes(); await this.execViewTypesInit(); + Promise.all(Array.from(this.editorViews.values()).map((d) => d.onSimulatorRendererReady)).then(() => { + this.workspace.emitWindowRendererReady(); + }); this.url = await this.resource.url(); this.setDefaultViewType(); this.initReady = true; @@ -182,6 +185,10 @@ export class EditorWindow implements IEditorWindow { return this.editorView?.designer; } + get plugins() { + return this.editorView?.plugins; + } + get innerPlugins() { return this.editorView?.innerPlugins; } diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 30c8fcdade..ea19ea0c07 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -1,6 +1,6 @@ import { IDesigner, ILowCodePluginManager, LowCodePluginManager } from '@alilc/lowcode-designer'; -import { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; -import { IPublicApiPlugins, IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types'; +import { createModuleEventBus, Editor, IEditor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; +import { IPublicApiPlugins, IPublicApiWorkspace, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types'; import { BasicContext } from './context/base-context'; import { EditorWindow } from './window'; import type { IEditorWindow } from './window'; @@ -11,6 +11,8 @@ enum EVENT { CHANGE_WINDOW = 'change_window', CHANGE_ACTIVE_WINDOW = 'change_active_window', + + WINDOW_RENDER_READY = 'window_render_ready', } const CHANGE_EVENT = 'resource.list.change'; @@ -19,10 +21,12 @@ export interface IWorkspace extends Omit<IPublicApiWorkspace< LowCodePluginManager, IEditorWindow >, 'resourceList' | 'plugins'> { - readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise<void>; + readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise<IPublicTypeDisposable>; readonly shellModelFactory: IShellModelFactory; + enableAutoOpenFirstWindow: boolean; + window: IEditorWindow; plugins: ILowCodePluginManager; @@ -32,11 +36,19 @@ export interface IWorkspace extends Omit<IPublicApiWorkspace< getResourceType(resourceName: string): IResourceType; checkWindowQueue(): void; + + emitWindowRendererReady(): void; + + initWindow(): void; + + setActive(active: boolean): void; } export class Workspace implements IWorkspace { context: BasicContext; + enableAutoOpenFirstWindow: boolean; + private emitter: IEventBus = createModuleEventBus('workspace'); private _isActive = false; @@ -79,10 +91,10 @@ export class Workspace implements IWorkspace { }[] = []; constructor( - readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise<void>, + readonly registryInnerPlugin: (designer: IDesigner, editor: IEditor, plugins: IPublicApiPlugins) => Promise<IPublicTypeDisposable>, readonly shellModelFactory: any, ) { - this.init(); + this.context = new BasicContext(this, ''); makeObservable(this); } @@ -97,13 +109,8 @@ export class Workspace implements IWorkspace { } } - init() { - this.initWindow(); - this.context = new BasicContext(this, ''); - } - initWindow() { - if (!this.defaultResourceType) { + if (!this.defaultResourceType || this.enableAutoOpenFirstWindow === false) { return; } const resourceName = this.defaultResourceType.name; @@ -128,7 +135,7 @@ export class Workspace implements IWorkspace { const resourceType = new ResourceType(resourceTypeModel); this.resourceTypeMap.set(resourceTypeModel.resourceName, resourceType); - if (!this.window && this.defaultResourceType) { + if (!this.window && this.defaultResourceType && this._isActive) { this.initWindow(); } } @@ -149,6 +156,17 @@ export class Workspace implements IWorkspace { }; } + onWindowRendererReady(fn: () => void): IPublicTypeDisposable { + this.emitter.on(EVENT.WINDOW_RENDER_READY, fn); + return () => { + this.emitter.off(EVENT.WINDOW_RENDER_READY, fn); + }; + } + + emitWindowRendererReady() { + this.emitter.emit(EVENT.WINDOW_RENDER_READY); + } + getResourceType(resourceName: string): IResourceType { return this.resourceTypeMap.get(resourceName)!; } @@ -188,7 +206,7 @@ export class Workspace implements IWorkspace { } openEditorWindow(name: string, title: string, options: Object, viewType?: string, sleep?: boolean) { - if (!this.window?.initReady && !sleep) { + if (this.window && !this.window?.initReady && !sleep) { this.windowQueue.push({ name, title, options, viewType, }); From 832e2a0aa3e2bfe87e5c1977682c4837c5167a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Wed, 19 Apr 2023 16:12:22 +0800 Subject: [PATCH 111/469] chore: add awesome badge for exploring LCE ecosystem --- packages/engine/README-zh_CN.md | 4 ++-- packages/engine/README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/engine/README-zh_CN.md b/packages/engine/README-zh_CN.md index b5256af9ca..c99e98cf6c 100644 --- a/packages/engine/README-zh_CN.md +++ b/packages/engine/README-zh_CN.md @@ -14,8 +14,8 @@ [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url] -[![codecov][codecov-image-url]][codecov-url] - +[![codecov][codecov-image-url]][codecov-url] [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/lowcode-workspace/awesome-lowcode-engine) + [![](https://img.shields.io/badge/LowCodeEngine-%E6%9F%A5%E7%9C%8B%E8%B4%A1%E7%8C%AE%E6%8E%92%E8%A1%8C%E6%A6%9C-orange)](https://opensource.alibaba.com/contribution_leaderboard/details?projectValue=lowcode-engine) [npm-image]: https://img.shields.io/npm/v/@alilc/lowcode-engine.svg?style=flat-square diff --git a/packages/engine/README.md b/packages/engine/README.md index 2d1254e4a5..52bce86163 100644 --- a/packages/engine/README.md +++ b/packages/engine/README.md @@ -14,7 +14,7 @@ An enterprise-class low-code technology stack with scale-out design [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url] -[![codecov][codecov-image-url]][codecov-url] +[![codecov][codecov-image-url]][codecov-url] [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/lowcode-workspace/awesome-lowcode-engine) [![](https://img.shields.io/badge/LowCodeEngine-Check%20Your%20Contribution-orange)](https://opensource.alibaba.com/contribution_leaderboard/details?projectValue=lowcode-engine) From e964492b89dec702a1c54467e3c45e2b850a4dd5 Mon Sep 17 00:00:00 2001 From: "{authemail@qq.com}" <authemail@qq.com> Date: Thu, 20 Apr 2023 10:02:10 +0800 Subject: [PATCH 112/469] =?UTF-8?q?docs:=20=E4=BF=AE=E5=A4=8D=E8=A1=A8?= =?UTF-8?q?=E6=A0=BC=E6=8E=92=E7=89=88=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/demoUsage/panels/code.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/docs/docs/demoUsage/panels/code.md b/docs/docs/demoUsage/panels/code.md index 929c9bcb08..645fcc7af4 100644 --- a/docs/docs/demoUsage/panels/code.md +++ b/docs/docs/demoUsage/panels/code.md @@ -45,16 +45,13 @@ window.Next.Message.success('成功') - 读取:每次打开面板时,都会尝试读取 schema 中的 originCode 字段,如果没有,则从 schema 上的字段还原代码; - 写入:在关闭代码编辑面板(主动点击叉或者点击非代码编辑区块的被动关闭都算)时,将自动写入到 schema 中;您也可以在编辑过程中点击“保存”按钮手动保存; -| 源码面板中 | schema 中 | + +| 源码面板中 | Schema 中 | | --- | --- | -| 本地数据初始值设置: -![image.png](https://img.alicdn.com/imgextra/i4/O1CN01V6iaTY1gVNHi7gQfK_!!6000000004147-2-tps-370-146.png) | ![image.png](https://img.alicdn.com/imgextra/i2/O1CN010rhIPa268BEfGmzO6_!!6000000007616-2-tps-2098-826.png) | -| 生命周期方法: -![image.png](https://img.alicdn.com/imgextra/i4/O1CN010Y1TxV1QOvrVLRUjD_!!6000000001967-2-tps-478-260.png) | ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01pbJzVQ1VSfAL7Lh8G_!!6000000002652-2-tps-2010-836.png) | -| 自定义函数: -![image.png](https://img.alicdn.com/imgextra/i4/O1CN01S2gjFk1CU3fm61eiD_!!6000000000083-2-tps-660-642.png) | ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01X35YxU1GUkjj1YWVj_!!6000000000626-2-tps-1862-822.png) | -| 编译前全量代码: -![image.png](https://img.alicdn.com/imgextra/i2/O1CN01sbiK9N1kc1Uxp1OHY_!!6000000004703-2-tps-762-1122.png) | ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01adKSg61QXAzRjQ4bm_!!6000000001985-2-tps-1906-796.png) | +| 本地数据初始值设置:![image.png](https://img.alicdn.com/imgextra/i4/O1CN01V6iaTY1gVNHi7gQfK_!!6000000004147-2-tps-370-146.png) | ![image.png](https://img.alicdn.com/imgextra/i2/O1CN010rhIPa268BEfGmzO6_!!6000000007616-2-tps-2098-826.png) | +| 生命周期方法:![image.png](https://img.alicdn.com/imgextra/i4/O1CN010Y1TxV1QOvrVLRUjD_!!6000000001967-2-tps-478-260.png) | ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01pbJzVQ1VSfAL7Lh8G_!!6000000002652-2-tps-2010-836.png) | +| 自定义函数:![image.png](https://img.alicdn.com/imgextra/i4/O1CN01S2gjFk1CU3fm61eiD_!!6000000000083-2-tps-660-642.png) | ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01X35YxU1GUkjj1YWVj_!!6000000000626-2-tps-1862-822.png) | +| 编译前全量代码:![image.png](https://img.alicdn.com/imgextra/i2/O1CN01sbiK9N1kc1Uxp1OHY_!!6000000004703-2-tps-762-1122.png) | ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01adKSg61QXAzRjQ4bm_!!6000000001985-2-tps-1906-796.png) | - 异常处理:如果代码解析失败,它将无法被正常保存到 schema 中,此时编辑器会弹层提示: From f2e014cdbea998725559dd0f0c65df3c2520af72 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 20 Apr 2023 10:38:53 +0800 Subject: [PATCH 113/469] chore(docs): publish docs 1.0.27 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 4c8cfc1619..8c6e8a86cb 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.26", + "version": "1.0.27", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 4a18f71ebc1d74a9c719f1260e9c324f0c7dfdbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Wed, 19 Apr 2023 16:48:16 +0800 Subject: [PATCH 114/469] feat: add workflow for checking base branch --- .github/workflows/check base branch.yml | 33 +++++++++++++++++++ .github/workflows/help wanted.yml | 2 +- .../workflows/insufficient information.yml | 2 +- .github/workflows/test modules.yml | 2 +- .github/workflows/test packages.yml | 2 +- 5 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/check base branch.yml diff --git a/.github/workflows/check base branch.yml b/.github/workflows/check base branch.yml new file mode 100644 index 0000000000..cef996c75a --- /dev/null +++ b/.github/workflows/check base branch.yml @@ -0,0 +1,33 @@ +name: Check Base Branch + +on: + pull_request: + types: [opened] + +jobs: + code-review: + name: Check + runs-on: ubuntu-latest + + steps: + # 判断用户是否有写仓库权限 + - name: 'Check User Permission' + uses: 'lannonbr/repo-permission-check-action@2.0.0' + with: + permission: 'write' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: 'Check base branch name is develop or not' + if: github.event.pull_request.base.ref != 'develop' # check the target branch if it's master + uses: actions-cool/issues-helper@v2 + with: + actions: 'create-comment' + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.pull_request.number }} + body: | + 感谢你的 PR,根据引擎的 [研发协作流程](https://lowcode-engine.cn/site/docs/participate/flow),请将目标合入分支设置为 **develop**。 + + Thanks in advance, according to the [Contribution Guideline](https://lowcode-engine.cn/site/docs/participate/flow), please set the base branch to **develop**. + + @${{ github.event.pull_request.user.login }} \ No newline at end of file diff --git a/.github/workflows/help wanted.yml b/.github/workflows/help wanted.yml index 94927ad28f..619d08b936 100644 --- a/.github/workflows/help wanted.yml +++ b/.github/workflows/help wanted.yml @@ -1,4 +1,4 @@ -name: Issue Reply +name: Help Wanted on: issues: diff --git a/.github/workflows/insufficient information.yml b/.github/workflows/insufficient information.yml index 15885043a0..c49e133f16 100644 --- a/.github/workflows/insufficient information.yml +++ b/.github/workflows/insufficient information.yml @@ -1,4 +1,4 @@ -name: Issue Reply +name: Insufficient Info on: issues: diff --git a/.github/workflows/test modules.yml b/.github/workflows/test modules.yml index 9410626e88..b2464cc40c 100644 --- a/.github/workflows/test modules.yml +++ b/.github/workflows/test modules.yml @@ -1,4 +1,4 @@ -name: lint & test +name: Lint & Test (Mods) on: push: diff --git a/.github/workflows/test packages.yml b/.github/workflows/test packages.yml index 5d1ee89076..4ee9b4156c 100644 --- a/.github/workflows/test packages.yml +++ b/.github/workflows/test packages.yml @@ -1,4 +1,4 @@ -name: lint & test +name: Lint & Test (Pkgs) on: push: From aab8a3a10ec1612164de76aec81f196d5e395dc5 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 21 Apr 2023 16:29:25 +0800 Subject: [PATCH 115/469] feat: update setter types --- packages/editor-core/src/di/setter.ts | 11 +++++---- .../src/components/settings/settings-pane.tsx | 13 ++++++----- packages/shell/src/api/setters.ts | 23 +++++++++++-------- packages/types/src/shell/api/setters.ts | 8 +++++++ 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/packages/editor-core/src/di/setter.ts b/packages/editor-core/src/di/setter.ts index 4139c59394..437d9a89e2 100644 --- a/packages/editor-core/src/di/setter.ts +++ b/packages/editor-core/src/di/setter.ts @@ -1,8 +1,7 @@ import { ReactNode } from 'react'; -import { IPublicTypeCustomView, IPublicTypeRegisteredSetter } from '@alilc/lowcode-types'; +import { IPublicApiSetters, IPublicTypeCustomView, IPublicTypeRegisteredSetter } from '@alilc/lowcode-types'; import { createContent, isCustomView } from '@alilc/lowcode-utils'; - const settersMap = new Map<string, IPublicTypeRegisteredSetter & { type: string; }>(); @@ -44,13 +43,17 @@ function getInitialFromSetter(setter: any) { ) || null; // eslint-disable-line } -export class Setters { - constructor(readonly viewName: string = 'global') {} +export interface ISetters extends IPublicApiSetters { + +} +export class Setters implements ISetters { settersMap = new Map<string, IPublicTypeRegisteredSetter & { type: string; }>(); + constructor(readonly viewName: string = 'global') {} + getSetter = (type: string): IPublicTypeRegisteredSetter | null => { return this.settersMap.get(type) || null; }; diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index 31ea78cced..9cc8d9caed 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -1,14 +1,13 @@ -import { Component, MouseEvent, Fragment } from 'react'; +import { Component, MouseEvent, Fragment, ReactNode } from 'react'; import { shallowIntl, observer, obx, engineConfig, runInAction } from '@alilc/lowcode-editor-core'; import { createContent, isJSSlot, isSetterConfig } from '@alilc/lowcode-utils'; import { Skeleton, Stage } from '@alilc/lowcode-editor-skeleton'; -import { IPublicTypeCustomView } from '@alilc/lowcode-types'; +import { IPublicApiSetters, IPublicTypeCustomView, IPublicTypeDynamicProps } from '@alilc/lowcode-types'; import { ISettingEntry, IComponentMeta, ISettingField, isSettingField, ISettingTopEntry } from '@alilc/lowcode-designer'; import { createField } from '../field'; import PopupService, { PopupPipe } from '../popup'; import { SkeletonContext } from '../../context'; import { intl } from '../../locale'; -import { Setters } from '@alilc/lowcode-shell'; function isStandardComponent(componentMeta: IComponentMeta | null) { if (!componentMeta) return false; @@ -40,7 +39,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView stageName: string | undefined; - setters?: Setters; + setters?: IPublicApiSetters; constructor(props: SettingFieldViewProps) { super(props); @@ -112,7 +111,9 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView const { defaultValue } = extraProps; const { setter } = this.field; - let setterProps: any = {}; + let setterProps: { + setters?: (ReactNode | string)[]; + } & Record<string, unknown> | IPublicTypeDynamicProps = {}; let setterType: any; let initialValue: any = null; @@ -236,7 +237,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView ...extraProps, }, !stageName && - this.setters.createSetterContent(setterType, { + this.setters?.createSetterContent(setterType, { ...shallowIntl(setterProps), forceInline: extraProps.forceInline, key: field.id, diff --git a/packages/shell/src/api/setters.ts b/packages/shell/src/api/setters.ts index 72d29c8a8b..56f42d18ba 100644 --- a/packages/shell/src/api/setters.ts +++ b/packages/shell/src/api/setters.ts @@ -1,5 +1,5 @@ import { IPublicTypeCustomView, IPublicApiSetters, IPublicTypeRegisteredSetter } from '@alilc/lowcode-types'; -import { Setters as InnerSetters, globalContext } from '@alilc/lowcode-editor-core'; +import { ISetters, globalContext, untracked } from '@alilc/lowcode-editor-core'; import { ReactNode } from 'react'; import { getLogger } from '@alilc/lowcode-utils'; @@ -9,26 +9,28 @@ const settersSymbol = Symbol('setters'); const logger = getLogger({ level: 'warn', bizName: 'shell-setters' }); export class Setters implements IPublicApiSetters { - readonly [innerSettersSymbol]: InnerSetters; + readonly [innerSettersSymbol]: ISetters; - get [settersSymbol](): InnerSetters { + get [settersSymbol](): ISetters { if (this.workspaceMode) { return this[innerSettersSymbol]; } const workspace = globalContext.get('workspace'); if (workspace.isActive) { - if (!workspace.window.innerSetters) { - logger.error('setter api 调用时机出现问题,请检查'); - return this[innerSettersSymbol]; - } - return workspace.window.innerSetters; + return untracked(() => { + if (!workspace.window.innerSetters) { + logger.error('setter api 调用时机出现问题,请检查'); + return this[innerSettersSymbol]; + } + return workspace.window.innerSetters; + }); } return this[innerSettersSymbol]; } - constructor(innerSetters: InnerSetters, readonly workspaceMode = false) { + constructor(innerSetters: ISetters, readonly workspaceMode = false) { this[innerSettersSymbol] = innerSetters; } @@ -64,6 +66,9 @@ export class Setters implements IPublicApiSetters { return this[settersSymbol].registerSetter(typeOrMaps, setter); }; + /** + * @deprecated + */ createSetterContent = (setter: any, props: Record<string, any>): ReactNode => { return this[settersSymbol].createSetterContent(setter, props); }; diff --git a/packages/types/src/shell/api/setters.ts b/packages/types/src/shell/api/setters.ts index 9ff2e8edaf..011a9dcacd 100644 --- a/packages/types/src/shell/api/setters.ts +++ b/packages/types/src/shell/api/setters.ts @@ -1,6 +1,9 @@ +import { ReactNode } from 'react'; + import { IPublicTypeRegisteredSetter, IPublicTypeCustomView } from '../type'; export interface IPublicApiSetters { + /** * 获取指定 setter * get setter by type @@ -29,4 +32,9 @@ export interface IPublicApiSetters { typeOrMaps: string | { [key: string]: IPublicTypeCustomView | IPublicTypeRegisteredSetter }, setter?: IPublicTypeCustomView | IPublicTypeRegisteredSetter | undefined ): void; + + /** + * @deprecated + */ + createSetterContent (setter: any, props: Record<string, any>): ReactNode; } From c50a0823db7630f20ad29d66d3f63a836285cd27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=92=E6=9C=A8?= <31089228+StringKe@users.noreply.github.com> Date: Sat, 22 Apr 2023 04:42:16 +0000 Subject: [PATCH 116/469] =?UTF-8?q?feat(utils):=20cursor=20=E4=B8=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=20less?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/utils/src/cursor.css | 19 +++++++++++++++++++ packages/utils/src/cursor.less | 15 --------------- packages/utils/src/cursor.ts | 2 +- 3 files changed, 20 insertions(+), 16 deletions(-) create mode 100644 packages/utils/src/cursor.css delete mode 100644 packages/utils/src/cursor.less diff --git a/packages/utils/src/cursor.css b/packages/utils/src/cursor.css new file mode 100644 index 0000000000..e13da656ea --- /dev/null +++ b/packages/utils/src/cursor.css @@ -0,0 +1,19 @@ +html.lc-cursor-dragging, +html.lc-cursor-dragging * { + cursor: move !important; +} + +html.lc-cursor-x-resizing, +html.lc-cursor-x-resizing * { + cursor: col-resize; +} + +html.lc-cursor-y-resizing, +html.lc-cursor-y-resizing * { + cursor: row-resize; +} + +html.lc-cursor-copy, +html.lc-cursor-copy * { + cursor: copy !important; +} diff --git a/packages/utils/src/cursor.less b/packages/utils/src/cursor.less deleted file mode 100644 index 30c890862e..0000000000 --- a/packages/utils/src/cursor.less +++ /dev/null @@ -1,15 +0,0 @@ -html.lc-cursor-dragging, html.lc-cursor-dragging * { - cursor: move !important; -} - -html.lc-cursor-x-resizing, html.lc-cursor-x-resizing * { - cursor: col-resize; -} - -html.lc-cursor-y-resizing, html.lc-cursor-y-resizing * { - cursor: row-resize; -} - -html.lc-cursor-copy, html.lc-cursor-copy * { - cursor: copy !important; -} diff --git a/packages/utils/src/cursor.ts b/packages/utils/src/cursor.ts index fea4bce65b..c12ec64b92 100644 --- a/packages/utils/src/cursor.ts +++ b/packages/utils/src/cursor.ts @@ -1,4 +1,4 @@ -import './cursor.less'; +import './cursor.css'; export class Cursor { private states = new Set<string>(); From 358dde43a4a6097abc71fd47e708cca7af105acf Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Sun, 23 Apr 2023 17:33:32 +0800 Subject: [PATCH 117/469] feat(shell): add editor-view model --- docs/docs/api/model/editor-view.md | 21 +++ docs/docs/api/model/window.md | 16 ++ packages/designer/src/plugin/plugin-types.ts | 2 + packages/engine/src/engine-core.ts | 2 + packages/plugin-outline-pane/package.json | 2 - .../src/controllers/pane-controller.ts | 13 +- .../src/controllers/tree-master.ts | 172 +++++++++++++----- .../src/controllers/tree-node.ts | 8 +- .../src/controllers/tree.ts | 14 +- packages/plugin-outline-pane/src/index.tsx | 30 ++- .../plugin-outline-pane/src/views/filter.tsx | 13 +- .../plugin-outline-pane/src/views/pane.tsx | 40 +++- .../src/views/tree-branches.tsx | 26 ++- .../src/views/tree-node.tsx | 25 ++- .../src/views/tree-title.tsx | 37 ++-- .../plugin-outline-pane/src/views/tree.tsx | 36 ++-- packages/shell/src/model/editor-view.ts | 27 +++ packages/shell/src/model/index.ts | 1 + packages/shell/src/model/window.ts | 9 +- packages/shell/src/symbols.ts | 2 + packages/types/src/shell/enum/index.ts | 3 +- .../src/shell/enum/plugin-register-level.ts | 6 + packages/types/src/shell/model/dragon.ts | 8 +- packages/types/src/shell/model/editor-view.ts | 3 + packages/types/src/shell/model/index.ts | 1 + .../types/src/shell/model/plugin-context.ts | 15 +- packages/types/src/shell/model/window.ts | 13 ++ .../workspace/src/context/base-context.ts | 4 +- .../workspace/src/context/view-context.ts | 12 +- packages/workspace/src/index.ts | 1 + packages/workspace/src/resource.ts | 4 +- packages/workspace/src/window.ts | 11 +- packages/workspace/src/workspace.ts | 4 +- 33 files changed, 395 insertions(+), 186 deletions(-) create mode 100644 docs/docs/api/model/editor-view.md create mode 100644 packages/shell/src/model/editor-view.ts create mode 100644 packages/types/src/shell/enum/plugin-register-level.ts create mode 100644 packages/types/src/shell/model/editor-view.ts diff --git a/docs/docs/api/model/editor-view.md b/docs/docs/api/model/editor-view.md new file mode 100644 index 0000000000..a3cc83e1f2 --- /dev/null +++ b/docs/docs/api/model/editor-view.md @@ -0,0 +1,21 @@ +--- +title: EditorView +sidebar_position: 12 +--- + +> **[@experimental](./#experimental)**<br/> +> **@types** [IPublicModelEditorView](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/editor-view.ts)<br/> +> **@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) diff --git a/docs/docs/api/model/window.md b/docs/docs/api/model/window.md index f102c0cab3..3cc8b5d5e7 100644 --- a/docs/docs/api/model/window.md +++ b/docs/docs/api/model/window.md @@ -38,6 +38,22 @@ sidebar_position: 12 关联模型 [IPublicModelResource](./resource) +### currentEditorView +窗口当前视图 + +`@type {IPublicModelEditorView}` + +关联模型 [IPublicModelEditorView](./editor-view) + +### editorViews + +窗口所有视图 + +`@type {IPublicModelEditorView[]}` + +关联模型 [IPublicModelEditorView](./editor-view) + + ## 方法 ### importSchema diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index 23aac2849d..ac08d7d0ca 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -17,6 +17,7 @@ import { IPublicTypePluginMeta, IPublicTypePluginRegisterOptions, IPublicModelWindow, + IPublicEnumPluginRegisterLevel, } from '@alilc/lowcode-types'; import PluginContext from './plugin-context'; @@ -58,6 +59,7 @@ export interface ILowCodePluginContextPrivate { set canvas(canvas: IPublicApiCanvas); set workspace(workspace: IPublicApiWorkspace); set editorWindow(window: IPublicModelWindow); + set registerLevel(level: IPublicEnumPluginRegisterLevel); } export interface ILowCodePluginContextApiAssembler { assembleApis( diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index f0c283ec11..84dfd67aa8 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -18,6 +18,7 @@ import { IPublicTypeDisposable, IPublicApiPlugins, IPublicApiWorkspace, + IPublicEnumPluginRegisterLevel, } from '@alilc/lowcode-types'; import { Designer, @@ -138,6 +139,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.plugins = plugins; context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.workspace = workspace; + context.registerLevel = IPublicEnumPluginRegisterLevel.Default; }, }; diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index ec4738cd76..8a1472ce20 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -13,8 +13,6 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-designer": "1.1.6", - "@alilc/lowcode-editor-core": "1.1.6", "@alilc/lowcode-types": "1.1.6", "@alilc/lowcode-utils": "1.1.6", "classnames": "^2.2.6", diff --git a/packages/plugin-outline-pane/src/controllers/pane-controller.ts b/packages/plugin-outline-pane/src/controllers/pane-controller.ts index a02844ad1b..e7c41892c6 100644 --- a/packages/plugin-outline-pane/src/controllers/pane-controller.ts +++ b/packages/plugin-outline-pane/src/controllers/pane-controller.ts @@ -16,16 +16,15 @@ import { IPublicModelDropLocation, IPublicModelScroller, IPublicModelScrollTarget, - IPublicModelPluginContext, IPublicModelLocateEvent, } from '@alilc/lowcode-types'; import TreeNode from './tree-node'; import { IndentTrack } from '../helper/indent-track'; import DwellTimer from '../helper/dwell-timer'; -import { ITreeBoard, TreeMaster } from './tree-master'; +import { IOutlinePanelPluginContext, ITreeBoard, TreeMaster } from './tree-master'; export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTypeScrollable { - private pluginContext: IPublicModelPluginContext; + private pluginContext: IOutlinePanelPluginContext; private treeMaster?: TreeMaster; @@ -100,8 +99,8 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTy private _shell: HTMLDivElement | null = null; - constructor(at: string | symbol, pluginContext: IPublicModelPluginContext, treeMaster: TreeMaster) { - this.pluginContext = pluginContext; + constructor(at: string | symbol, treeMaster: TreeMaster) { + this.pluginContext = treeMaster.pluginContext; this.treeMaster = treeMaster; this.at = at; let inited = false; @@ -237,7 +236,7 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTy let { node } = treeNode; if (isDragNodeObject(dragObject)) { const newNodes = operationalNodes; - let i = newNodes.length; + let i = newNodes?.length; let p: any = node; while (i-- > 0) { if (newNodes[i].contains(p)) { @@ -482,7 +481,7 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTy const isSlotContainer = treeNode.hasSlots(); const isContainer = treeNode.isContainer(); - if (container.isSlot && !treeNode.expanded) { + if (container.isSlotNode && !treeNode.expanded) { // 未展开,直接定位到内部第一个节点 if (isSlotContainer) { detail.index = null; diff --git a/packages/plugin-outline-pane/src/controllers/tree-master.ts b/packages/plugin-outline-pane/src/controllers/tree-master.ts index 074ed3447b..a6852803b3 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-master.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-master.ts @@ -1,69 +1,141 @@ import { isLocationChildrenDetail } from '@alilc/lowcode-utils'; -import { IPublicModelPluginContext, IPublicTypeActiveTarget, IPublicModelNode } from '@alilc/lowcode-types'; +import { IPublicModelPluginContext, IPublicTypeActiveTarget, IPublicModelNode, IPublicTypeDisposable, IPublicEnumPluginRegisterLevel } from '@alilc/lowcode-types'; import TreeNode from './tree-node'; import { Tree } from './tree'; +import EventEmitter from 'events'; +import { enUS, zhCN } from '../locale'; +import { ReactNode } from 'react'; export interface ITreeBoard { readonly at: string | symbol; scrollToNode(treeNode: TreeNode, detail?: any): void; } +enum EVENT_NAMES { + pluginContextChanged = 'pluginContextChanged', +} + +export interface IOutlinePanelPluginContext extends IPublicModelPluginContext { + extraTitle?: string; + intlNode(id: string, params?: object): ReactNode; + intl(id: string, params?: object): string; + getLocale(): string; +} + export class TreeMaster { - readonly pluginContext: IPublicModelPluginContext; + pluginContext: IOutlinePanelPluginContext; private boards = new Set<ITreeBoard>(); private treeMap = new Map<string, Tree>(); - constructor(pluginContext: IPublicModelPluginContext) { - this.pluginContext = pluginContext; - let startTime: any; - const { event, project, canvas } = this.pluginContext; - canvas.dragon?.onDragstart(() => { - startTime = Date.now() / 1000; - // needs? - this.toVision(); - }); - canvas.activeTracker?.onChange((target: IPublicTypeActiveTarget) => { - const { node, detail } = target; - const tree = this.currentTree; - if (!tree/* || node.document !== tree.document */) { - return; - } - const treeNode = tree.getTreeNode(node); - if (detail && isLocationChildrenDetail(detail)) { - treeNode.expand(true); - } else { - treeNode.expandParents(); - } - this.boards.forEach((board) => { - board.scrollToNode(treeNode, detail); + private disposeEvents: (IPublicTypeDisposable | undefined)[] = []; + + event = new EventEmitter(); + + constructor(pluginContext: IPublicModelPluginContext, readonly options: { + extraTitle?: string; + }) { + this.setPluginContext(pluginContext); + const { workspace } = this.pluginContext; + this.initEvent(); + if (pluginContext.registerLevel === IPublicEnumPluginRegisterLevel.Workspace) { + workspace.onWindowRendererReady(() => { + this.setPluginContext(workspace.window?.currentEditorView); + let dispose: IPublicTypeDisposable | undefined; + const windowViewTypeChangeEvent = () => { + dispose = workspace.window?.onChangeViewType(() => { + this.setPluginContext(workspace.window?.currentEditorView); + }); + }; + + windowViewTypeChangeEvent(); + + workspace.onChangeActiveWindow(() => { + windowViewTypeChangeEvent(); + this.setPluginContext(workspace.window?.currentEditorView); + dispose && dispose(); + }); }); + } + } + + private setPluginContext(pluginContext: IPublicModelPluginContext | undefined) { + if (!pluginContext) { + return; + } + const { intl, intlNode, getLocale } = pluginContext.common.utils.createIntl({ + 'en-US': enUS, + 'zh-CN': zhCN, }); - canvas.dragon?.onDragend(() => { - const endTime: any = Date.now() / 1000; - const nodes = project.currentDocument?.selection?.getNodes(); - event.emit('outlinePane.dragend', { - selected: nodes - ?.map((n) => { - if (!n) { - return; - } - const npm = n?.componentMeta?.npm; - return ( - [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || n?.componentMeta?.componentName - ); - }) - .join('&'), - time: (endTime - startTime).toFixed(2), - }); + let _pluginContext: IOutlinePanelPluginContext = Object.assign(pluginContext, { + intl, + intlNode, + getLocale, }); - project.onRemoveDocument((data: {id: string}) => { - const { id } = data; - this.treeMap.delete(id); + _pluginContext.extraTitle = this.options && this.options['extraTitle']; + this.pluginContext = _pluginContext; + this.disposeEvent(); + this.initEvent(); + this.emitPluginContextChange(); + } + + private disposeEvent() { + this.disposeEvents.forEach(d => { + d && d(); }); } + private initEvent() { + let startTime: any; + const { event, project, canvas } = this.pluginContext; + this.disposeEvents = [ + canvas.dragon?.onDragstart(() => { + startTime = Date.now() / 1000; + // needs? + this.toVision(); + }), + canvas.activeTracker?.onChange((target: IPublicTypeActiveTarget) => { + const { node, detail } = target; + const tree = this.currentTree; + if (!tree/* || node.document !== tree.document */) { + return; + } + const treeNode = tree.getTreeNode(node); + if (detail && isLocationChildrenDetail(detail)) { + treeNode.expand(true); + } else { + treeNode.expandParents(); + } + this.boards.forEach((board) => { + board.scrollToNode(treeNode, detail); + }); + }), + canvas.dragon?.onDragend(() => { + const endTime: any = Date.now() / 1000; + const nodes = project.currentDocument?.selection?.getNodes(); + event.emit('outlinePane.dragend', { + selected: nodes + ?.map((n) => { + if (!n) { + return; + } + const npm = n?.componentMeta?.npm; + return ( + [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || n?.componentMeta?.componentName + ); + }) + .join('&'), + time: (endTime - startTime).toFixed(2), + }); + }), + project.onRemoveDocument((data: {id: string}) => { + const { id } = data; + this.treeMap.delete(id); + }), + ]; + } + private toVision() { const tree = this.currentTree; if (tree) { @@ -86,6 +158,14 @@ export class TreeMaster { // todo others purge } + onPluginContextChange(fn: () => void) { + this.event.on(EVENT_NAMES.pluginContextChanged, fn); + } + + emitPluginContextChange() { + this.event.emit(EVENT_NAMES.pluginContextChanged); + } + get currentTree(): Tree | null { const doc = this.pluginContext.project.getCurrentDocument(); if (doc) { @@ -93,7 +173,7 @@ export class TreeMaster { if (this.treeMap.has(id)) { return this.treeMap.get(id)!; } - const tree = new Tree(this.pluginContext); + const tree = new Tree(this); this.treeMap.set(id, tree); return tree; } diff --git a/packages/plugin-outline-pane/src/controllers/tree-node.ts b/packages/plugin-outline-pane/src/controllers/tree-node.ts index 62f373e2aa..2a6bc0aca0 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-node.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-node.ts @@ -2,12 +2,12 @@ import { IPublicTypeTitleContent, IPublicTypeLocationChildrenDetail, IPublicModelNode, - IPublicModelPluginContext, IPublicTypeDisposable, } from '@alilc/lowcode-types'; import { isI18nData, isLocationChildrenDetail } from '@alilc/lowcode-utils'; import EventEmitter from 'events'; import { Tree } from './tree'; +import { IOutlinePanelPluginContext } from './tree-master'; /** * 大纲树过滤结果 @@ -38,7 +38,7 @@ enum EVENT_NAMES { } export default class TreeNode { - readonly pluginContext: IPublicModelPluginContext; + readonly pluginContext: IOutlinePanelPluginContext; event = new EventEmitter(); private _node: IPublicModelNode; @@ -160,9 +160,9 @@ export default class TreeNode { return this._node; } - constructor(tree: Tree, node: IPublicModelNode, pluginContext: IPublicModelPluginContext) { + constructor(tree: Tree, node: IPublicModelNode) { this.tree = tree; - this.pluginContext = pluginContext; + this.pluginContext = tree.pluginContext; this._node = node; } diff --git a/packages/plugin-outline-pane/src/controllers/tree.ts b/packages/plugin-outline-pane/src/controllers/tree.ts index c0098794c6..94cab78797 100644 --- a/packages/plugin-outline-pane/src/controllers/tree.ts +++ b/packages/plugin-outline-pane/src/controllers/tree.ts @@ -1,12 +1,13 @@ import TreeNode from './tree-node'; -import { IPublicModelNode, IPublicModelPluginContext, IPublicTypePropChangeOptions } from '@alilc/lowcode-types'; +import { IPublicModelNode, IPublicTypePropChangeOptions } from '@alilc/lowcode-types'; +import { IOutlinePanelPluginContext, TreeMaster } from './tree-master'; export class Tree { private treeNodesMap = new Map<string, TreeNode>(); readonly id: string | undefined; - readonly pluginContext: IPublicModelPluginContext; + readonly pluginContext: IOutlinePanelPluginContext; get root(): TreeNode | null { if (this.pluginContext.project.currentDocument?.focusNode) { @@ -15,8 +16,11 @@ export class Tree { return null; } - constructor(pluginContext: IPublicModelPluginContext) { - this.pluginContext = pluginContext; + readonly treeMaster: TreeMaster; + + constructor(treeMaster: TreeMaster) { + this.treeMaster = treeMaster; + this.pluginContext = treeMaster.pluginContext; const doc = this.pluginContext.project.currentDocument; this.id = doc?.id; @@ -51,7 +55,7 @@ export class Tree { return tnode; } - const treeNode = new TreeNode(this, node, this.pluginContext); + const treeNode = new TreeNode(this, node); this.treeNodesMap.set(node.id, treeNode); return treeNode; } diff --git a/packages/plugin-outline-pane/src/index.tsx b/packages/plugin-outline-pane/src/index.tsx index 701e46540a..1ea53b2f06 100644 --- a/packages/plugin-outline-pane/src/index.tsx +++ b/packages/plugin-outline-pane/src/index.tsx @@ -1,21 +1,13 @@ import { Pane } from './views/pane'; import { IconOutline } from './icons/outline'; import { IPublicModelPluginContext, IPublicModelDocumentModel } from '@alilc/lowcode-types'; -import { enUS, zhCN } from './locale'; import { MasterPaneName, BackupPaneName } from './helper/consts'; import { TreeMaster } from './controllers/tree-master'; import { PaneController } from './controllers/pane-controller'; +import { useState } from 'react'; export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { - const { skeleton, config, common, event, canvas, project } = ctx; - const { intl, intlNode, getLocale } = common.utils.createIntl({ - 'en-US': enUS, - 'zh-CN': zhCN, - }); - ctx.intl = intl; - ctx.intlNode = intlNode; - ctx.getLocale = getLocale; - ctx.extraTitle = options && options['extraTitle']; + const { skeleton, config, canvas, project } = ctx; let isInFloatArea = true; const hasPreferenceForOutline = config.getPreference().contains('outline-pane-pinned-status-isFloat', 'skeleton'); @@ -26,8 +18,7 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { masterPane: false, backupPane: false, }; - const treeMaster = new TreeMaster(ctx); - let masterPaneController: PaneController | null = null; + const treeMaster = new TreeMaster(ctx, options); let backupPaneController: PaneController | null = null; return { async init() { @@ -40,16 +31,20 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { name: MasterPaneName, props: { icon: IconOutline, - description: intlNode('Outline Tree'), + description: treeMaster.pluginContext.intlNode('Outline Tree'), }, - content: (props: any) => { - masterPaneController = new PaneController(MasterPaneName, ctx, treeMaster); + content: function Context(props: any) { + const [masterPaneController, setMasterPaneController] = useState(new PaneController(MasterPaneName, treeMaster)); + treeMaster.onPluginContextChange(() => { + setMasterPaneController(new PaneController(MasterPaneName, treeMaster)); + }); + return ( <Pane config={config} - pluginContext={ctx} treeMaster={treeMaster} controller={masterPaneController} + key={masterPaneController.id} {...props} /> ); @@ -73,10 +68,9 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { hiddenWhenInit: true, }, content: (props: any) => { - backupPaneController = new PaneController(BackupPaneName, ctx, treeMaster); + backupPaneController = new PaneController(BackupPaneName, treeMaster); return ( <Pane - pluginContext={ctx} treeMaster={treeMaster} controller={backupPaneController} {...props} diff --git a/packages/plugin-outline-pane/src/views/filter.tsx b/packages/plugin-outline-pane/src/views/filter.tsx index 166a5c8e2f..908f83d567 100644 --- a/packages/plugin-outline-pane/src/views/filter.tsx +++ b/packages/plugin-outline-pane/src/views/filter.tsx @@ -5,11 +5,9 @@ import { Search, Checkbox, Balloon, Divider } from '@alifd/next'; import TreeNode from '../controllers/tree-node'; import { Tree } from '../controllers/tree'; import { matchTreeNode, FILTER_OPTIONS } from './filter-tree'; -import { IPublicModelPluginContext } from '@alilc/lowcode-types'; export default class Filter extends PureComponent<{ tree: Tree; - pluginContext: IPublicModelPluginContext; }, { keywords: string; filterOps: string[]; @@ -53,14 +51,16 @@ export default class Filter extends PureComponent<{ return ( <div className="lc-outline-filter"> + {/* @ts-ignore */} <Search hasClear shape="simple" - placeholder={this.props.pluginContext.intl('Filter Node')} + placeholder={this.props.tree.pluginContext.intl('Filter Node')} className="lc-outline-filter-search-input" value={keywords} onChange={this.handleSearchChange} /> + {/* @ts-ignore */} <Balloon v2 align="br" @@ -72,14 +72,17 @@ export default class Filter extends PureComponent<{ </div> )} > + {/* @ts-ignore */} <Checkbox checked={checkAll} indeterminate={indeterminate} onChange={this.handleCheckAll} > - {this.props.pluginContext.intlNode('Check All')} + {this.props.tree.pluginContext.intlNode('Check All')} </Checkbox> + {/* @ts-ignore */} <Divider /> + {/* @ts-ignore */} <Checkbox.Group value={filterOps} direction="ver" @@ -91,7 +94,7 @@ export default class Filter extends PureComponent<{ value={op.value} key={op.value} > - {this.props.pluginContext.intlNode(op.label)} + {this.props.tree.pluginContext.intlNode(op.label)} </Checkbox> ))} </Checkbox.Group> diff --git a/packages/plugin-outline-pane/src/views/pane.tsx b/packages/plugin-outline-pane/src/views/pane.tsx index adaada7862..8805cfffa0 100644 --- a/packages/plugin-outline-pane/src/views/pane.tsx +++ b/packages/plugin-outline-pane/src/views/pane.tsx @@ -1,47 +1,71 @@ import React, { PureComponent } from 'react'; +import { Loading } from '@alifd/next'; import { PaneController } from '../controllers/pane-controller'; import TreeView from './tree'; import './style.less'; -import { IPublicModelPluginContext } from '@alilc/lowcode-types'; import Filter from './filter'; import { TreeMaster } from '../controllers/tree-master'; +import { Tree } from '../controllers/tree'; +import { IPublicTypeDisposable } from '@alilc/lowcode-types'; export class Pane extends PureComponent<{ config: any; - pluginContext: IPublicModelPluginContext; treeMaster: TreeMaster; controller: PaneController; +}, { + tree: Tree | null; }> { private controller; - private treeMaster: TreeMaster; + + private dispose: IPublicTypeDisposable; constructor(props: any) { super(props); const { controller, treeMaster } = props; - this.treeMaster = treeMaster; this.controller = controller; + this.state = { + tree: treeMaster.currentTree, + }; } componentWillUnmount() { this.controller.purge(); + this.dispose && this.dispose(); + } + + componentDidMount() { + this.dispose = this.props.treeMaster.pluginContext.project.onSimulatorRendererReady(() => { + this.setState({ + tree: this.props.treeMaster.currentTree, + }); + }); } render() { - const tree = this.treeMaster.currentTree; + const tree = this.state.tree; if (!tree) { return ( <div className="lc-outline-pane"> - <p className="lc-outline-notice">{this.props.pluginContext.intl('Initializing')}</p> + <p className="lc-outline-notice"> + {/* @ts-ignore */} + <Loading + style={{ + display: 'block', + marginTop: '40px', + }} + tip={this.props.treeMaster.pluginContext.intl('Initializing')} + /> + </p> </div> ); } return ( <div className="lc-outline-pane"> - <Filter tree={tree} pluginContext={this.props.pluginContext} /> + <Filter tree={tree} /> <div ref={(shell) => this.controller.mount(shell)} className="lc-outline-tree-container"> - <TreeView key={tree.id} tree={tree} pluginContext={this.props.pluginContext} /> + <TreeView key={tree.id} tree={tree} /> </div> </div> ); diff --git a/packages/plugin-outline-pane/src/views/tree-branches.tsx b/packages/plugin-outline-pane/src/views/tree-branches.tsx index 210fe0af85..2e281071bb 100644 --- a/packages/plugin-outline-pane/src/views/tree-branches.tsx +++ b/packages/plugin-outline-pane/src/views/tree-branches.tsx @@ -2,12 +2,11 @@ import { PureComponent } from 'react'; import classNames from 'classnames'; import TreeNode from '../controllers/tree-node'; import TreeNodeView from './tree-node'; -import { IPublicModelPluginContext, IPublicModelExclusiveGroup, IPublicTypeDisposable, IPublicTypeLocationChildrenDetail } from '@alilc/lowcode-types'; +import { IPublicModelExclusiveGroup, IPublicTypeDisposable, IPublicTypeLocationChildrenDetail } from '@alilc/lowcode-types'; export default class TreeBranches extends PureComponent<{ treeNode: TreeNode; isModal?: boolean; - pluginContext: IPublicModelPluginContext; expanded: boolean; treeChildren: TreeNode[] | null; }> { @@ -51,12 +50,11 @@ export default class TreeBranches extends PureComponent<{ return ( <div className="tree-node-branches"> { - !isModal && <TreeNodeSlots treeNode={treeNode} pluginContext={this.props.pluginContext} /> + !isModal && <TreeNodeSlots treeNode={treeNode} /> } <TreeNodeChildren treeNode={treeNode} isModal={isModal || false} - pluginContext={this.props.pluginContext} treeChildren={this.props.treeChildren} /> </div> @@ -73,7 +71,6 @@ interface ITreeNodeChildrenState { class TreeNodeChildren extends PureComponent<{ treeNode: TreeNode; isModal?: boolean; - pluginContext: IPublicModelPluginContext; treeChildren: TreeNode[] | null; }, ITreeNodeChildrenState> { state: ITreeNodeChildrenState = { @@ -84,8 +81,8 @@ class TreeNodeChildren extends PureComponent<{ }; offLocationChanged: IPublicTypeDisposable | undefined; componentDidMount() { - const { treeNode, pluginContext } = this.props; - const { project } = pluginContext; + const { treeNode } = this.props; + const { project } = treeNode.pluginContext; const { filterWorking, matchSelf, keywords } = treeNode.filterReult; const { dropDetail } = treeNode; this.setState({ @@ -122,13 +119,14 @@ class TreeNodeChildren extends PureComponent<{ let groupContents: any[] = []; let currentGrp: IPublicModelExclusiveGroup; const { filterWorking, matchSelf, keywords } = this.state; - const Title = this.props.pluginContext.common.editorCabin.Title; + const Title = this.props.treeNode.pluginContext.common.editorCabin.Title; const endGroup = () => { if (groupContents.length > 0) { children.push( <div key={currentGrp.id} className="condition-group-container" data-id={currentGrp.firstNode?.id}> <div className="condition-group-title"> + {/* @ts-ignore */} <Title title={currentGrp.title} match={filterWorking && matchSelf} @@ -171,12 +169,12 @@ class TreeNodeChildren extends PureComponent<{ children.push(insertion); } } - groupContents.push(<TreeNodeView key={child.id} treeNode={child} isModal={isModal} pluginContext={this.props.pluginContext} />); + groupContents.push(<TreeNodeView key={child.id} treeNode={child} isModal={isModal} />); } else { if (index === dropIndex) { children.push(insertion); } - children.push(<TreeNodeView key={child.id} treeNode={child} isModal={isModal} pluginContext={this.props.pluginContext} />); + children.push(<TreeNodeView key={child.id} treeNode={child} isModal={isModal} />); } }); endGroup(); @@ -191,14 +189,13 @@ class TreeNodeChildren extends PureComponent<{ class TreeNodeSlots extends PureComponent<{ treeNode: TreeNode; - pluginContext: IPublicModelPluginContext; }> { render() { const { treeNode } = this.props; if (!treeNode.hasSlots()) { return null; } - const Title = this.props.pluginContext.common.editorCabin.Title; + const Title = this.props.treeNode.pluginContext.common.editorCabin.Title; return ( <div className={classNames('tree-node-slots', { @@ -207,10 +204,11 @@ class TreeNodeSlots extends PureComponent<{ data-id={treeNode.id} > <div className="tree-node-slots-title"> - <Title title={{ type: 'i18n', intl: this.props.pluginContext.intlNode('Slots') }} /> + {/* @ts-ignore */} + <Title title={{ type: 'i18n', intl: this.props.treeNode.pluginContext.intlNode('Slots') }} /> </div> {treeNode.slots.map(tnode => ( - <TreeNodeView key={tnode.id} treeNode={tnode} pluginContext={this.props.pluginContext} /> + <TreeNodeView key={tnode.id} treeNode={tnode} /> ))} </div> ); diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx index 331397a0bd..882fe15b1a 100644 --- a/packages/plugin-outline-pane/src/views/tree-node.tsx +++ b/packages/plugin-outline-pane/src/views/tree-node.tsx @@ -4,22 +4,24 @@ import TreeNode from '../controllers/tree-node'; import TreeTitle from './tree-title'; import TreeBranches from './tree-branches'; import { IconEyeClose } from '../icons/eye-close'; -import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicTypeDisposable } from '@alilc/lowcode-types'; +import { IPublicModelModalNodesManager, IPublicTypeDisposable } from '@alilc/lowcode-types'; +import { IOutlinePanelPluginContext } from '../controllers/tree-master'; class ModalTreeNodeView extends PureComponent<{ treeNode: TreeNode; - pluginContext: IPublicModelPluginContext; }, { treeChildren: TreeNode[] | null; }> { private modalNodesManager: IPublicModelModalNodesManager | undefined | null; - readonly pluginContext: IPublicModelPluginContext; + readonly pluginContext: IOutlinePanelPluginContext; - constructor(props: any) { + constructor(props: { + treeNode: TreeNode; + }) { super(props); // 模态管理对象 - this.pluginContext = props.pluginContext; + this.pluginContext = props.treeNode.pluginContext; const { project } = this.pluginContext; this.modalNodesManager = project.currentDocument?.modalNodesManager; this.state = { @@ -72,7 +74,6 @@ class ModalTreeNodeView extends PureComponent<{ treeChildren={this.state.treeChildren} expanded={expanded} isModal - pluginContext={this.pluginContext} /> </div> </div> @@ -83,7 +84,6 @@ class ModalTreeNodeView extends PureComponent<{ export default class TreeNodeView extends PureComponent<{ treeNode: TreeNode; isModal?: boolean; - pluginContext: IPublicModelPluginContext; isRootNode?: boolean; }> { state: { @@ -134,8 +134,8 @@ export default class TreeNodeView extends PureComponent<{ } componentDidMount() { - const { treeNode, pluginContext } = this.props; - const { project } = pluginContext; + const { treeNode } = this.props; + const { project } = treeNode.pluginContext; const doc = project.currentDocument; @@ -178,14 +178,14 @@ export default class TreeNodeView extends PureComponent<{ } shouldShowModalTreeNode(): boolean { - const { treeNode, isRootNode, pluginContext } = this.props; + const { treeNode, isRootNode } = this.props; if (!isRootNode) { // 只在 当前树 的根节点展示模态节点 return false; } // 当指定了新的根节点时,要从原始的根节点去获取模态节点 - const { project } = pluginContext; + const { project } = treeNode.pluginContext; const rootNode = project.currentDocument?.root; const rootTreeNode = treeNode.tree.getTreeNode(rootNode!); const modalNodes = rootTreeNode.children?.filter((item) => { @@ -234,19 +234,16 @@ export default class TreeNodeView extends PureComponent<{ hidden={this.state.hidden} locked={this.state.locked} expandable={this.state.expandable} - pluginContext={this.props.pluginContext} /> {shouldShowModalTreeNode && <ModalTreeNodeView treeNode={treeNode} - pluginContext={this.props.pluginContext} /> } <TreeBranches treeNode={treeNode} isModal={false} expanded={this.state.expanded} - pluginContext={this.props.pluginContext} treeChildren={this.state.treeChildren} /> </div> diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 6e1b14a466..96a3dfa7b2 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -1,7 +1,7 @@ import { KeyboardEvent, FocusEvent, Fragment, PureComponent } from 'react'; import classNames from 'classnames'; import { createIcon } from '@alilc/lowcode-utils'; -import { IPublicModelPluginContext, IPublicApiEvent } from '@alilc/lowcode-types'; +import { IPublicApiEvent } from '@alilc/lowcode-types'; import TreeNode from '../controllers/tree-node'; import { IconLock, IconUnlock, IconArrowRight, IconEyeClose, IconEye, IconCond, IconLoop, IconRadioActive, IconRadio, IconSetting } from '../icons'; @@ -23,7 +23,6 @@ export default class TreeTitle extends PureComponent<{ hidden: boolean; locked: boolean; expandable: boolean; - pluginContext: IPublicModelPluginContext; }> { state: { editing: boolean; @@ -53,7 +52,7 @@ export default class TreeTitle extends PureComponent<{ const { treeNode } = this.props; const value = (e.target as HTMLInputElement).value || ''; treeNode.setTitleLabel(value); - emitOutlineEvent(this.props.pluginContext.event, 'rename', treeNode, { value }); + emitOutlineEvent(this.props.treeNode.pluginContext.event, 'rename', treeNode, { value }); this.cancelEdit(); }; @@ -90,7 +89,8 @@ export default class TreeTitle extends PureComponent<{ } render() { - const { treeNode, isModal, pluginContext } = this.props; + const { treeNode, isModal } = this.props; + const { pluginContext } = treeNode; const { editing } = this.state; const isCNode = !treeNode.isRoot(); const { node } = treeNode; @@ -153,7 +153,7 @@ export default class TreeTitle extends PureComponent<{ <IconRadio className="tree-node-modal-radio" /> </div> )} - {isCNode && <ExpandBtn expandable={this.props.expandable} expanded={this.props.expanded} treeNode={treeNode} pluginContext={this.props.pluginContext} />} + {isCNode && <ExpandBtn expandable={this.props.expandable} expanded={this.props.expanded} treeNode={treeNode} />} <div className="tree-node-icon">{createIcon(treeNode.icon)}</div> <div className="tree-node-title-label"> {editing ? ( @@ -166,6 +166,7 @@ export default class TreeTitle extends PureComponent<{ /> ) : ( <Fragment> + {/* @ts-ignore */} <Title title={this.state.title} match={filterWorking && matchSelf} @@ -175,6 +176,7 @@ export default class TreeTitle extends PureComponent<{ {node.slotFor && ( <a className="tree-node-tag slot"> {/* todo: click redirect to prop */} + {/* @ts-ignore */} <Tip>{intlNode('Slot for {prop}', { prop: node.slotFor.key })}</Tip> </a> )} @@ -182,6 +184,7 @@ export default class TreeTitle extends PureComponent<{ <a className="tree-node-tag loop"> {/* todo: click todo something */} <IconLoop /> + {/* @ts-ignore */} <Tip>{intlNode('Loop')}</Tip> </a> )} @@ -189,15 +192,16 @@ export default class TreeTitle extends PureComponent<{ <a className="tree-node-tag cond"> {/* todo: click todo something */} <IconCond /> + {/* @ts-ignore */} <Tip>{intlNode('Conditional')}</Tip> </a> )} </Fragment> )} </div> - {shouldShowHideBtn && <HideBtn hidden={this.props.hidden} treeNode={treeNode} pluginContext={this.props.pluginContext} />} - {shouldShowLockBtn && <LockBtn locked={this.props.locked} treeNode={treeNode} pluginContext={this.props.pluginContext} />} - {shouldEditBtn && <RenameBtn treeNode={treeNode} pluginContext={this.props.pluginContext} onClick={this.enableEdit} /> } + {shouldShowHideBtn && <HideBtn hidden={this.props.hidden} treeNode={treeNode} />} + {shouldShowLockBtn && <LockBtn locked={this.props.locked} treeNode={treeNode} />} + {shouldEditBtn && <RenameBtn treeNode={treeNode} onClick={this.enableEdit} /> } </div> ); @@ -206,11 +210,10 @@ export default class TreeTitle extends PureComponent<{ class RenameBtn extends PureComponent<{ treeNode: TreeNode; - pluginContext: IPublicModelPluginContext; onClick: (e: any) => void; }> { render() { - const { intl, common } = this.props.pluginContext; + const { intl, common } = this.props.treeNode.pluginContext; const Tip = common.editorCabin.Tip; return ( <div @@ -218,6 +221,7 @@ class RenameBtn extends PureComponent<{ onClick={this.props.onClick} > <IconSetting /> + {/* @ts-ignore */} <Tip>{intl('Rename')}</Tip> </div> ); @@ -226,12 +230,11 @@ class RenameBtn extends PureComponent<{ class LockBtn extends PureComponent<{ treeNode: TreeNode; - pluginContext: IPublicModelPluginContext; locked: boolean; }> { render() { const { treeNode, locked } = this.props; - const { intl, common } = this.props.pluginContext; + const { intl, common } = this.props.treeNode.pluginContext; const Tip = common.editorCabin.Tip; return ( <div @@ -242,6 +245,7 @@ class LockBtn extends PureComponent<{ }} > {locked ? <IconUnlock /> : <IconLock /> } + {/* @ts-ignore */} <Tip>{locked ? intl('Unlock') : intl('Lock')}</Tip> </div> ); @@ -251,24 +255,24 @@ class LockBtn extends PureComponent<{ class HideBtn extends PureComponent<{ treeNode: TreeNode; hidden: boolean; - pluginContext: IPublicModelPluginContext; }, { hidden: boolean; }> { render() { const { treeNode, hidden } = this.props; - const { intl, common } = this.props.pluginContext; + const { intl, common } = treeNode.pluginContext; const Tip = common.editorCabin.Tip; return ( <div className="tree-node-hide-btn" onClick={(e) => { e.stopPropagation(); - emitOutlineEvent(this.props.pluginContext.event, hidden ? 'show' : 'hide', treeNode); + emitOutlineEvent(treeNode.pluginContext.event, hidden ? 'show' : 'hide', treeNode); treeNode.setHidden(!hidden); }} > {hidden ? <IconEye /> : <IconEyeClose />} + {/* @ts-ignore */} <Tip>{hidden ? intl('Show') : intl('Hide')}</Tip> </div> ); @@ -277,7 +281,6 @@ class HideBtn extends PureComponent<{ class ExpandBtn extends PureComponent<{ treeNode: TreeNode; - pluginContext: IPublicModelPluginContext; expanded: boolean; expandable: boolean; }> { @@ -294,7 +297,7 @@ class ExpandBtn extends PureComponent<{ if (expanded) { e.stopPropagation(); } - emitOutlineEvent(this.props.pluginContext.event, expanded ? 'collapse' : 'expand', treeNode); + emitOutlineEvent(treeNode.pluginContext.event, expanded ? 'collapse' : 'expand', treeNode); treeNode.setExpanded(!expanded); }} > diff --git a/packages/plugin-outline-pane/src/views/tree.tsx b/packages/plugin-outline-pane/src/views/tree.tsx index 930c65cce9..4bc5028861 100644 --- a/packages/plugin-outline-pane/src/views/tree.tsx +++ b/packages/plugin-outline-pane/src/views/tree.tsx @@ -2,7 +2,7 @@ import { MouseEvent as ReactMouseEvent, PureComponent } from 'react'; import { isFormEvent, canClickNode, isShaken } from '@alilc/lowcode-utils'; import { Tree } from '../controllers/tree'; import TreeNodeView from './tree-node'; -import { IPublicEnumDragObjectType, IPublicModelPluginContext, IPublicModelNode } from '@alilc/lowcode-types'; +import { IPublicEnumDragObjectType, IPublicModelNode } from '@alilc/lowcode-types'; import TreeNode from '../controllers/tree-node'; function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string { @@ -20,12 +20,21 @@ function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string export default class TreeView extends PureComponent<{ tree: Tree; - pluginContext: IPublicModelPluginContext; }> { private shell: HTMLDivElement | null = null; + private ignoreUpSelected = false; + + private boostEvent?: MouseEvent; + + state: { + root: TreeNode | null; + } = { + root: null, + }; + private hover(e: ReactMouseEvent) { - const { project } = this.props.pluginContext; + const { project } = this.props.tree.pluginContext; const detecting = project.currentDocument?.detecting; if (detecting?.enable) { return; @@ -54,7 +63,7 @@ export default class TreeView extends PureComponent<{ return; } - const { project, event, canvas } = this.props.pluginContext; + const { project, event, canvas } = this.props.tree.pluginContext; const doc = project.currentDocument; const selection = doc?.selection; const focusNode = doc?.focusNode; @@ -109,10 +118,6 @@ export default class TreeView extends PureComponent<{ return tree.getTreeNodeById(id); } - private ignoreUpSelected = false; - - private boostEvent?: MouseEvent; - private onMouseDown = (e: ReactMouseEvent) => { if (isFormEvent(e.nativeEvent)) { return; @@ -127,7 +132,7 @@ export default class TreeView extends PureComponent<{ if (!canClickNode(node, e)) { return; } - const { project, canvas } = this.props.pluginContext; + const { project, canvas } = this.props.tree.pluginContext; const selection = project.currentDocument?.selection; const focusNode = project.currentDocument?.focusNode; @@ -166,22 +171,16 @@ export default class TreeView extends PureComponent<{ }; private onMouseLeave = () => { - const { pluginContext } = this.props; + const { pluginContext } = this.props.tree; const { project } = pluginContext; const doc = project.currentDocument; doc?.detecting.leave(); }; - state: { - root: TreeNode | null - } = { - root: null, - }; - componentDidMount() { - const { tree, pluginContext } = this.props; + const { tree } = this.props; const { root } = tree; - const { project } = pluginContext; + const { project } = tree.pluginContext; this.setState({ root }); const doc = project.currentDocument; doc?.onFocusNodeChanged(() => { @@ -208,7 +207,6 @@ export default class TreeView extends PureComponent<{ <TreeNodeView key={this.state.root?.id} treeNode={this.state.root} - pluginContext={this.props.pluginContext} isRootNode /> </div> diff --git a/packages/shell/src/model/editor-view.ts b/packages/shell/src/model/editor-view.ts new file mode 100644 index 0000000000..31027a5dee --- /dev/null +++ b/packages/shell/src/model/editor-view.ts @@ -0,0 +1,27 @@ +import { editorViewSymbol, pluginContextSymbol } from '../symbols'; +import { IPublicModelPluginContext } from '@alilc/lowcode-types'; +import { IViewContext } from '@alilc/lowcode-workspace'; + +export class EditorView { + [editorViewSymbol]: IViewContext; + + [pluginContextSymbol]: IPublicModelPluginContext; + + constructor(editorView: IViewContext) { + this[editorViewSymbol] = editorView; + this[pluginContextSymbol] = this[editorViewSymbol].innerPlugins._getLowCodePluginContext({ + pluginName: '', + }); + } + + toProxy() { + return new Proxy(this, { + get(target, prop, receiver) { + if ((target[pluginContextSymbol] as any)[prop as string]) { + return Reflect.get(target[pluginContextSymbol], prop, receiver); + } + return Reflect.get(target, prop, receiver); + }, + }); + } +} diff --git a/packages/shell/src/model/index.ts b/packages/shell/src/model/index.ts index cd481643e5..8b668c947f 100644 --- a/packages/shell/src/model/index.ts +++ b/packages/shell/src/model/index.ts @@ -19,3 +19,4 @@ export * from './active-tracker'; export * from './plugin-instance'; export * from './window'; export * from './clipboard'; +export * from './editor-view'; diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index 23bc5c06db..6af2534dd3 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -2,6 +2,7 @@ import { windowSymbol } from '../symbols'; import { IPublicModelResource, IPublicModelWindow, IPublicTypeDisposable } from '@alilc/lowcode-types'; import { IEditorWindow } from '@alilc/lowcode-workspace'; import { Resource as ShellResource } from './resource'; +import { EditorView } from './editor-view'; export class Window implements IPublicModelWindow { private readonly [windowSymbol]: IEditorWindow; @@ -42,7 +43,11 @@ export class Window implements IPublicModelWindow { return await this[windowSymbol].save(); } - get plugins() { - return this[windowSymbol].plugins; + get currentEditorView() { + return new EditorView(this[windowSymbol].editorView).toProxy() as any; + } + + get editorViews() { + return Array.from(this[windowSymbol].editorViews.values()).map(d => new EditorView(d).toProxy() as any); } } diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index 4ba6ff2369..48d6a96567 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -34,3 +34,5 @@ export const resourceSymbol = Symbol('resource'); export const clipboardSymbol = Symbol('clipboard'); export const configSymbol = Symbol('configSymbol'); export const conditionGroupSymbol = Symbol('conditionGroup'); +export const editorViewSymbol = Symbol('editorView'); +export const pluginContextSymbol = Symbol('pluginContext'); \ No newline at end of file diff --git a/packages/types/src/shell/enum/index.ts b/packages/types/src/shell/enum/index.ts index 5060558251..f3d5580119 100644 --- a/packages/types/src/shell/enum/index.ts +++ b/packages/types/src/shell/enum/index.ts @@ -2,4 +2,5 @@ export * from './event-names'; export * from './transition-type'; export * from './transform-stage'; export * from './drag-object-type'; -export * from './prop-value-changed-type'; \ No newline at end of file +export * from './prop-value-changed-type'; +export * from './plugin-register-level'; \ No newline at end of file diff --git a/packages/types/src/shell/enum/plugin-register-level.ts b/packages/types/src/shell/enum/plugin-register-level.ts new file mode 100644 index 0000000000..a0d9b746bb --- /dev/null +++ b/packages/types/src/shell/enum/plugin-register-level.ts @@ -0,0 +1,6 @@ +export enum IPublicEnumPluginRegisterLevel { + Default = 'default', + Workspace = 'workspace', + Resource = 'resource', + EditorView = 'editorView', +} \ No newline at end of file diff --git a/packages/types/src/shell/model/dragon.ts b/packages/types/src/shell/model/dragon.ts index 662eb6a007..917149faf3 100644 --- a/packages/types/src/shell/model/dragon.ts +++ b/packages/types/src/shell/model/dragon.ts @@ -1,5 +1,5 @@ /* eslint-disable max-len */ -import { IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type'; +import { IPublicTypeDisposable, IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type'; import { IPublicModelDragObject, IPublicModelLocateEvent, IPublicModelNode } from './'; export interface IPublicModelDragon< @@ -19,7 +19,7 @@ export interface IPublicModelDragon< * @param func * @returns */ - onDragstart(func: (e: LocateEvent) => any): () => void; + onDragstart(func: (e: LocateEvent) => any): IPublicTypeDisposable; /** * 绑定 drag 事件 @@ -27,7 +27,7 @@ export interface IPublicModelDragon< * @param func * @returns */ - onDrag(func: (e: LocateEvent) => any): () => void; + onDrag(func: (e: LocateEvent) => any): IPublicTypeDisposable; /** * 绑定 dragend 事件 @@ -35,7 +35,7 @@ export interface IPublicModelDragon< * @param func * @returns */ - onDragend(func: (o: { dragObject: IPublicModelDragObject; copy?: boolean }) => any): () => void; + onDragend(func: (o: { dragObject: IPublicModelDragObject; copy?: boolean }) => any): IPublicTypeDisposable; /** * 设置拖拽监听的区域 shell,以及自定义拖拽转换函数 boost diff --git a/packages/types/src/shell/model/editor-view.ts b/packages/types/src/shell/model/editor-view.ts new file mode 100644 index 0000000000..793417845b --- /dev/null +++ b/packages/types/src/shell/model/editor-view.ts @@ -0,0 +1,3 @@ +import { IPublicModelPluginContext } from './plugin-context'; + +export interface IPublicModelEditorView extends IPublicModelPluginContext {} \ No newline at end of file diff --git a/packages/types/src/shell/model/index.ts b/packages/types/src/shell/model/index.ts index b62fb76b95..e310128ca0 100644 --- a/packages/types/src/shell/model/index.ts +++ b/packages/types/src/shell/model/index.ts @@ -30,3 +30,4 @@ export * from './sensor'; export * from './resource'; export * from './clipboard'; export * from './setting-field'; +export * from './editor-view'; diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts index 5d97b54726..e670e54ea3 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -12,18 +12,11 @@ import { IPublicApiPlugins, IPublicApiWorkspace, } from '../api'; +import { IPublicEnumPluginRegisterLevel } from '../enum'; import { IPublicModelEngineConfig } from './'; export interface IPublicModelPluginContext { - /** - * 对于插件开发者来说,可以在 context 挂载自定义的内容,作为插件内全局上下文使用 - * - * for plugin developers, costom properties can be add to plugin context - * from inside plugin for convenience. - */ - [key: string]: any; - /** * 可通过该对象读取插件初始化配置 * by using this, init options can be accessed from inside plugin @@ -108,6 +101,12 @@ export interface IPublicModelPluginContext { * @tutorial https://lowcode-engine.cn/site/docs/api/workspace */ get workspace(): IPublicApiWorkspace; + + /** + * 插件注册层级 + * @since v1.1.7 + */ + get registerLevel(): IPublicEnumPluginRegisterLevel; } /** diff --git a/packages/types/src/shell/model/window.ts b/packages/types/src/shell/model/window.ts index bb27ce317c..5f77b0cbf8 100644 --- a/packages/types/src/shell/model/window.ts +++ b/packages/types/src/shell/model/window.ts @@ -1,6 +1,7 @@ import { ReactElement } from 'react'; import { IPublicTypeDisposable, IPublicTypeNodeSchema } from '../type'; import { IPublicModelResource } from './resource'; +import { IPublicModelEditorView } from './editor-view'; export interface IPublicModelWindow< Resource = IPublicModelResource @@ -18,6 +19,18 @@ export interface IPublicModelWindow< /** 窗口资源类型 */ resource?: Resource; + /** + * 窗口当前视图 + * @since v1.1.7 + */ + currentEditorView: IPublicModelEditorView; + + /** + * 窗口全部视图实例 + * @since v1.1.7 + */ + editorViews: IPublicModelEditorView[]; + /** 当前窗口导入 schema */ importSchema(schema: IPublicTypeNodeSchema): void; diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index 57a38712b9..b12a78183a 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -44,6 +44,7 @@ import { IPublicApiProject, IPublicApiSetters, IPublicApiSkeleton, + IPublicEnumPluginRegisterLevel, IPublicModelPluginContext, IPublicTypePluginMeta, } from '@alilc/lowcode-types'; @@ -100,7 +101,7 @@ export class BasicContext implements IBasicContext { preference: IPluginPreferenceMananger; workspace: IWorkspace; - constructor(innerWorkspace: IWorkspace, viewName: string, public editorWindow?: IEditorWindow) { + constructor(innerWorkspace: IWorkspace, viewName: string, registerLevel: IPublicEnumPluginRegisterLevel, public editorWindow?: IEditorWindow) { const editor = new Editor(viewName, true); const innerSkeleton = new InnerSkeleton(editor, viewName); @@ -168,6 +169,7 @@ export class BasicContext implements IBasicContext { if (editorWindow) { context.editorWindow = new Window(editorWindow); } + context.registerLevel = registerLevel; }, }; diff --git a/packages/workspace/src/context/view-context.ts b/packages/workspace/src/context/view-context.ts index 3939898506..7dfc663931 100644 --- a/packages/workspace/src/context/view-context.ts +++ b/packages/workspace/src/context/view-context.ts @@ -1,12 +1,16 @@ import { computed, makeObservable, obx } from '@alilc/lowcode-editor-core'; -import { IPublicEditorViewConfig, IPublicTypeEditorView } from '@alilc/lowcode-types'; +import { IPublicEditorViewConfig, IPublicEnumPluginRegisterLevel, IPublicTypeEditorView } from '@alilc/lowcode-types'; import { flow } from 'mobx'; import { IWorkspace } from '../workspace'; -import { BasicContext } from './base-context'; +import { BasicContext, IBasicContext } from './base-context'; import { IEditorWindow } from '../window'; import { getWebviewPlugin } from '../inner-plugins/webview'; -export class Context extends BasicContext { +export interface IViewContext extends IBasicContext { + +} + +export class Context extends BasicContext implements IViewContext { viewName = 'editor-view'; instance: IPublicEditorViewConfig; @@ -30,7 +34,7 @@ export class Context extends BasicContext { }); constructor(public workspace: IWorkspace, public editorWindow: IEditorWindow, public editorView: IPublicTypeEditorView, options: Object | undefined) { - super(workspace, editorView.viewName, editorWindow); + super(workspace, editorView.viewName, IPublicEnumPluginRegisterLevel.EditorView, editorWindow); this.viewType = editorView.viewType || 'editor'; this.viewName = editorView.viewName; this.instance = editorView(this.innerPlugins._getLowCodePluginContext({ diff --git a/packages/workspace/src/index.ts b/packages/workspace/src/index.ts index 1f3b77a7aa..6c437fad0a 100644 --- a/packages/workspace/src/index.ts +++ b/packages/workspace/src/index.ts @@ -4,3 +4,4 @@ export * from './window'; export * from './layouts/workbench'; export { Resource } from './resource'; export type { IResource } from './resource'; +export type { IViewContext } from './context/view-context'; diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index 222cb1162e..e51993c81e 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -1,5 +1,5 @@ import { ISkeleton } from '@alilc/lowcode-editor-skeleton'; -import { IPublicTypeEditorView, IPublicResourceData, IPublicResourceTypeConfig, IBaseModelResource } from '@alilc/lowcode-types'; +import { IPublicTypeEditorView, IPublicResourceData, IPublicResourceTypeConfig, IBaseModelResource, IPublicEnumPluginRegisterLevel } from '@alilc/lowcode-types'; import { Logger } from '@alilc/lowcode-utils'; import { BasicContext, IBasicContext } from './context/base-context'; import { ResourceType, IResourceType } from './resource-type'; @@ -75,7 +75,7 @@ export class Resource implements IResource { } constructor(readonly resourceData: IPublicResourceData, readonly resourceType: IResourceType, readonly workspace: IWorkspace) { - this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`); + this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`, IPublicEnumPluginRegisterLevel.Resource); this.resourceTypeInstance = resourceType.resourceTypeModel(this.context.innerPlugins._getLowCodePluginContext({ pluginName: '', }), this.options); diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index 37a1622c04..92b7078517 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -1,6 +1,6 @@ import { uniqueId } from '@alilc/lowcode-utils'; import { createModuleEventBus, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; -import { Context } from './context/view-context'; +import { Context, IViewContext } from './context/view-context'; import { IWorkspace } from './workspace'; import { IResource } from './resource'; import { IPublicTypeDisposable } from '../../types/es/shell/type/disposable'; @@ -13,10 +13,12 @@ interface IWindowCOnfig { sleep?: boolean; } -export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'changeViewType'> { +export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'changeViewType' | 'currentEditorView' | 'editorViews'> { readonly resource: IResource; - editorViews: Map<string, Context>; + editorViews: Map<string, IViewContext>; + + editorView: IViewContext; changeViewType: (name: string, ignoreEmit?: boolean) => void; @@ -71,6 +73,9 @@ export class EditorWindow implements IEditorWindow { async save() { const value: any = {}; const editorViews = this.resource.editorViews; + if (!editorViews) { + return; + } for (let i = 0; i < editorViews.length; i++) { const name = editorViews[i].viewName; const saveResult = await this.editorViews.get(name)?.save(); diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index ea19ea0c07..37341cdc3f 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -1,6 +1,6 @@ import { IDesigner, ILowCodePluginManager, LowCodePluginManager } from '@alilc/lowcode-designer'; import { createModuleEventBus, Editor, IEditor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; -import { IPublicApiPlugins, IPublicApiWorkspace, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types'; +import { IPublicApiPlugins, IPublicApiWorkspace, IPublicEnumPluginRegisterLevel, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types'; import { BasicContext } from './context/base-context'; import { EditorWindow } from './window'; import type { IEditorWindow } from './window'; @@ -94,7 +94,7 @@ export class Workspace implements IWorkspace { readonly registryInnerPlugin: (designer: IDesigner, editor: IEditor, plugins: IPublicApiPlugins) => Promise<IPublicTypeDisposable>, readonly shellModelFactory: any, ) { - this.context = new BasicContext(this, ''); + this.context = new BasicContext(this, '', IPublicEnumPluginRegisterLevel.Workspace); makeObservable(this); } From ebc137d11871c069b395f80408e6ffc46959a2bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 24 Apr 2023 14:06:17 +0800 Subject: [PATCH 118/469] docs: update common.md --- docs/docs/api/common.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/docs/api/common.md b/docs/docs/api/common.md index e5bfa8629d..966e2277f2 100644 --- a/docs/docs/api/common.md +++ b/docs/docs/api/common.md @@ -95,6 +95,17 @@ common.utils.startTransaction(() => { }, IPublicEnumTransitionType.repaint); ``` +#### getConvertedExtraKey + +props key 转化工具 + +```typescript +getConvertedExtraKey(key: string): string + +``` + +**@since v1.0.17** + #### createIntl i18n 相关工具 ```typescript @@ -144,4 +155,4 @@ const { intl, getLocale, setLocale } = common.utils.createIntl({ * get Workbench Component */ get Workbench(): Component; -``` \ No newline at end of file +``` From 5b1423068e5630975cba21460a58b46702810dee Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 26 Apr 2023 10:20:52 +0800 Subject: [PATCH 119/469] feat(outline-pane): export OutlinePaneContext --- .../src/controllers/tree-master.ts | 3 +- packages/plugin-outline-pane/src/index.tsx | 61 +++++++++++-------- .../plugin-outline-pane/src/views/filter.tsx | 5 -- .../plugin-outline-pane/src/views/pane.tsx | 20 +++--- .../plugin-outline-pane/src/views/style.less | 7 ++- .../renderer-core/tests/hoc/leaf.test.tsx | 7 --- .../tests/renderer/base.test.tsx | 1 - .../tests/renderer/renderer.test.tsx | 2 - 8 files changed, 50 insertions(+), 56 deletions(-) diff --git a/packages/plugin-outline-pane/src/controllers/tree-master.ts b/packages/plugin-outline-pane/src/controllers/tree-master.ts index a6852803b3..cb62980482 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-master.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-master.ts @@ -40,6 +40,7 @@ export class TreeMaster { const { workspace } = this.pluginContext; this.initEvent(); if (pluginContext.registerLevel === IPublicEnumPluginRegisterLevel.Workspace) { + this.setPluginContext(workspace.window?.currentEditorView); workspace.onWindowRendererReady(() => { this.setPluginContext(workspace.window?.currentEditorView); let dispose: IPublicTypeDisposable | undefined; @@ -60,7 +61,7 @@ export class TreeMaster { } } - private setPluginContext(pluginContext: IPublicModelPluginContext | undefined) { + private setPluginContext(pluginContext: IPublicModelPluginContext | undefined | null) { if (!pluginContext) { return; } diff --git a/packages/plugin-outline-pane/src/index.tsx b/packages/plugin-outline-pane/src/index.tsx index 1ea53b2f06..95b219a4b1 100644 --- a/packages/plugin-outline-pane/src/index.tsx +++ b/packages/plugin-outline-pane/src/index.tsx @@ -6,6 +6,34 @@ import { TreeMaster } from './controllers/tree-master'; import { PaneController } from './controllers/pane-controller'; import { useState } from 'react'; +export function OutlinePaneContext(props: { + treeMaster?: TreeMaster; + + pluginContext: IPublicModelPluginContext; + + options: any; + + paneName: string; + + hideFilter?: boolean; +}) { + const treeMaster = props.treeMaster || new TreeMaster(props.pluginContext, props.options); + const [masterPaneController, setMasterPaneController] = useState(new PaneController(props.paneName || MasterPaneName, treeMaster)); + treeMaster.onPluginContextChange(() => { + setMasterPaneController(new PaneController(props.paneName || MasterPaneName, treeMaster)); + }); + + return ( + <Pane + treeMaster={treeMaster} + controller={masterPaneController} + key={masterPaneController.id} + hideFilter={props.hideFilter} + {...props} + /> + ); +} + export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { const { skeleton, config, canvas, project } = ctx; @@ -19,7 +47,6 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { backupPane: false, }; const treeMaster = new TreeMaster(ctx, options); - let backupPaneController: PaneController | null = null; return { async init() { skeleton.add({ @@ -33,22 +60,7 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { icon: IconOutline, description: treeMaster.pluginContext.intlNode('Outline Tree'), }, - content: function Context(props: any) { - const [masterPaneController, setMasterPaneController] = useState(new PaneController(MasterPaneName, treeMaster)); - treeMaster.onPluginContextChange(() => { - setMasterPaneController(new PaneController(MasterPaneName, treeMaster)); - }); - - return ( - <Pane - config={config} - treeMaster={treeMaster} - controller={masterPaneController} - key={masterPaneController.id} - {...props} - /> - ); - }, + content: OutlinePaneContext, }, panelProps: { area: isInFloatArea ? 'leftFloatArea' : 'leftFixedArea', @@ -57,6 +69,8 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { }, contentProps: { treeTitleExtra: config.get('treeTitleExtra'), + treeMaster, + paneName: MasterPaneName, }, }); @@ -67,15 +81,10 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { props: { hiddenWhenInit: true, }, - content: (props: any) => { - backupPaneController = new PaneController(BackupPaneName, treeMaster); - return ( - <Pane - treeMaster={treeMaster} - controller={backupPaneController} - {...props} - /> - ); + content: OutlinePaneContext, + contentProps: { + paneName: BackupPaneName, + treeMaster, }, }); diff --git a/packages/plugin-outline-pane/src/views/filter.tsx b/packages/plugin-outline-pane/src/views/filter.tsx index 908f83d567..8fd18ed251 100644 --- a/packages/plugin-outline-pane/src/views/filter.tsx +++ b/packages/plugin-outline-pane/src/views/filter.tsx @@ -51,7 +51,6 @@ export default class Filter extends PureComponent<{ return ( <div className="lc-outline-filter"> - {/* @ts-ignore */} <Search hasClear shape="simple" @@ -60,7 +59,6 @@ export default class Filter extends PureComponent<{ value={keywords} onChange={this.handleSearchChange} /> - {/* @ts-ignore */} <Balloon v2 align="br" @@ -72,7 +70,6 @@ export default class Filter extends PureComponent<{ </div> )} > - {/* @ts-ignore */} <Checkbox checked={checkAll} indeterminate={indeterminate} @@ -80,9 +77,7 @@ export default class Filter extends PureComponent<{ > {this.props.tree.pluginContext.intlNode('Check All')} </Checkbox> - {/* @ts-ignore */} <Divider /> - {/* @ts-ignore */} <Checkbox.Group value={filterOps} direction="ver" diff --git a/packages/plugin-outline-pane/src/views/pane.tsx b/packages/plugin-outline-pane/src/views/pane.tsx index 8805cfffa0..36a2bfa0b7 100644 --- a/packages/plugin-outline-pane/src/views/pane.tsx +++ b/packages/plugin-outline-pane/src/views/pane.tsx @@ -9,9 +9,9 @@ import { Tree } from '../controllers/tree'; import { IPublicTypeDisposable } from '@alilc/lowcode-types'; export class Pane extends PureComponent<{ - config: any; treeMaster: TreeMaster; controller: PaneController; + hideFilter?: boolean; }, { tree: Tree | null; }> { @@ -26,6 +26,11 @@ export class Pane extends PureComponent<{ this.state = { tree: treeMaster.currentTree, }; + this.dispose = this.props.treeMaster.pluginContext?.project?.onSimulatorRendererReady(() => { + this.setState({ + tree: this.props.treeMaster.currentTree, + }); + }); } componentWillUnmount() { @@ -33,14 +38,6 @@ export class Pane extends PureComponent<{ this.dispose && this.dispose(); } - componentDidMount() { - this.dispose = this.props.treeMaster.pluginContext.project.onSimulatorRendererReady(() => { - this.setState({ - tree: this.props.treeMaster.currentTree, - }); - }); - } - render() { const tree = this.state.tree; @@ -48,7 +45,6 @@ export class Pane extends PureComponent<{ return ( <div className="lc-outline-pane"> <p className="lc-outline-notice"> - {/* @ts-ignore */} <Loading style={{ display: 'block', @@ -63,8 +59,8 @@ export class Pane extends PureComponent<{ return ( <div className="lc-outline-pane"> - <Filter tree={tree} /> - <div ref={(shell) => this.controller.mount(shell)} className="lc-outline-tree-container"> + { !this.props.hideFilter && <Filter tree={tree} /> } + <div ref={(shell) => this.controller.mount(shell)} className={`lc-outline-tree-container ${ this.props.hideFilter ? 'lc-hidden-outline-filter' : '' }`}> <TreeView key={tree.id} tree={tree} /> </div> </div> diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index cd133932b9..f343fba170 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -14,10 +14,14 @@ overflow: auto; } + > .lc-outline-tree-container.lc-hidden-outline-filter { + top: 0; + } + > .lc-outline-filter { padding: 12px 16px; display: flex; - align-items: center; + align-items: stretch; justify-content: right; .lc-outline-filter-search-input { @@ -27,7 +31,6 @@ .lc-outline-filter-icon { background: #ebecf0; border: 1px solid #c4c6cf; - height: 28px; display: flex; align-items: center; border-radius: 0 2px 2px 0; diff --git a/packages/renderer-core/tests/hoc/leaf.test.tsx b/packages/renderer-core/tests/hoc/leaf.test.tsx index 94d50f87a9..d4a65e578a 100644 --- a/packages/renderer-core/tests/hoc/leaf.test.tsx +++ b/packages/renderer-core/tests/hoc/leaf.test.tsx @@ -83,7 +83,6 @@ beforeEach(() => { }); component = renderer.create( - // @ts-ignore <Div _leaf={DivNode}> <Text _leaf={TextNode} content="content"></Text> </Div> @@ -238,7 +237,6 @@ describe('mini unit render', () => { nodeMap.set(textSchema.id, TextNode); component = renderer.create( - // @ts-ignore <MiniRenderDiv _leaf={MiniRenderDivNode}> <Text _leaf={TextNode} content="content"></Text> </MiniRenderDiv> @@ -285,7 +283,6 @@ describe('mini unit render', () => { nodeMap.set(textSchema.id, TextNode); renderer.create( - // @ts-ignore <div> <Text _leaf={TextNode} content="content"></Text> </div> @@ -309,7 +306,6 @@ describe('mini unit render', () => { }); renderer.create( - // @ts-ignore <div> <Text _leaf={TextNode} content="content"></Text> </div> @@ -388,7 +384,6 @@ describe('mini unit render', () => { }; const component = renderer.create( - // @ts-ignore <MiniRenderDiv _leaf={MiniRenderDivNode}> <Text _leaf={TextNode} content="content"></Text> </MiniRenderDiv> @@ -428,7 +423,6 @@ describe('mini unit render', () => { nodeMap.set(miniRenderSchema.id, MiniRenderDivNode); component = renderer.create( - // @ts-ignore <MiniRenderDiv _leaf={MiniRenderDivNode}> <Text _leaf={TextNode} content="content"></Text> </MiniRenderDiv> @@ -491,7 +485,6 @@ describe('onVisibleChange', () => { describe('children', () => { it('this.props.children is array', () => { const component = renderer.create( - // @ts-ignore <Div _leaf={DivNode}> <Text _leaf={TextNode} content="content"></Text> <Text _leaf={TextNode} content="content"></Text> diff --git a/packages/renderer-core/tests/renderer/base.test.tsx b/packages/renderer-core/tests/renderer/base.test.tsx index 63c5cfbb2e..3faa2bcf44 100644 --- a/packages/renderer-core/tests/renderer/base.test.tsx +++ b/packages/renderer-core/tests/renderer/base.test.tsx @@ -79,7 +79,6 @@ describe('Base Render methods', () => { // const originalUtils = jest.requireActual('../../src/utils'); // mockParseExpression.mockImplementation(originalUtils.parseExpression); const component = TestRenderer.create( - // @ts-ignore <RendererClass __schema={mockSchema} components={components as any} diff --git a/packages/renderer-core/tests/renderer/renderer.test.tsx b/packages/renderer-core/tests/renderer/renderer.test.tsx index 36ee4167e8..081cede8ab 100644 --- a/packages/renderer-core/tests/renderer/renderer.test.tsx +++ b/packages/renderer-core/tests/renderer/renderer.test.tsx @@ -13,7 +13,6 @@ function getComp(schema, comp = null, others = {}): Promise<{ }> { return new Promise((resolve, reject) => { const component = renderer.create( - // @ts-ignore <Renderer schema={schema} components={components as any} @@ -48,7 +47,6 @@ afterEach(() => { describe('Base Render', () => { it('renderComp', () => { const content = ( - // @ts-ignore <Renderer schema={schema as any} components={components as any} From c3d75b27da5c9f1b800d2aee4befc30477b16a29 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 26 Apr 2023 10:24:17 +0800 Subject: [PATCH 120/469] feat(workspace): add config for resource shell model --- packages/designer/src/plugin/plugin-context.ts | 4 ++++ packages/shell/src/model/resource.ts | 4 ++++ packages/shell/src/model/window.ts | 5 ++++- packages/types/src/shell/model/resource.ts | 4 ++++ packages/types/src/shell/model/window.ts | 2 +- packages/types/src/shell/type/resource-list.ts | 4 ++++ packages/workspace/src/context/base-context.ts | 2 +- packages/workspace/src/resource.ts | 4 ++++ 8 files changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/designer/src/plugin/plugin-context.ts b/packages/designer/src/plugin/plugin-context.ts index f43134c75d..94e296fd1c 100644 --- a/packages/designer/src/plugin/plugin-context.ts +++ b/packages/designer/src/plugin/plugin-context.ts @@ -17,6 +17,8 @@ import { IPublicTypePluginDeclaration, IPublicApiCanvas, IPublicApiWorkspace, + IPublicEnumPluginRegisterLevel, + IPublicModelWindow, } from '@alilc/lowcode-types'; import { IPluginContextOptions, @@ -41,6 +43,8 @@ export default class PluginContext implements pluginEvent: IPublicApiEvent; canvas: IPublicApiCanvas; workspace: IPublicApiWorkspace; + registerLevel: IPublicEnumPluginRegisterLevel; + editorWindow: IPublicModelWindow; constructor( options: IPluginContextOptions, diff --git a/packages/shell/src/model/resource.ts b/packages/shell/src/model/resource.ts index b2b0653981..43f28fbd8d 100644 --- a/packages/shell/src/model/resource.ts +++ b/packages/shell/src/model/resource.ts @@ -25,6 +25,10 @@ export class Resource implements IPublicModelResource { return this[resourceSymbol].resourceType.name; } + get config() { + return this[resourceSymbol].config; + } + get type() { return this[resourceSymbol].resourceType.type; } diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index 6af2534dd3..f539e95678 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -44,7 +44,10 @@ export class Window implements IPublicModelWindow { } get currentEditorView() { - return new EditorView(this[windowSymbol].editorView).toProxy() as any; + if (this[windowSymbol].editorView) { + return new EditorView(this[windowSymbol].editorView).toProxy() as any; + } + return null; } get editorViews() { diff --git a/packages/types/src/shell/model/resource.ts b/packages/types/src/shell/model/resource.ts index e18f3d5032..1f59845e69 100644 --- a/packages/types/src/shell/model/resource.ts +++ b/packages/types/src/shell/model/resource.ts @@ -18,6 +18,10 @@ export interface IBaseModelResource< get children(): Resource[]; get viewName(): string | undefined; + + get config(): { + disableBehaviors?: ('copy' | 'remove')[]; + } | undefined; } export type IPublicModelResource = IBaseModelResource<IPublicModelResource>; diff --git a/packages/types/src/shell/model/window.ts b/packages/types/src/shell/model/window.ts index 5f77b0cbf8..a33be6ceb1 100644 --- a/packages/types/src/shell/model/window.ts +++ b/packages/types/src/shell/model/window.ts @@ -23,7 +23,7 @@ export interface IPublicModelWindow< * 窗口当前视图 * @since v1.1.7 */ - currentEditorView: IPublicModelEditorView; + currentEditorView: IPublicModelEditorView | null; /** * 窗口全部视图实例 diff --git a/packages/types/src/shell/type/resource-list.ts b/packages/types/src/shell/type/resource-list.ts index 5831d7b507..7abdcc7b13 100644 --- a/packages/types/src/shell/type/resource-list.ts +++ b/packages/types/src/shell/type/resource-list.ts @@ -24,6 +24,10 @@ export interface IPublicResourceData { /** 资源子元素 */ children?: IPublicResourceData[]; + + config?: { + disableBehaviors?: ('copy' | 'remove')[]; + }; } export type IPublicResourceList = IPublicResourceData[]; \ No newline at end of file diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index b12a78183a..b359a6139f 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -101,7 +101,7 @@ export class BasicContext implements IBasicContext { preference: IPluginPreferenceMananger; workspace: IWorkspace; - constructor(innerWorkspace: IWorkspace, viewName: string, registerLevel: IPublicEnumPluginRegisterLevel, public editorWindow?: IEditorWindow) { + constructor(innerWorkspace: IWorkspace, viewName: string, readonly registerLevel: IPublicEnumPluginRegisterLevel, public editorWindow?: IEditorWindow) { const editor = new Editor(viewName, true); const innerSkeleton = new InnerSkeleton(editor, viewName); diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index e51993c81e..8c59aed1ef 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -74,6 +74,10 @@ export class Resource implements IResource { return this.resourceData?.children?.map(d => new Resource(d, this.workspace.getResourceType(d.resourceName || this.resourceType.name), this.workspace)) || []; } + get config() { + return this.resourceData.config; + } + constructor(readonly resourceData: IPublicResourceData, readonly resourceType: IResourceType, readonly workspace: IWorkspace) { this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`, IPublicEnumPluginRegisterLevel.Resource); this.resourceTypeInstance = resourceType.resourceTypeModel(this.context.innerPlugins._getLowCodePluginContext({ From 9fd28efd0ea6f4d872928d1e339c852b817194da Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 26 Apr 2023 10:57:28 +0800 Subject: [PATCH 121/469] fix: removeEditorWindow does not compare title --- packages/workspace/src/workspace.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 37341cdc3f..c723d2b5c5 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -192,8 +192,8 @@ export class Workspace implements IWorkspace { this.emitChangeWindow(); } - removeEditorWindow(resourceName: string) { - const index = this.windows.findIndex(d => (d.resource?.name === resourceName && d.title)); + removeEditorWindow(resourceName: string, title: string) { + const index = this.windows.findIndex(d => (d.resource?.name === resourceName && d.title === title)); this.remove(index); } From 70120a033af95e4d09f3c152c7a6464c5b2ec683 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 26 Apr 2023 15:34:02 +0800 Subject: [PATCH 122/469] feat: get editor from this or params --- .../bem-tools/border-resizing.tsx | 13 ++++---- .../bem-tools/border-selecting.tsx | 5 ++- .../live-editing/live-editing.ts | 17 +++++----- .../builtin-simulator/node-selector/index.tsx | 5 ++- packages/designer/src/component-meta.ts | 2 ++ .../designer/src/document/document-model.ts | 5 +++ packages/designer/src/document/history.ts | 13 ++++---- .../src/document/node/node-children.ts | 33 +++++++------------ .../settings/settings-primary-pane.tsx | 5 +-- .../src/components/widget-views/index.tsx | 14 +++----- packages/workspace/src/workspace.ts | 3 ++ 11 files changed, 53 insertions(+), 62 deletions(-) diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx index 29401ca6b6..4b3c5c31a9 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx @@ -1,10 +1,10 @@ import React, { Component, Fragment } from 'react'; import DragResizeEngine from './drag-resize-engine'; -import { observer, computed, globalContext } from '@alilc/lowcode-editor-core'; +import { observer, computed } from '@alilc/lowcode-editor-core'; import classNames from 'classnames'; import { SimulatorContext } from '../context'; import { BuiltinSimulatorHost } from '../host'; -import { OffsetObserver, Designer } from '../../designer'; +import { OffsetObserver, Designer, INode } from '../../designer'; import { Node } from '../../document'; import { normalizeTriggers } from '../../utils/misc'; @@ -135,7 +135,7 @@ export class BoxResizingInstance extends Component<{ // this.hoveringCapture.setBoundary(this.outline); this.willBind(); - const resize = (e: MouseEvent, direction: string, node: any, moveX: number, moveY: number) => { + const resize = (e: MouseEvent, direction: string, node: INode, moveX: number, moveY: number) => { const { advanced } = node.componentMeta; if ( advanced.callbacks && @@ -149,7 +149,7 @@ export class BoxResizingInstance extends Component<{ } }; - const resizeStart = (e: MouseEvent, direction: string, node: any) => { + const resizeStart = (e: MouseEvent, direction: string, node: INode) => { const { advanced } = node.componentMeta; if ( advanced.callbacks && @@ -161,7 +161,7 @@ export class BoxResizingInstance extends Component<{ } }; - const resizeEnd = (e: MouseEvent, direction: string, node: any) => { + const resizeEnd = (e: MouseEvent, direction: string, node: INode) => { const { advanced } = node.componentMeta; if ( advanced.callbacks && @@ -172,8 +172,7 @@ export class BoxResizingInstance extends Component<{ advanced.callbacks.onResizeEnd(e, cbNode); } - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); + const editor = node.document?.designer.editor; const npm = node?.componentMeta?.npm; const selected = [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx index 75b4a34881..0e9d734b60 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx @@ -9,7 +9,7 @@ import { ComponentType, } from 'react'; import classNames from 'classnames'; -import { observer, computed, Tip, globalContext } from '@alilc/lowcode-editor-core'; +import { observer, computed, Tip } from '@alilc/lowcode-editor-core'; import { createIcon, isReactComponent, isActionContentObject } from '@alilc/lowcode-utils'; import { IPublicTypeActionContentObject } from '@alilc/lowcode-types'; import { BuiltinSimulatorHost } from '../host'; @@ -131,8 +131,7 @@ function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActio className="lc-borders-action" onClick={() => { action && action(node.internalToShellNode()!); - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); + const editor = node.document?.designer.editor; const npm = node?.componentMeta?.npm; const selected = [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || diff --git a/packages/designer/src/builtin-simulator/live-editing/live-editing.ts b/packages/designer/src/builtin-simulator/live-editing/live-editing.ts index e92e266ee9..c8594d701b 100644 --- a/packages/designer/src/builtin-simulator/live-editing/live-editing.ts +++ b/packages/designer/src/builtin-simulator/live-editing/live-editing.ts @@ -1,6 +1,6 @@ -import { obx, globalContext } from '@alilc/lowcode-editor-core'; +import { obx } from '@alilc/lowcode-editor-core'; import { IPublicTypePluginConfig, IPublicTypeLiveTextEditingConfig } from '@alilc/lowcode-types'; -import { Node, Prop } from '../../document'; +import { INode, Prop } from '../../document'; const EDITOR_KEY = 'data-setter-prop'; @@ -17,7 +17,7 @@ function defaultSaveContent(content: string, prop: Prop) { } export interface EditingTarget { - node: Node; + node: INode; rootElement: HTMLElement; event: MouseEvent; } @@ -47,13 +47,16 @@ export class LiveEditing { @obx.ref private _editing: Prop | null = null; + private _dispose?: () => void; + + private _save?: () => void; + apply(target: EditingTarget) { const { node, event, rootElement } = target; const targetElement = event.target as HTMLElement; const { liveTextEditing } = node.componentMeta; - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); + const editor = node.document?.designer.editor; const npm = node?.componentMeta?.npm; const selected = [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || node?.componentMeta?.componentName || ''; @@ -166,10 +169,6 @@ export class LiveEditing { return this._editing; } - private _dispose?: () => void; - - private _save?: () => void; - saveAndDispose() { if (this._save) { this._save(); diff --git a/packages/designer/src/builtin-simulator/node-selector/index.tsx b/packages/designer/src/builtin-simulator/node-selector/index.tsx index 09c8f12622..07ae754aae 100644 --- a/packages/designer/src/builtin-simulator/node-selector/index.tsx +++ b/packages/designer/src/builtin-simulator/node-selector/index.tsx @@ -1,6 +1,6 @@ import { Overlay } from '@alifd/next'; import React, { MouseEvent } from 'react'; -import { Title, globalContext } from '@alilc/lowcode-editor-core'; +import { Title } from '@alilc/lowcode-editor-core'; import { canClickNode } from '@alilc/lowcode-utils'; import './index.less'; @@ -66,8 +66,7 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState if (canClick && typeof node.select === 'function') { node.select(); - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); + const editor = node.document?.designer.editor; const npm = node?.componentMeta?.npm; const selected = [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 4b0a613cb4..00c4956217 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -60,6 +60,8 @@ export function buildFilter(rule?: string | string[] | RegExp | IPublicTypeNesti export interface IComponentMeta extends IPublicModelComponentMeta<INode> { prototype?: any; + liveTextEditing?: IPublicTypeLiveTextEditingConfig[]; + get rootSelector(): string | undefined; setMetadata(metadata: IPublicTypeComponentMetadata): void; diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index c55e7a8e47..699775bc77 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -148,6 +148,10 @@ export interface IDocumentModel extends Omit<IPublicModelDocumentModel< suspense(): void; close(): void; + + unlinkNode(node: INode): void; + + destroyNode(node: INode): void; } export class DocumentModel implements IDocumentModel { @@ -333,6 +337,7 @@ export class DocumentModel implements IDocumentModel { this.import(schema as IPublicTypeRootSchema, true); this.simulator?.rerender(); }, + this, ); this.setupListenActiveNodes(); diff --git a/packages/designer/src/document/history.ts b/packages/designer/src/document/history.ts index d190a9a9cb..ca288c03a8 100644 --- a/packages/designer/src/document/history.ts +++ b/packages/designer/src/document/history.ts @@ -1,6 +1,7 @@ -import { reaction, untracked, globalContext, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; +import { reaction, untracked, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { IPublicTypeNodeSchema, IPublicModelHistory, IPublicTypeDisposable } from '@alilc/lowcode-types'; import { Logger } from '@alilc/lowcode-utils'; +import { IDocumentModel } from '../designer'; const logger = new Logger({ level: 'warn', bizName: 'history' }); @@ -37,10 +38,12 @@ export class History<T = IPublicTypeNodeSchema> implements IHistory { return this.session.data; } + private timeGap: number = 1000; + constructor( dataFn: () => T | null, private redoer: (data: T) => void, - private timeGap: number = 1000, + private document?: IDocumentModel, ) { this.session = new Session(0, null, this.timeGap); this.records = [this.session]; @@ -130,8 +133,7 @@ export class History<T = IPublicTypeNodeSchema> implements IHistory { } const cursor = this.session.cursor - 1; this.go(cursor); - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); + const editor = this.document?.designer.editor; if (!editor) { return; } @@ -144,8 +146,7 @@ export class History<T = IPublicTypeNodeSchema> implements IHistory { } const cursor = this.session.cursor + 1; this.go(cursor); - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); + const editor = this.document?.designer.editor; if (!editor) { return; } diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index 1b6df58660..4fb1c3d226 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -1,4 +1,4 @@ -import { obx, computed, globalContext, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; +import { obx, computed, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { Node, INode } from './node'; import { IPublicTypeNodeData, IPublicModelNodeChildren, IPublicEnumTransformStage, IPublicTypeDisposable } from '@alilc/lowcode-types'; import { shallowEqual, compatStage, isNodeSchema } from '@alilc/lowcode-utils'; @@ -16,12 +16,12 @@ export interface INodeChildren extends Omit<IPublicModelNodeChildren<INode>, 'isEmpty' | 'notEmpty' > { + children: INode[]; + get owner(): INode; get length(): number; - children: INode[]; - unlinkChild(node: INode): void; /** @@ -239,11 +239,8 @@ export class NodeChildren implements INodeChildren { } const { document } = node; /* istanbul ignore next */ - if (globalContext.has('editor')) { - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); - editor.eventBus.emit('node.remove', { node, index: i }); - } + const editor = node.document?.designer.editor; + editor?.eventBus.emit('node.remove', { node, index: i }); document?.unlinkNode(node); document?.selection.remove(node.id); document?.destroyNode(node); @@ -281,14 +278,11 @@ export class NodeChildren implements INodeChildren { const i = children.map(d => d.id).indexOf(node.id); if (node.parent) { - if (globalContext.has('editor')) { - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); - editor.eventBus.emit('node.remove.topLevel', { - node, - index: node.index, - }); - } + const editor = node.document?.designer.editor; + editor?.eventBus.emit('node.remove.topLevel', { + node, + index: node.index, + }); } if (i < 0) { @@ -317,11 +311,8 @@ export class NodeChildren implements INodeChildren { }); this.emitter.emit('insert', node); /* istanbul ignore next */ - if (globalContext.has('editor')) { - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); - editor.eventBus.emit('node.add', { node }); - } + const editor = node.document?.designer.editor; + editor?.eventBus.emit('node.add', { node }); if (useMutator) { this.reportModified(node, this.owner, { type: 'insert' }); } diff --git a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx index 0bbef4bf26..800719588f 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -53,8 +53,7 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, { } renderBreadcrumb() { - const { settings } = this.main; - const { config } = this.props; + const { settings, editor } = this.main; // const shouldIgnoreRoot = config.props?.ignoreRoot; const { shouldIgnoreRoot } = this.state; if (!settings) { @@ -73,8 +72,6 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, { ); } - const workspace = globalContext.get('workspace'); - const editor = this.props.engineEditor; const designer = editor.get('designer'); const current = designer?.currentSelection?.getNodes()?.[0]; let node: INode | null = settings.first; diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index 87f11664c9..513fc1bdd6 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -1,7 +1,7 @@ import { Component, ReactElement } from 'react'; import { Icon } from '@alifd/next'; import classNames from 'classnames'; -import { Title, observer, Tip, globalContext } from '@alilc/lowcode-editor-core'; +import { Title, observer, Tip } from '@alilc/lowcode-editor-core'; import { DockProps } from '../../types'; import { PanelDock } from '../../widget/panel-dock'; import { composeTitle } from '../../widget/utils'; @@ -116,14 +116,12 @@ export class DraggableLineView extends Component<{ panel: Panel }> { } // 抛出事件,对于有些需要 panel 插件随着 度变化进行再次渲染的,由panel插件内部监听事件实现 - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); + const editor = this.props.panel.skeleton.editor; editor?.eventBus.emit('dockpane.drag', width); } onDragChange(type: 'start' | 'end') { - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); + const editor = this.props.panel.skeleton.editor; editor?.eventBus.emit('dockpane.dragchange', type); // builtinSimulator 屏蔽掉 鼠标事件 editor?.eventBus.emit('designer.builtinSimulator.disabledEvents', type === 'start'); @@ -187,8 +185,7 @@ export class TitledPanelView extends Component<{ panel: Panel; area?: string }> if (!panel.inited) { return null; } - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); + const editor = panel.skeleton.editor; const panelName = area ? `${area}-${panel.name}` : panel.name; editor?.eventBus.emit('skeleton.panel.toggle', { name: panelName || '', @@ -250,8 +247,7 @@ export class PanelView extends Component<{ if (!panel.inited) { return null; } - const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); + const editor = panel.skeleton.editor; const panelName = area ? `${area}-${panel.name}` : panel.name; editor?.eventBus.emit('skeleton.panel.toggle', { name: panelName || '', diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index c723d2b5c5..26e1d65519 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -183,6 +183,9 @@ export class Workspace implements IWorkspace { } private remove(index: number) { + if (index < 0) { + return; + } const window = this.windows[index]; this.windows.splice(index, 1); if (this.window === window) { From c11bceb2cea9548947b724a179518ac0ea280b62 Mon Sep 17 00:00:00 2001 From: wendell0316 <wangdong9603@163.com> Date: Thu, 27 Apr 2023 09:43:56 +0800 Subject: [PATCH 123/469] feat: add more props for popup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: popup可以接受外部参数 目前配置都是固定的,对于一些简单定制化的需求无法满足 * feat: 增加类型约束,固定可修改项 * Revert "feat: 增加类型约束,固定可修改项" This reverts commit 7e3b4dd1fafce56bfb94d7f77fda729eec4066d0. * feat: 添加类型 --- .../src/components/popup/index.tsx | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/packages/editor-skeleton/src/components/popup/index.tsx b/packages/editor-skeleton/src/components/popup/index.tsx index 68897d61a7..1367723a16 100644 --- a/packages/editor-skeleton/src/components/popup/index.tsx +++ b/packages/editor-skeleton/src/components/popup/index.tsx @@ -4,6 +4,22 @@ import { uniqueId } from '@alilc/lowcode-utils'; import { IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import './style.less'; +export interface PopupExtProps { + width?: number; + hasMask?: boolean; + trigger?: ReactNode; + canCloseByOutSideClick?: boolean + className?: string; + safeNode?: string[]; +} + +interface PopupProps extends PopupExtProps{ + content?: ReactNode, + title?: ReactNode, + actionKey?: string +} + + export const PopupContext = createContext<PopupPipe>({} as any); export class PopupPipe { @@ -11,7 +27,7 @@ export class PopupPipe { private currentId?: string; - create(props?: object): { + create(props?: PopupExtProps): { send: (content: ReactNode, title: ReactNode) => void; show: (target: Element) => void; } { @@ -45,13 +61,13 @@ export class PopupPipe { }; } - private popup(props: object, target?: Element) { + private popup(props: PopupProps, target?: Element) { Promise.resolve().then(() => { this.emitter.emit('popupchange', props, target); }); } - onPopupChange(fn: (props: object, target?: Element) => void): () => void { + onPopupChange(fn: (props: PopupProps, target?: Element) => void): () => void { this.emitter.on('popupchange', fn); return () => { this.emitter.removeListener('popupchange', fn); @@ -86,18 +102,23 @@ export default class PopupService extends Component<{ } } +interface StateType extends PopupProps { + visible?: boolean, + offsetX?: number, + pos?: {top: number, height: number} +} export class PopupContent extends PureComponent<{ safeId?: string; popupContainer?: string }> { static contextType = PopupContext; popupContainerId = uniqueId('popupContainer'); - state: any = { + state: StateType = { visible: false, offsetX: -300, }; private dispose = (this.context as PopupPipe).onPopupChange((props, target) => { - const state: any = { + const state: StateType = { ...props, visible: true, }; @@ -132,7 +153,7 @@ export class PopupContent extends PureComponent<{ safeId?: string; popupContaine }; render() { - const { content, visible, title, actionKey, pos, offsetX } = this.state; + const { content, visible, title, actionKey, pos, offsetX, width = 360, hasMask = false, canCloseByOutSideClick = true, safeNode = [] } = this.state; if (!visible) { return null; } @@ -146,10 +167,10 @@ export class PopupContent extends PureComponent<{ safeId?: string; popupContaine return ( <Drawer - width={360} + width={width} visible={visible} offset={[offsetX, 0]} - hasMask={false} + hasMask={hasMask} onVisibleChange={(_visible, type) => { if (avoidLaterHidden) { return; @@ -160,11 +181,11 @@ export class PopupContent extends PureComponent<{ safeId?: string; popupContaine }} trigger={<div className="lc-popup-placeholder" style={pos} />} triggerType="click" - canCloseByOutSideClick + canCloseByOutSideClick={canCloseByOutSideClick} animation={false} onClose={this.onClose} id={this.props.safeId} - safeNode={id} + safeNode={[id, ...safeNode]} closeable container={this.props.popupContainer} > From 04f5416050e4bf1f0fb286762eac1c023190033f Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 27 Apr 2023 10:05:55 +0800 Subject: [PATCH 124/469] chore(docs): publish docs 1.0.28 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 8c6e8a86cb..80f146513f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.27", + "version": "1.0.28", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From ec4a95c9ba4de05c950ee7cd216311e225a2aef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E6=9E=97?= <chenglin@dian.so> Date: Thu, 27 Apr 2023 15:41:20 +0800 Subject: [PATCH 125/469] fix: fix proxy plugins.delete not added async --- packages/shell/src/api/plugins.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/shell/src/api/plugins.ts b/packages/shell/src/api/plugins.ts index e5a79edbd4..b6f5e63717 100644 --- a/packages/shell/src/api/plugins.ts +++ b/packages/shell/src/api/plugins.ts @@ -66,8 +66,8 @@ export class Plugins implements IPublicApiPlugins { return this[pluginsSymbol].has(pluginName); } - delete(pluginName: string) { - this[pluginsSymbol].delete(pluginName); + async delete(pluginName: string) { + return await this[pluginsSymbol].delete(pluginName); } toProxy() { From 1bb46dcf3be698dd12bdecb6d9e03f673674365f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E6=9E=97?= <chenglin@dian.so> Date: Thu, 4 May 2023 15:28:09 +0800 Subject: [PATCH 126/469] chore: safer plugins.delete --- packages/designer/src/plugin/plugin-manager.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/designer/src/plugin/plugin-manager.ts b/packages/designer/src/plugin/plugin-manager.ts index 449afebdff..071bfa9d14 100644 --- a/packages/designer/src/plugin/plugin-manager.ts +++ b/packages/designer/src/plugin/plugin-manager.ts @@ -143,11 +143,10 @@ export class LowCodePluginManager implements ILowCodePluginManager { } async delete(pluginName: string): Promise<boolean> { - const idx = this.plugins.findIndex((plugin) => plugin.name === pluginName); - if (idx === -1) return false; - const plugin = this.plugins[idx]; + const plugin = this.plugins.find(({ name }) => name === pluginName); + if (!plugin) return false; await plugin.destroy(); - + const idx = this.plugins.indexOf(plugin); this.plugins.splice(idx, 1); return this.pluginsMap.delete(pluginName); } From 4db1971c3f84ff55d73e5b4199f52289f33dab54 Mon Sep 17 00:00:00 2001 From: milocooper <milocooper@163.com> Date: Wed, 3 May 2023 21:24:37 +0800 Subject: [PATCH 127/469] fix: Corrects the fourth heading name related to how drag is made in edit page documents. --- docs/docs/guide/design/editor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/guide/design/editor.md b/docs/docs/guide/design/editor.md index fcead2922c..0614d9c332 100644 --- a/docs/docs/guide/design/editor.md +++ b/docs/docs/guide/design/editor.md @@ -336,7 +336,7 @@ simulator-renderer 通过调用 host 的方法,将 schema、components 等参 1. **画布内拖拽:**此时 sensor 是 simulatorHost,拖拽完成之后,会根据拖拽的位置来完成节点的精确插入。 2. **从组件面板拖拽到画布**:此时的 sensor 还是 simulatorHost,因为拖拽结束的目标还是画布。 3. **大纲树面板拖拽到画布中**:此时有两个 sensor,一个是大纲树,当我们拖拽到画布区域时,画布区域内的 simulatorHost 开始接管。 -4. **画布拖拽到画布中**:从画布中开始拖拽时,最新生效的是 simulatorHost,当离开画布到大纲树时,大纲树 sensor 开始接管生效。当拖拽到大纲树的某一个节点下时,大纲树会将大纲树中的信息转化为 schema,然后渲染到画布中。 +4. **画布拖拽到大纲树中**:从画布中开始拖拽时,最新生效的是 simulatorHost,当离开画布到大纲树时,大纲树 sensor 开始接管生效。当拖拽到大纲树的某一个节点下时,大纲树会将大纲树中的信息转化为 schema,然后渲染到画布中。 ### 其他 引擎的编排能力远远不止上述所描述的功能,这里只描述了其核心和关键的功能。在整个引擎的迭代和设计过程中还有很多细节来使我们的引擎更好用、更容易扩展。 From 57889d5ad02aa2a3418ab3dc719e9a60aef2a3dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Thu, 4 May 2023 17:01:02 +0800 Subject: [PATCH 128/469] fix: use noop function instead --- modules/code-generator/src/plugins/component/react/jsx.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/src/plugins/component/react/jsx.ts b/modules/code-generator/src/plugins/component/react/jsx.ts index 7cf5bd9de3..588b356ad6 100644 --- a/modules/code-generator/src/plugins/component/react/jsx.ts +++ b/modules/code-generator/src/plugins/component/react/jsx.ts @@ -58,7 +58,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => generateCompositeType( { type: 'JSFunction', - value: input.value || 'null', + value: input.value || 'function () {}', }, Scope.createRootScope(), ), From 9a68f0f27c062b637ace824eca7ccaa6ed9573b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Thu, 4 May 2023 17:02:17 +0800 Subject: [PATCH 129/469] fix: attr name in IPublicTypePanelDockConfig should not be optional --- packages/types/src/shell/type/widget-base-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/types/src/shell/type/widget-base-config.ts b/packages/types/src/shell/type/widget-base-config.ts index f8268628bc..edddf2d68f 100644 --- a/packages/types/src/shell/type/widget-base-config.ts +++ b/packages/types/src/shell/type/widget-base-config.ts @@ -25,7 +25,7 @@ export interface IPublicTypePanelDockConfig extends IPublicTypeWidgetBaseConfig props?: IPublicTypePanelDockProps; /** 面板 name, 当没有 props.title 时, 会使用 name 作为标题 */ - name?: string; + name: string; } export interface IPublicTypePanelDockProps { From 5b68b860acdcd078d7a9bb6acd18cb01d51a4552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Thu, 4 May 2023 17:03:37 +0800 Subject: [PATCH 130/469] refactor: moduleName of Component should not be converted --- modules/code-generator/src/parser/SchemaParser.ts | 5 +++-- .../src/plugins/component/react/containerClass.ts | 2 +- modules/code-generator/src/utils/schema.ts | 6 ++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/modules/code-generator/src/parser/SchemaParser.ts b/modules/code-generator/src/parser/SchemaParser.ts index 3108fee477..c6263877c1 100644 --- a/modules/code-generator/src/parser/SchemaParser.ts +++ b/modules/code-generator/src/parser/SchemaParser.ts @@ -32,7 +32,7 @@ import { import { SUPPORT_SCHEMA_VERSION_LIST } from '../const'; import { getErrorMessage } from '../utils/errors'; -import { handleSubNodes, isValidContainerType } from '../utils/schema'; +import { handleSubNodes, isValidContainerType, ContainerType } from '../utils/schema'; import { uniqueArray } from '../utils/common'; import { componentAnalyzer } from '../analyzer/componentAnalyzer'; import { ensureValidClassName } from '../utils/validate'; @@ -161,7 +161,8 @@ export class SchemaParser implements ISchemaParser { ...subRoot, componentName: getRootComponentName(subRoot.componentName, compDeps), containerType: subRoot.componentName, - moduleName: ensureValidClassName(changeCase.pascalCase(subRoot.fileName)), + moduleName: ensureValidClassName(subRoot.componentName === ContainerType.Component ? + subRoot.fileName : changeCase.pascalCase(subRoot.fileName)), }; return container; }); diff --git a/modules/code-generator/src/plugins/component/react/containerClass.ts b/modules/code-generator/src/plugins/component/react/containerClass.ts index b4c474b38a..eab6cbebee 100644 --- a/modules/code-generator/src/plugins/component/react/containerClass.ts +++ b/modules/code-generator/src/plugins/component/react/containerClass.ts @@ -48,7 +48,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { type: ChunkType.STRING, fileType: FileType.JSX, name: CLASS_DEFINE_CHUNK_NAME.InsVar, - content: `static displayName = '${changeCase.pascalCase(ir.moduleName)}';`, + content: `static displayName = '${ir.moduleName}';`, linkAfter: [ CLASS_DEFINE_CHUNK_NAME.Start, ], diff --git a/modules/code-generator/src/utils/schema.ts b/modules/code-generator/src/utils/schema.ts index 831b38965a..f9529945eb 100644 --- a/modules/code-generator/src/utils/schema.ts +++ b/modules/code-generator/src/utils/schema.ts @@ -147,4 +147,10 @@ export function isValidContainerType(schema: IPublicTypeNodeSchema) { 'Component', 'Block', ].includes(schema.componentName); +} + +export const enum ContainerType { + Page = 'Page', + Component = 'Component', + Block = 'Block', } \ No newline at end of file From b695bdaadb47db02dd85ea59b8df3739927fd164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Sat, 6 May 2023 17:08:58 +0800 Subject: [PATCH 131/469] chore(release): code-generator - 1.1.1 --- modules/code-generator/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index 97d945469f..8fc9ef953d 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-code-generator", - "version": "1.1.0", + "version": "1.1.1", "description": "出码引擎 for LowCode Engine", "license": "MIT", "main": "lib/index.js", @@ -145,4 +145,4 @@ "registry": "https://registry.npmjs.org/" }, "repository": "git@github.com:alibaba/lowcode-engine.git" -} \ No newline at end of file +} From 9410d21de3f7a86769b37038b3b49365cc84511e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Sat, 6 May 2023 17:11:26 +0800 Subject: [PATCH 132/469] chore(release): code-generator - 1.1.2 --- modules/code-generator/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index 8fc9ef953d..f830b23ede 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-code-generator", - "version": "1.1.1", + "version": "1.1.2", "description": "出码引擎 for LowCode Engine", "license": "MIT", "main": "lib/index.js", From 9947a36d1778e9cf76740b4d8bf4a6b134d1e74e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Sat, 6 May 2023 17:46:53 +0800 Subject: [PATCH 133/469] refactor: synchronize exports of standalone with the normal entry --- modules/code-generator/src/index.ts | 4 +-- modules/code-generator/src/standalone.ts | 31 ++++++++++++++++++------ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/modules/code-generator/src/index.ts b/modules/code-generator/src/index.ts index 0c8fdf3849..da9b12d877 100644 --- a/modules/code-generator/src/index.ts +++ b/modules/code-generator/src/index.ts @@ -9,7 +9,7 @@ import { createModuleBuilder } from './generator/ModuleBuilder'; import { createDiskPublisher } from './publisher/disk'; import { createZipPublisher } from './publisher/zip'; import createIceJsProjectBuilder, { plugins as icejsPlugins } from './solutions/icejs'; -import createIce3JsProjectBuilder, { plugins as icejs3Plugins } from './solutions/icejs3'; +import createIceJs3ProjectBuilder, { plugins as icejs3Plugins } from './solutions/icejs3'; import createRaxAppProjectBuilder, { plugins as raxPlugins } from './solutions/rax-app'; // 引入说明 @@ -42,7 +42,7 @@ export default { createModuleBuilder, solutions: { icejs: createIceJsProjectBuilder, - icejs3: createIce3JsProjectBuilder, + icejs3: createIceJs3ProjectBuilder, rax: createRaxAppProjectBuilder, }, solutionParts: { diff --git a/modules/code-generator/src/standalone.ts b/modules/code-generator/src/standalone.ts index 2f15515cf8..23d16e61f0 100644 --- a/modules/code-generator/src/standalone.ts +++ b/modules/code-generator/src/standalone.ts @@ -8,7 +8,8 @@ import './polyfills/buffer'; import { createProjectBuilder } from './generator/ProjectBuilder'; import { createModuleBuilder } from './generator/ModuleBuilder'; import { createZipPublisher } from './publisher/zip'; -import createIceJsProjectBuilder, { plugins as reactPlugins } from './solutions/icejs'; +import createIceJsProjectBuilder, { plugins as icejsPlugins } from './solutions/icejs'; +import createIceJs3ProjectBuilder, { plugins as icejs3Plugins } from './solutions/icejs3'; import createRaxAppProjectBuilder, { plugins as raxPlugins } from './solutions/rax-app'; // 引入说明 @@ -18,6 +19,7 @@ import { COMMON_CHUNK_NAME, CLASS_DEFINE_CHUNK_NAME, DEFAULT_LINK_AFTER } from ' // 引入通用插件组 import esmodule from './plugins/common/esmodule'; import requireUtils from './plugins/common/requireUtils'; +import styleImport from './plugins/common/styleImport'; import css from './plugins/component/style/css'; import constants from './plugins/project/constants'; @@ -32,6 +34,7 @@ import * as CONSTANTS from './const'; // 引入内置解决方案模块 import icejs from './plugins/project/framework/icejs'; +import icejs3 from './plugins/project/framework/icejs3'; import rax from './plugins/project/framework/rax'; export default { @@ -39,10 +42,12 @@ export default { createModuleBuilder, solutions: { icejs: createIceJsProjectBuilder, + icejs3: createIceJs3ProjectBuilder, rax: createRaxAppProjectBuilder, }, solutionParts: { icejs, + icejs3, rax, }, publishers: { @@ -50,6 +55,7 @@ export default { }, plugins: { common: { + /** * 处理 ES Module * @deprecated please use esModule @@ -57,12 +63,7 @@ export default { esmodule, esModule: esmodule, requireUtils, - }, - react: { - ...reactPlugins, - }, - rax: { - ...raxPlugins, + styleImport, }, style: { css, @@ -72,6 +73,22 @@ export default { i18n, utils, }, + icejs: { + ...icejsPlugins, + }, + icejs3: { + ...icejs3Plugins, + }, + rax: { + ...raxPlugins, + }, + + /** + * @deprecated please use icejs + */ + react: { + ...icejsPlugins, + }, }, postprocessor: { prettier, From 239bb29de1853c87f687a4355df76179a09d5ae5 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 11 May 2023 10:01:56 +0800 Subject: [PATCH 134/469] feat: add skeleton item model --- .../designer/src/document/document-model.ts | 2 +- .../designer/src/document/node/props/prop.ts | 4 +++ packages/designer/src/project/project.ts | 8 ++--- packages/editor-skeleton/src/skeleton.ts | 7 +++-- packages/editor-skeleton/src/widget/panel.ts | 4 +++ packages/engine/src/modules/classes.ts | 2 ++ packages/engine/src/modules/symbols.ts | 2 ++ packages/shell/src/api/skeleton.ts | 18 ++++++++--- packages/shell/src/index.ts | 2 ++ packages/shell/src/model/index.ts | 1 + packages/shell/src/model/skeleton-item.ts | 31 +++++++++++++++++++ packages/shell/src/symbols.ts | 3 +- packages/types/src/shell/api/skeleton.ts | 3 +- packages/types/src/shell/model/index.ts | 1 + .../types/src/shell/model/skeleton-item.ts | 6 ++++ .../workspace/src/context/view-context.ts | 2 ++ 16 files changed, 83 insertions(+), 13 deletions(-) create mode 100644 packages/shell/src/model/skeleton-item.ts create mode 100644 packages/types/src/shell/model/skeleton-item.ts diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 699775bc77..2d39ed1151 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -141,7 +141,7 @@ export interface IDocumentModel extends Omit<IPublicModelDocumentModel< insertNodes(parent: INode, thing: INode[] | IPublicTypeNodeData[], at?: number | null, copy?: boolean): INode[]; - open(): DocumentModel; + open(): IDocumentModel; remove(): void; diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 5dc1ea5dfe..37017d72d8 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -16,6 +16,8 @@ export type UNSET = typeof UNSET; export interface IProp extends Omit<IPublicModelProp< INode >, 'exportSchema' | 'node'>, IPropParent { + spread: boolean; + key: string | number | undefined; readonly props: IProps; @@ -42,6 +44,8 @@ export interface IProp extends Omit<IPublicModelProp< setupItems(): IProp[] | null; + isVirtual(): boolean; + get type(): ValueTypes; get size(): number; diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 0675190b28..75e621d5e2 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -1,7 +1,7 @@ import { obx, computed, makeObservable, action, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { IDesigner } from '../designer'; import { DocumentModel, isDocumentModel } from '../document'; -import type { IDocumentModel } from "../document"; +import type { IDocumentModel } from '../document'; import { IPublicTypeComponentsMap, IPublicEnumTransformStage, @@ -317,13 +317,13 @@ export class Project implements IProject { doc = this.createDocument(); return doc.open(); } - if (typeof doc === 'string') { - const got = this.documents.find((item) => item.fileName === doc || item.id === doc); + if (typeof doc === 'string' || typeof doc === 'number') { + const got = this.documents.find((item) => item.fileName === String(doc) || String(item.id) === String(doc)); if (got) { return got.open(); } - const data = this.data.componentsTree.find((data) => data.fileName === doc); + const data = this.data.componentsTree.find((data) => data.fileName === String(doc)); if (data) { doc = this.createDocument(data); return doc.open(); diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 180859f1d9..616e7f0172 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -56,7 +56,8 @@ export interface ISkeleton extends Omit<IPublicApiSkeleton, 'onShowWidget' | 'onHideWidget' | 'remove' | - 'hideArea' + 'hideArea' | + 'add' > { editor: IEditor; @@ -101,6 +102,8 @@ export interface ISkeleton extends Omit<IPublicApiSkeleton, ): WidgetContainer; createPanel(config: PanelConfig): Panel; + + add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined; } export class Skeleton { @@ -440,7 +443,7 @@ export class Skeleton { return restConfig; } - add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>) { + add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined { const parsedConfig = { ...this.parseConfig(config), ...extraConfig, diff --git a/packages/editor-skeleton/src/widget/panel.ts b/packages/editor-skeleton/src/widget/panel.ts index feec08da7a..b35af6a212 100644 --- a/packages/editor-skeleton/src/widget/panel.ts +++ b/packages/editor-skeleton/src/widget/panel.ts @@ -211,6 +211,10 @@ export class Panel implements IWidget { this.setActive(false); } + disable() {} + + enable(): void {} + show() { this.setActive(true); } diff --git a/packages/engine/src/modules/classes.ts b/packages/engine/src/modules/classes.ts index 44aeed9651..d68ea43de2 100644 --- a/packages/engine/src/modules/classes.ts +++ b/packages/engine/src/modules/classes.ts @@ -10,6 +10,7 @@ import { Selection, Prop, SimulatorHost, + SkeletonItem, } from '@alilc/lowcode-shell'; import { Node as InnerNode } from '@alilc/lowcode-designer'; @@ -26,4 +27,5 @@ export default { Selection, Prop, SimulatorHost, + SkeletonItem, }; diff --git a/packages/engine/src/modules/symbols.ts b/packages/engine/src/modules/symbols.ts index 7faccff513..a0371abf98 100644 --- a/packages/engine/src/modules/symbols.ts +++ b/packages/engine/src/modules/symbols.ts @@ -11,6 +11,7 @@ import { designerCabinSymbol, propSymbol, simulatorHostSymbol, + skeletonItemSymbol, } from '@alilc/lowcode-shell'; export default { @@ -26,4 +27,5 @@ export default { designerCabinSymbol, propSymbol, simulatorHostSymbol, + skeletonItemSymbol, }; diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index cb5c8f8aae..b48747598e 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -4,8 +4,9 @@ import { SkeletonEvents, } from '@alilc/lowcode-editor-skeleton'; import { skeletonSymbol } from '../symbols'; -import { IPublicApiSkeleton, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; +import { IPublicApiSkeleton, IPublicModelSkeletonItem, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; import { getLogger } from '@alilc/lowcode-utils'; +import { SkeletonItem } from '../model/skeleton-item'; const innerSkeletonSymbol = Symbol('skeleton'); @@ -46,12 +47,15 @@ export class Skeleton implements IPublicApiSkeleton { * @param extraConfig * @returns */ - add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>) { + add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IPublicModelSkeletonItem | undefined { const configWithName = { ...config, pluginName: this.pluginName, }; - return this[skeletonSymbol].add(configWithName, extraConfig); + const item = this[skeletonSymbol].add(configWithName, extraConfig); + if (item) { + return new SkeletonItem(item); + } } /** @@ -68,6 +72,10 @@ export class Skeleton implements IPublicApiSkeleton { skeleton[normalizeArea(area)].container?.remove(name); } + getAreaItems(areaName: IPublicTypeWidgetConfigArea): IPublicModelSkeletonItem[] { + return this[skeletonSymbol][normalizeArea(areaName)].container.items?.map(d => new SkeletonItem(d)); + } + /** * 显示面板 * @param name @@ -193,7 +201,7 @@ export class Skeleton implements IPublicApiSkeleton { } } -function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea' | 'rightArea' | 'topArea' | 'toolbar' | 'mainArea' | 'bottomArea' | 'leftFixedArea' | 'leftFloatArea' | 'stages' { +function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea' | 'rightArea' | 'topArea' | 'toolbar' | 'mainArea' | 'bottomArea' | 'leftFixedArea' | 'leftFloatArea' | 'stages' | 'subTopArea' { switch (area) { case 'leftArea': case 'left': @@ -220,6 +228,8 @@ function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea return 'leftFloatArea'; case 'stages': return 'stages'; + case 'subTopArea': + return 'subTopArea'; default: throw new Error(`${area} not supported`); } diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index b3fca90b0a..6f79c78bcd 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -11,6 +11,7 @@ import { Clipboard, SettingField, Window, + SkeletonItem, } from './model'; import { Project, @@ -66,4 +67,5 @@ export { SimulatorHost, Config, SettingField, + SkeletonItem, }; diff --git a/packages/shell/src/model/index.ts b/packages/shell/src/model/index.ts index 8b668c947f..a15d50b549 100644 --- a/packages/shell/src/model/index.ts +++ b/packages/shell/src/model/index.ts @@ -20,3 +20,4 @@ export * from './plugin-instance'; export * from './window'; export * from './clipboard'; export * from './editor-view'; +export * from './skeleton-item'; diff --git a/packages/shell/src/model/skeleton-item.ts b/packages/shell/src/model/skeleton-item.ts new file mode 100644 index 0000000000..b91e5a19a0 --- /dev/null +++ b/packages/shell/src/model/skeleton-item.ts @@ -0,0 +1,31 @@ +import { skeletonItemSymbol } from '../symbols'; +import { IPublicModelSkeletonItem } from '@alilc/lowcode-types'; +import { Dock, IWidget, Panel, PanelDock, Stage, Widget } from '@alilc/lowcode-editor-skeleton'; + +export class SkeletonItem implements IPublicModelSkeletonItem { + private [skeletonItemSymbol]: IWidget | Widget | Panel | Stage | Dock | PanelDock; + + constructor(skeletonItem: IWidget | Widget | Panel | Stage | Dock | PanelDock) { + this[skeletonItemSymbol] = skeletonItem; + } + + get name() { + return this[skeletonItemSymbol].name; + } + + disable() { + this[skeletonItemSymbol].disable?.(); + } + + enable() { + this[skeletonItemSymbol].enable?.(); + } + + hide() { + this[skeletonItemSymbol].hide(); + } + + show() { + this[skeletonItemSymbol].show(); + } +} \ No newline at end of file diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index 48d6a96567..b4ec01c7ec 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -35,4 +35,5 @@ export const clipboardSymbol = Symbol('clipboard'); export const configSymbol = Symbol('configSymbol'); export const conditionGroupSymbol = Symbol('conditionGroup'); export const editorViewSymbol = Symbol('editorView'); -export const pluginContextSymbol = Symbol('pluginContext'); \ No newline at end of file +export const pluginContextSymbol = Symbol('pluginContext'); +export const skeletonItemSymbol = Symbol('skeletonItem'); \ No newline at end of file diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts index b22b3586c4..13ba3468b4 100644 --- a/packages/types/src/shell/api/skeleton.ts +++ b/packages/types/src/shell/api/skeleton.ts @@ -1,3 +1,4 @@ +import { IPublicModelSkeletonItem } from '../model'; import { IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type'; export interface IPublicApiSkeleton { @@ -9,7 +10,7 @@ export interface IPublicApiSkeleton { * @param extraConfig * @returns */ - add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): any; + add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IPublicModelSkeletonItem | undefined; /** * 移除一个面板实例 diff --git a/packages/types/src/shell/model/index.ts b/packages/types/src/shell/model/index.ts index e310128ca0..1924f11215 100644 --- a/packages/types/src/shell/model/index.ts +++ b/packages/types/src/shell/model/index.ts @@ -31,3 +31,4 @@ export * from './resource'; export * from './clipboard'; export * from './setting-field'; export * from './editor-view'; +export * from './skeleton-item'; diff --git a/packages/types/src/shell/model/skeleton-item.ts b/packages/types/src/shell/model/skeleton-item.ts new file mode 100644 index 0000000000..ca262ccbf0 --- /dev/null +++ b/packages/types/src/shell/model/skeleton-item.ts @@ -0,0 +1,6 @@ +/** + * @since 1.1.7 + */ +export interface IPublicModelSkeletonItem { + +} \ No newline at end of file diff --git a/packages/workspace/src/context/view-context.ts b/packages/workspace/src/context/view-context.ts index 7dfc663931..ff4c12eeea 100644 --- a/packages/workspace/src/context/view-context.ts +++ b/packages/workspace/src/context/view-context.ts @@ -7,7 +7,9 @@ import { IEditorWindow } from '../window'; import { getWebviewPlugin } from '../inner-plugins/webview'; export interface IViewContext extends IBasicContext { + editorWindow: IEditorWindow; + viewName: string; } export class Context extends BasicContext implements IViewContext { From 8ac68b982b29493f9b367d1e96cf4ef49ff1bdd5 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 11 May 2023 10:08:27 +0800 Subject: [PATCH 135/469] feat: support reset locale config --- packages/plugin-designer/src/index.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/plugin-designer/src/index.tsx b/packages/plugin-designer/src/index.tsx index d40609c48c..54eda13651 100644 --- a/packages/plugin-designer/src/index.tsx +++ b/packages/plugin-designer/src/index.tsx @@ -62,6 +62,11 @@ export default class DesignerPlugin extends PureComponent<PluginProps, DesignerP if (!this._mounted) { return; } + engineConfig.onGot('locale', (locale) => { + this.setState({ + locale, + }); + }); const { components, packages, extraEnvironment, utils } = assets; const state = { componentMetadatas: components || [], From 22d2fddc3e999dc8516f2d5b0e2b57527efbe741 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 11 May 2023 10:11:33 +0800 Subject: [PATCH 136/469] feat: workspace add onChangeActiveWindow event api --- packages/shell/src/api/workspace.ts | 4 ++++ packages/shell/src/model/editor-view.ts | 2 +- packages/workspace/src/window.ts | 7 +++++-- packages/workspace/src/workspace.ts | 18 ++++++++++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index 9676b85222..bfc7b27e1e 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -73,4 +73,8 @@ export class Workspace implements IPublicApiWorkspace { onChangeActiveWindow(fn: () => void): IPublicTypeDisposable { return this[workspaceSymbol].onChangeActiveWindow(fn); } + + onChangeActiveEditorView(fn: () => void): IPublicTypeDisposable { + return this[workspaceSymbol].onChangeActiveEditorView(fn); + } } diff --git a/packages/shell/src/model/editor-view.ts b/packages/shell/src/model/editor-view.ts index 31027a5dee..d70a109b1d 100644 --- a/packages/shell/src/model/editor-view.ts +++ b/packages/shell/src/model/editor-view.ts @@ -10,7 +10,7 @@ export class EditorView { constructor(editorView: IViewContext) { this[editorViewSymbol] = editorView; this[pluginContextSymbol] = this[editorViewSymbol].innerPlugins._getLowCodePluginContext({ - pluginName: '', + pluginName: editorView.editorWindow + editorView.viewName, }); } diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index 92b7078517..41b9c53ea2 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -3,8 +3,7 @@ import { createModuleEventBus, IEventBus, makeObservable, obx } from '@alilc/low import { Context, IViewContext } from './context/view-context'; import { IWorkspace } from './workspace'; import { IResource } from './resource'; -import { IPublicTypeDisposable } from '../../types/es/shell/type/disposable'; -import { IPublicModelWindow } from '@alilc/lowcode-types'; +import { IPublicModelWindow, IPublicTypeDisposable } from '@alilc/lowcode-types'; interface IWindowCOnfig { title: string | undefined; @@ -158,6 +157,10 @@ export class EditorWindow implements IEditorWindow { if (!ignoreEmit) { this.emitter.emit('window.change.view.type', name); + + if (this.id === this.workspace.window.id) { + this.workspace.emitChangeActiveEditorView(); + } } this.editorView.setActivate(true); }; diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 26e1d65519..33daf064a1 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -13,6 +13,8 @@ enum EVENT { CHANGE_ACTIVE_WINDOW = 'change_active_window', WINDOW_RENDER_READY = 'window_render_ready', + + CHANGE_ACTIVE_EDITOR_VIEW = 'change_active_editor_view', } const CHANGE_EVENT = 'resource.list.change'; @@ -42,6 +44,10 @@ export interface IWorkspace extends Omit<IPublicApiWorkspace< initWindow(): void; setActive(active: boolean): void; + + onChangeActiveEditorView(fn: () => void): IPublicTypeDisposable; + + emitChangeActiveEditorView(): void; } export class Workspace implements IWorkspace { @@ -258,12 +264,24 @@ export class Workspace implements IWorkspace { }; } + onChangeActiveEditorView(fn: () => void) { + this.emitter.on(EVENT.CHANGE_ACTIVE_EDITOR_VIEW, fn); + return () => { + this.emitter.removeListener(EVENT.CHANGE_ACTIVE_EDITOR_VIEW, fn); + }; + } + + emitChangeActiveEditorView() { + this.emitter.emit(EVENT.CHANGE_ACTIVE_EDITOR_VIEW); + } + emitChangeWindow() { this.emitter.emit(EVENT.CHANGE_WINDOW); } emitChangeActiveWindow() { this.emitter.emit(EVENT.CHANGE_ACTIVE_WINDOW); + this.emitChangeActiveEditorView(); } onChangeActiveWindow(fn: () => void) { From 48ddc4db59a92f7da8852a261a6274290df2d44a Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 11 May 2023 17:06:25 +0800 Subject: [PATCH 137/469] fix: fix plugin-outline-pane condition tag not update --- .../src/controllers/tree-node.ts | 19 +++++++++++++++++++ .../src/controllers/tree.ts | 3 +++ .../src/views/tree-title.tsx | 9 ++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/plugin-outline-pane/src/controllers/tree-node.ts b/packages/plugin-outline-pane/src/controllers/tree-node.ts index 2a6bc0aca0..af82904ee1 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-node.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-node.ts @@ -35,6 +35,8 @@ enum EVENT_NAMES { titleLabelChanged = 'titleLabelChanged', expandableChanged = 'expandableChanged', + + conditionChanged = 'conditionChanged', } export default class TreeNode { @@ -152,6 +154,10 @@ export default class TreeNode { return this.node.slots.map((node) => this.tree.getTreeNode(node)); } + get condition(): boolean { + return this.node.hasCondition() && !this.node.conditionGroup; + } + get children(): TreeNode[] | null { return this.node.children?.map((node) => this.tree.getTreeNode(node)) || null; } @@ -203,6 +209,15 @@ export default class TreeNode { this.event.off(EVENT_NAMES.titleLabelChanged, fn); }; } + + onConditionChanged(fn: (treeNode: TreeNode) => void): IPublicTypeDisposable { + this.event.on(EVENT_NAMES.conditionChanged, fn); + + return () => { + this.event.off(EVENT_NAMES.conditionChanged, fn); + }; + } + onExpandableChanged(fn: (expandable: boolean) => void): IPublicTypeDisposable { this.event.on(EVENT_NAMES.expandableChanged, fn); return () => { @@ -221,6 +236,10 @@ export default class TreeNode { this.event.emit(EVENT_NAMES.titleLabelChanged, this.title); } + notifyConditionChanged(): void { + this.event.emit(EVENT_NAMES.conditionChanged, this.condition); + } + setHidden(flag: boolean) { if (this.node.conditionGroup) { return; diff --git a/packages/plugin-outline-pane/src/controllers/tree.ts b/packages/plugin-outline-pane/src/controllers/tree.ts index 94cab78797..7b9ad0593f 100644 --- a/packages/plugin-outline-pane/src/controllers/tree.ts +++ b/packages/plugin-outline-pane/src/controllers/tree.ts @@ -35,6 +35,9 @@ export class Tree { if (key === '___title___') { const treeNode = this.getTreeNodeById(node.id); treeNode?.notifyTitleLabelChanged(); + } else if (key === '___condition___') { + const treeNode = this.getTreeNodeById(node.id); + treeNode?.notifyConditionChanged(); } }); } diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 96a3dfa7b2..9232132383 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -27,6 +27,7 @@ export default class TreeTitle extends PureComponent<{ state: { editing: boolean; title: string; + condition?: boolean; } = { editing: false, title: '', @@ -80,12 +81,18 @@ export default class TreeTitle extends PureComponent<{ this.setState({ editing: false, title: treeNode.titleLabel, + condition: treeNode.condition, }); treeNode.onTitleLabelChanged(() => { this.setState({ title: treeNode.titleLabel, }); }); + treeNode.onConditionChanged(() => { + this.setState({ + condition: treeNode.condition, + }); + }); } render() { @@ -188,7 +195,7 @@ export default class TreeTitle extends PureComponent<{ <Tip>{intlNode('Loop')}</Tip> </a> )} - {node.hasCondition() && !node.conditionGroup && ( + {this.state.condition && ( <a className="tree-node-tag cond"> {/* todo: click todo something */} <IconCond /> From 5ada0a40201e15054e36946c47516ef9426a1e40 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 11 May 2023 11:02:46 +0800 Subject: [PATCH 138/469] chore: use @alilc/build-plugin-lce to replace build-plugin-component --- package.json | 2 +- packages/designer/build.json | 2 +- packages/designer/build.test.json | 2 +- packages/designer/package.json | 2 +- packages/editor-core/build.json | 2 +- packages/editor-core/package.json | 2 +- packages/editor-skeleton/build.json | 4 ++-- packages/editor-skeleton/build.test.json | 2 +- packages/editor-skeleton/package.json | 2 +- packages/engine/build.json | 2 +- packages/engine/build.test.json | 2 +- packages/engine/package.json | 2 +- packages/plugin-designer/build.json | 2 +- packages/plugin-designer/package.json | 2 +- packages/plugin-outline-pane/build.json | 2 +- packages/plugin-outline-pane/package.json | 2 +- packages/rax-simulator-renderer/build.json | 2 +- packages/rax-simulator-renderer/package.json | 2 +- packages/react-renderer/build.json | 2 +- packages/react-renderer/build.test.json | 2 +- packages/react-renderer/package.json | 2 +- packages/react-simulator-renderer/build.json | 2 +- packages/react-simulator-renderer/build.test.json | 2 +- packages/react-simulator-renderer/package.json | 2 +- packages/renderer-core/build.json | 2 +- packages/renderer-core/build.test.json | 2 +- packages/renderer-core/package.json | 2 +- packages/shell/build.json | 2 +- packages/shell/build.test.json | 2 +- packages/shell/package.json | 4 +--- packages/types/build.json | 2 +- packages/types/package.json | 2 +- packages/utils/build.json | 2 +- packages/utils/build.test.json | 2 +- packages/utils/package.json | 2 +- packages/workspace/build.json | 2 +- packages/workspace/build.test.json | 2 +- packages/workspace/package.json | 2 +- 38 files changed, 39 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index 02585e563e..6a650c49b6 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "yarn": "^1.22.17", "rimraf": "^3.0.2", "@types/react-router": "5.1.18", - "build-plugin-component": "^1.12.0", + "@alilc/build-plugin-lce": "^0.0.3", "babel-jest": "^26.5.2", "@alilc/lowcode-test-mate": "^1.0.1" }, diff --git a/packages/designer/build.json b/packages/designer/build.json index bd5cf18dde..3e92600554 100644 --- a/packages/designer/build.json +++ b/packages/designer/build.json @@ -1,5 +1,5 @@ { "plugins": [ - "build-plugin-component" + "@alilc/build-plugin-lce" ] } diff --git a/packages/designer/build.test.json b/packages/designer/build.test.json index 45f0dbdfd3..10d18109b8 100644 --- a/packages/designer/build.test.json +++ b/packages/designer/build.test.json @@ -1,6 +1,6 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", "@alilc/lowcode-test-mate/plugin/index.ts" ], "babelPlugins": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 61190a3be7..e3b5ca968c 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -9,7 +9,7 @@ "es" ], "scripts": { - "build": "build-scripts build --skip-demo", + "build": "build-scripts build", "test": "build-scripts test --config build.test.json", "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, diff --git a/packages/editor-core/build.json b/packages/editor-core/build.json index 40b17de79a..c1ebc2c867 100644 --- a/packages/editor-core/build.json +++ b/packages/editor-core/build.json @@ -1,6 +1,6 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", "build-plugin-fusion", "./build.plugin.js" ] diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index c4272a0ab2..2701199d57 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -10,7 +10,7 @@ "es" ], "scripts": { - "build": "build-scripts build --skip-demo" + "build": "build-scripts build" }, "dependencies": { "@alifd/next": "^1.19.16", diff --git a/packages/editor-skeleton/build.json b/packages/editor-skeleton/build.json index 77627cdf98..d0aec10385 100644 --- a/packages/editor-skeleton/build.json +++ b/packages/editor-skeleton/build.json @@ -1,9 +1,9 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", "build-plugin-fusion", ["build-plugin-moment-locales", { "locales": ["zh-cn"] }] ] -} \ No newline at end of file +} diff --git a/packages/editor-skeleton/build.test.json b/packages/editor-skeleton/build.test.json index 45f0dbdfd3..10d18109b8 100644 --- a/packages/editor-skeleton/build.test.json +++ b/packages/editor-skeleton/build.test.json @@ -1,6 +1,6 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", "@alilc/lowcode-test-mate/plugin/index.ts" ], "babelPlugins": [ diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 7e64d81665..ff9c9a782b 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -11,7 +11,7 @@ ], "scripts": { "test": "build-scripts test --config build.test.json", - "build": "build-scripts build --skip-demo" + "build": "build-scripts build" }, "keywords": [ "lowcode", diff --git a/packages/engine/build.json b/packages/engine/build.json index e8c3e583de..405f2c005c 100644 --- a/packages/engine/build.json +++ b/packages/engine/build.json @@ -1,6 +1,6 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", [ "build-plugin-fusion", { diff --git a/packages/engine/build.test.json b/packages/engine/build.test.json index a43d8eff9f..9596d43e79 100644 --- a/packages/engine/build.test.json +++ b/packages/engine/build.test.json @@ -1,7 +1,7 @@ { "plugins": [ [ - "build-plugin-component", + "@alilc/build-plugin-lce", { "filename": "editor-preset-vision", "library": "LowcodeEditor", diff --git a/packages/engine/package.json b/packages/engine/package.json index 99b185db00..ca63f42f4a 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -12,7 +12,7 @@ "scripts": { "start": "build-scripts start", "version:update": "node ./scripts/version.js", - "build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --skip-demo", + "build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build", "build:umd": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --config build.umd.json", "test": "build-scripts test --config build.test.json --jest-passWithNoTests" }, diff --git a/packages/plugin-designer/build.json b/packages/plugin-designer/build.json index bd5cf18dde..3e92600554 100644 --- a/packages/plugin-designer/build.json +++ b/packages/plugin-designer/build.json @@ -1,5 +1,5 @@ { "plugins": [ - "build-plugin-component" + "@alilc/build-plugin-lce" ] } diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 0f64b70f19..5ffc7e96f3 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -10,7 +10,7 @@ "module": "es/index.js", "stylePath": "style.js", "scripts": { - "build": "build-scripts build --skip-demo" + "build": "build-scripts build" }, "keywords": [ "lowcode", diff --git a/packages/plugin-outline-pane/build.json b/packages/plugin-outline-pane/build.json index e791d5b6b3..d0aec10385 100644 --- a/packages/plugin-outline-pane/build.json +++ b/packages/plugin-outline-pane/build.json @@ -1,6 +1,6 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", "build-plugin-fusion", ["build-plugin-moment-locales", { "locales": ["zh-cn"] diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 8a1472ce20..cbba2bc456 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -9,7 +9,7 @@ "main": "lib/index.js", "module": "es/index.js", "scripts": { - "build": "build-scripts build --skip-demo" + "build": "build-scripts build" }, "dependencies": { "@alifd/next": "^1.19.16", diff --git a/packages/rax-simulator-renderer/build.json b/packages/rax-simulator-renderer/build.json index b95a17aafe..e7ae1dcf7a 100644 --- a/packages/rax-simulator-renderer/build.json +++ b/packages/rax-simulator-renderer/build.json @@ -1,3 +1,3 @@ { - "plugins": ["build-plugin-component", "./build.plugin.js"] + "plugins": ["@alilc/build-plugin-lce", "./build.plugin.js"] } diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 76954ff362..4f8bc7ad18 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -9,7 +9,7 @@ "dist" ], "scripts": { - "build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --skip-demo", + "build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build", "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { diff --git a/packages/react-renderer/build.json b/packages/react-renderer/build.json index e791d5b6b3..d0aec10385 100644 --- a/packages/react-renderer/build.json +++ b/packages/react-renderer/build.json @@ -1,6 +1,6 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", "build-plugin-fusion", ["build-plugin-moment-locales", { "locales": ["zh-cn"] diff --git a/packages/react-renderer/build.test.json b/packages/react-renderer/build.test.json index dcdc891e93..9cc30d7463 100644 --- a/packages/react-renderer/build.test.json +++ b/packages/react-renderer/build.test.json @@ -1,6 +1,6 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", "@alilc/lowcode-test-mate/plugin/index.ts" ] } diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 862f69d015..744c1cac09 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -12,7 +12,7 @@ "scripts": { "test": "build-scripts test --config build.test.json", "start": "build-scripts start", - "build": "build-scripts build --skip-demo", + "build": "build-scripts build", "build:umd": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --config build.umd.json" }, "keywords": [ diff --git a/packages/react-simulator-renderer/build.json b/packages/react-simulator-renderer/build.json index b95a17aafe..e7ae1dcf7a 100644 --- a/packages/react-simulator-renderer/build.json +++ b/packages/react-simulator-renderer/build.json @@ -1,3 +1,3 @@ { - "plugins": ["build-plugin-component", "./build.plugin.js"] + "plugins": ["@alilc/build-plugin-lce", "./build.plugin.js"] } diff --git a/packages/react-simulator-renderer/build.test.json b/packages/react-simulator-renderer/build.test.json index dcdc891e93..9cc30d7463 100644 --- a/packages/react-simulator-renderer/build.test.json +++ b/packages/react-simulator-renderer/build.test.json @@ -1,6 +1,6 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", "@alilc/lowcode-test-mate/plugin/index.ts" ] } diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index fce8d866eb..ad7673b620 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -12,7 +12,7 @@ ], "scripts": { "test": "build-scripts test --config build.test.json", - "build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --skip-demo", + "build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build", "build:umd": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --config build.umd.json", "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, diff --git a/packages/renderer-core/build.json b/packages/renderer-core/build.json index a8e42f1540..9140815c5e 100644 --- a/packages/renderer-core/build.json +++ b/packages/renderer-core/build.json @@ -1,7 +1,7 @@ { "plugins": [ [ - "build-plugin-component", + "@alilc/build-plugin-lce", { "babelPlugins": ["@babel/plugin-transform-typescript"] } diff --git a/packages/renderer-core/build.test.json b/packages/renderer-core/build.test.json index dcdc891e93..9cc30d7463 100644 --- a/packages/renderer-core/build.test.json +++ b/packages/renderer-core/build.test.json @@ -1,6 +1,6 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", "@alilc/lowcode-test-mate/plugin/index.ts" ] } diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 84a63aa9a2..1a6fd6090a 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -10,7 +10,7 @@ "es" ], "scripts": { - "build": "build-scripts build --skip-demo", + "build": "build-scripts build", "test": "build-scripts test --config build.test.json", "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, diff --git a/packages/shell/build.json b/packages/shell/build.json index bd5cf18dde..3e92600554 100644 --- a/packages/shell/build.json +++ b/packages/shell/build.json @@ -1,5 +1,5 @@ { "plugins": [ - "build-plugin-component" + "@alilc/build-plugin-lce" ] } diff --git a/packages/shell/build.test.json b/packages/shell/build.test.json index dcdc891e93..9cc30d7463 100644 --- a/packages/shell/build.test.json +++ b/packages/shell/build.test.json @@ -1,6 +1,6 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", "@alilc/lowcode-test-mate/plugin/index.ts" ] } diff --git a/packages/shell/package.json b/packages/shell/package.json index 9b9cc04168..521befb2eb 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -9,9 +9,7 @@ "es" ], "scripts": { - "build": "build-scripts build --skip-demo", - "test": "build-scripts test --config build.test.json", - "test:cov": "build-scripts test --config build.test.json --jest-coverage" + "build": "build-scripts build" }, "license": "MIT", "dependencies": { diff --git a/packages/types/build.json b/packages/types/build.json index bd5cf18dde..3e92600554 100644 --- a/packages/types/build.json +++ b/packages/types/build.json @@ -1,5 +1,5 @@ { "plugins": [ - "build-plugin-component" + "@alilc/build-plugin-lce" ] } diff --git a/packages/types/package.json b/packages/types/package.json index 6d90338869..b92d2efb66 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -9,7 +9,7 @@ "main": "lib/index.js", "module": "es/index.js", "scripts": { - "build": "build-scripts build --skip-demo" + "build": "build-scripts build" }, "dependencies": { "@alilc/lowcode-datasource-types": "^1.0.0", diff --git a/packages/utils/build.json b/packages/utils/build.json index bd5cf18dde..3e92600554 100644 --- a/packages/utils/build.json +++ b/packages/utils/build.json @@ -1,5 +1,5 @@ { "plugins": [ - "build-plugin-component" + "@alilc/build-plugin-lce" ] } diff --git a/packages/utils/build.test.json b/packages/utils/build.test.json index dcdc891e93..9cc30d7463 100644 --- a/packages/utils/build.test.json +++ b/packages/utils/build.test.json @@ -1,6 +1,6 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", "@alilc/lowcode-test-mate/plugin/index.ts" ] } diff --git a/packages/utils/package.json b/packages/utils/package.json index 8043a9e109..d52f6deef2 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -10,7 +10,7 @@ "module": "es/index.js", "scripts": { "test": "build-scripts test --config build.test.json", - "build": "build-scripts build --skip-demo" + "build": "build-scripts build" }, "dependencies": { "@alifd/next": "^1.19.16", diff --git a/packages/workspace/build.json b/packages/workspace/build.json index bd5cf18dde..3e92600554 100644 --- a/packages/workspace/build.json +++ b/packages/workspace/build.json @@ -1,5 +1,5 @@ { "plugins": [ - "build-plugin-component" + "@alilc/build-plugin-lce" ] } diff --git a/packages/workspace/build.test.json b/packages/workspace/build.test.json index dcdc891e93..9cc30d7463 100644 --- a/packages/workspace/build.test.json +++ b/packages/workspace/build.test.json @@ -1,6 +1,6 @@ { "plugins": [ - "build-plugin-component", + "@alilc/build-plugin-lce", "@alilc/lowcode-test-mate/plugin/index.ts" ] } diff --git a/packages/workspace/package.json b/packages/workspace/package.json index c1b1e25a57..52a45567d4 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -9,7 +9,7 @@ "es" ], "scripts": { - "build": "build-scripts build --skip-demo", + "build": "build-scripts build", "test": "build-scripts test --config build.test.json", "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, From f5438ff1abe6067ddb2e267fa8b905dca589138e Mon Sep 17 00:00:00 2001 From: Minglong Li <790669171@qq.com> Date: Fri, 12 May 2023 21:50:44 +0800 Subject: [PATCH 139/469] fix: return first if input schema is a react dom --- packages/renderer-core/src/renderer/base.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 56f58599b0..99a9a40cfa 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -493,6 +493,11 @@ export default function baseRendererFactory(): IBaseRenderComponent { return schema.map((item, idy) => this.__createVirtualDom(item, scope, parentInfo, (item as IPublicTypeNodeSchema)?.__ctx?.lceKey ? '' : String(idy))); } + // @ts-expect-error 如果直接转换好了,可以返回 + if (schema.$$typeof) { + return schema; + } + const _children = getSchemaChildren(schema); if (!schema.componentName) { logger.error('The componentName in the schema is invalid, please check the schema: ', schema); @@ -510,11 +515,6 @@ export default function baseRendererFactory(): IBaseRenderComponent { schema.children = [text]; } - // @ts-expect-error 如果直接转换好了,可以返回 - if (schema.$$typeof) { - return schema; - } - if (!isSchema(schema)) { return null; } From ee80fb12b864f2ddd657fe1503e57f755697d07a Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 16 May 2023 18:05:16 +0800 Subject: [PATCH 140/469] feat: workspace add some features --- packages/editor-core/src/config.ts | 5 +++++ packages/shell/src/api/workspace.ts | 4 ++-- packages/types/src/shell/api/workspace.ts | 8 +++++++- packages/types/src/shell/model/plugin-context.ts | 4 +++- packages/workspace/src/workspace.ts | 6 +++--- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/editor-core/src/config.ts b/packages/editor-core/src/config.ts index 4f0f708e7d..c325c2bb85 100644 --- a/packages/editor-core/src/config.ts +++ b/packages/editor-core/src/config.ts @@ -150,6 +150,11 @@ const VALID_ENGINE_OPTIONS = { description: '应用级设计模式下,自动打开第一个窗口', default: true, }, + enableWorkspaceMode: { + type: 'boolean', + description: '是否开启应用级设计模式', + default: false, + }, }; const getStrictModeValue = (engineOptions: IPublicTypeEngineOptions, defaultValue: boolean): boolean => { diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index bfc7b27e1e..8192ac67d4 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -42,8 +42,8 @@ export class Workspace implements IPublicApiWorkspace { this[workspaceSymbol].registerResourceType(resourceTypeModel); } - openEditorWindow(resourceName: string, title: string, extra: object, viewName?: string, sleep?: boolean): void { - this[workspaceSymbol].openEditorWindow(resourceName, title, extra, viewName, sleep); + async openEditorWindow(resourceName: string, title: string, extra: object, viewName?: string, sleep?: boolean): Promise<void> { + await this[workspaceSymbol].openEditorWindow(resourceName, title, extra, viewName, sleep); } openEditorWindowById(id: string) { diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index 8904a8231c..8ae2434bc5 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -30,7 +30,7 @@ export interface IPublicApiWorkspace< registerResourceType(resourceTypeModel: IPublicTypeResourceType): void; /** 打开视图窗口 */ - openEditorWindow(resourceName: string, title: string, extra: Object, viewName?: string, sleep?: boolean): void; + openEditorWindow(resourceName: string, title: string, extra: Object, viewName?: string, sleep?: boolean): Promise<void>; /** 通过视图 id 打开窗口 */ openEditorWindowById(id: string): void; @@ -47,6 +47,12 @@ export interface IPublicApiWorkspace< /** active 窗口变更事件 */ onChangeActiveWindow(fn: () => void): IPublicTypeDisposable; + /** + * active 视图变更事件 + * @since v1.1.7 + */ + onChangeActiveEditorView(fn: () => void): IPublicTypeDisposable; + /** * window 下的所有视图 renderer ready 事件 * @since v1.1.7 diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts index e670e54ea3..ea6fb71023 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -13,7 +13,7 @@ import { IPublicApiWorkspace, } from '../api'; import { IPublicEnumPluginRegisterLevel } from '../enum'; -import { IPublicModelEngineConfig } from './'; +import { IPublicModelEngineConfig, IPublicModelEditorView } from './'; export interface IPublicModelPluginContext { @@ -107,6 +107,8 @@ export interface IPublicModelPluginContext { * @since v1.1.7 */ get registerLevel(): IPublicEnumPluginRegisterLevel; + + get editorWindow(): IPublicModelEditorView; } /** diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 33daf064a1..ba3d91c41d 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -128,7 +128,7 @@ export class Workspace implements IWorkspace { title: resource.title, }); this.editorWindowMap.set(this.window.id, this.window); - this.windows.push(this.window); + this.windows = [...this.windows, this.window]; this.emitChangeWindow(); this.emitChangeActiveWindow(); } @@ -214,7 +214,7 @@ export class Workspace implements IWorkspace { } } - openEditorWindow(name: string, title: string, options: Object, viewType?: string, sleep?: boolean) { + async openEditorWindow(name: string, title: string, options: Object, viewType?: string, sleep?: boolean) { if (this.window && !this.window?.initReady && !sleep) { this.windowQueue.push({ name, title, options, viewType, @@ -230,7 +230,7 @@ export class Workspace implements IWorkspace { if (filterWindows && filterWindows.length) { this.window = filterWindows[0]; if (!sleep && this.window.sleep) { - this.window.init(); + await this.window.init(); } else { this.checkWindowQueue(); } From 2b3d96cedada3f3c3f91f16129aadee466052b9b Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 17 May 2023 18:57:09 +0800 Subject: [PATCH 141/469] feat: canvas.activeTracker add targer prop --- .../designer/src/designer/active-tracker.ts | 6 ++-- .../src/controllers/tree-master.ts | 36 ++++++++++--------- packages/shell/src/model/active-tracker.ts | 10 ++++++ .../types/src/shell/model/active-tracker.ts | 6 ++++ packages/workspace/src/resource.ts | 5 ++- 5 files changed, 42 insertions(+), 21 deletions(-) diff --git a/packages/designer/src/designer/active-tracker.ts b/packages/designer/src/designer/active-tracker.ts index 27a7090f8e..74d865673f 100644 --- a/packages/designer/src/designer/active-tracker.ts +++ b/packages/designer/src/designer/active-tracker.ts @@ -7,6 +7,8 @@ import { import { isNode } from '@alilc/lowcode-utils'; export interface IActiveTracker extends Omit< IPublicModelActiveTracker, 'track' | 'onChange' > { + _target: ActiveTarget | INode; + track(originalTarget: ActiveTarget | INode): void; onChange(fn: (target: ActiveTarget) => void): () => void; @@ -17,10 +19,10 @@ export interface ActiveTarget extends Omit< IPublicTypeActiveTarget, 'node' > { } export class ActiveTracker implements IActiveTracker { - private emitter: IEventBus = createModuleEventBus('ActiveTracker'); - @obx.ref private _target?: ActiveTarget | INode; + private emitter: IEventBus = createModuleEventBus('ActiveTracker'); + track(originalTarget: ActiveTarget | INode) { let target = originalTarget; if (isNode(originalTarget)) { diff --git a/packages/plugin-outline-pane/src/controllers/tree-master.ts b/packages/plugin-outline-pane/src/controllers/tree-master.ts index cb62980482..40162d808f 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-master.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-master.ts @@ -90,28 +90,29 @@ export class TreeMaster { private initEvent() { let startTime: any; const { event, project, canvas } = this.pluginContext; + const setExpandByActiveTracker = (target: IPublicTypeActiveTarget) => { + const { node, detail } = target; + const tree = this.currentTree; + if (!tree/* || node.document !== tree.document */) { + return; + } + const treeNode = tree.getTreeNode(node); + if (detail && isLocationChildrenDetail(detail)) { + treeNode.expand(true); + } else { + treeNode.expandParents(); + } + this.boards.forEach((board) => { + board.scrollToNode(treeNode, detail); + }); + }; this.disposeEvents = [ canvas.dragon?.onDragstart(() => { startTime = Date.now() / 1000; // needs? this.toVision(); }), - canvas.activeTracker?.onChange((target: IPublicTypeActiveTarget) => { - const { node, detail } = target; - const tree = this.currentTree; - if (!tree/* || node.document !== tree.document */) { - return; - } - const treeNode = tree.getTreeNode(node); - if (detail && isLocationChildrenDetail(detail)) { - treeNode.expand(true); - } else { - treeNode.expandParents(); - } - this.boards.forEach((board) => { - board.scrollToNode(treeNode, detail); - }); - }), + canvas.activeTracker?.onChange(setExpandByActiveTracker), canvas.dragon?.onDragend(() => { const endTime: any = Date.now() / 1000; const nodes = project.currentDocument?.selection?.getNodes(); @@ -135,6 +136,9 @@ export class TreeMaster { this.treeMap.delete(id); }), ]; + if (canvas.activeTracker?.target) { + setExpandByActiveTracker(canvas.activeTracker?.target); + } } private toVision() { diff --git a/packages/shell/src/model/active-tracker.ts b/packages/shell/src/model/active-tracker.ts index 41871aacba..e6170b7a68 100644 --- a/packages/shell/src/model/active-tracker.ts +++ b/packages/shell/src/model/active-tracker.ts @@ -12,6 +12,16 @@ export class ActiveTracker implements IPublicModelActiveTracker { this[activeTrackerSymbol] = innerTracker; } + get target() { + const { node: innerNode, detail, instance } = this[activeTrackerSymbol]._target; + const publicNode = ShellNode.create(innerNode); + return { + node: publicNode!, + detail, + instance, + }; + } + onChange(fn: (target: IPublicTypeActiveTarget) => void): () => void { if (!fn) { return () => {}; diff --git a/packages/types/src/shell/model/active-tracker.ts b/packages/types/src/shell/model/active-tracker.ts index b0ceec11fb..2538a26017 100644 --- a/packages/types/src/shell/model/active-tracker.ts +++ b/packages/types/src/shell/model/active-tracker.ts @@ -2,6 +2,12 @@ import { IPublicTypeActiveTarget } from '../type'; import { IPublicModelNode } from './node'; export interface IPublicModelActiveTracker { + + /** + * @since 1.1.7 + */ + target: IPublicTypeActiveTarget; + onChange(fn: (target: IPublicTypeActiveTarget) => void): () => void; track(node: IPublicModelNode): void; diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index 8c59aed1ef..4b695d036d 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -70,9 +70,7 @@ export class Resource implements IResource { return this.context.innerSkeleton; } - get children(): IResource[] { - return this.resourceData?.children?.map(d => new Resource(d, this.workspace.getResourceType(d.resourceName || this.resourceType.name), this.workspace)) || []; - } + children: IResource[]; get config() { return this.resourceData.config; @@ -92,6 +90,7 @@ export class Resource implements IResource { if (!resourceType) { logger.error(`resourceType[${resourceType}] is unValid.`); } + this.children = this.resourceData?.children?.map(d => new Resource(d, this.workspace.getResourceType(d.resourceName || this.resourceType.name), this.workspace)) || []; } async init() { From 059ffe0eaac7c82ca3a97789a25a0eed0f57a2c3 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 17 May 2023 17:22:10 +0800 Subject: [PATCH 142/469] feat: improve the workspace sleep scene --- packages/workspace/src/window.ts | 6 ++---- packages/workspace/src/workspace.ts | 12 ++++++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index 41b9c53ea2..0e37b4986e 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -51,9 +51,6 @@ export class EditorWindow implements IEditorWindow { this.title = config.title; this.icon = resource.icon; this.sleep = config.sleep; - if (!config.sleep) { - this.init(); - } } async importSchema(schema: any) { @@ -155,6 +152,8 @@ export class EditorWindow implements IEditorWindow { return; } + this.editorView.setActivate(true); + if (!ignoreEmit) { this.emitter.emit('window.change.view.type', name); @@ -162,7 +161,6 @@ export class EditorWindow implements IEditorWindow { this.workspace.emitChangeActiveEditorView(); } } - this.editorView.setActivate(true); }; get project() { diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index ba3d91c41d..46c8c4a0e1 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -115,7 +115,7 @@ export class Workspace implements IWorkspace { } } - initWindow() { + async initWindow() { if (!this.defaultResourceType || this.enableAutoOpenFirstWindow === false) { return; } @@ -127,6 +127,7 @@ export class Workspace implements IWorkspace { this.window = new EditorWindow(resource, this, { title: resource.title, }); + await this.window.init(); this.editorWindowMap.set(this.window.id, this.window); this.windows = [...this.windows, this.window]; this.emitChangeWindow(); @@ -196,6 +197,9 @@ export class Workspace implements IWorkspace { this.windows.splice(index, 1); if (this.window === window) { this.window = this.windows[index] || this.windows[index + 1] || this.windows[index - 1]; + if (this.window.sleep) { + this.window.init(); + } this.emitChangeActiveWindow(); } this.emitChangeWindow(); @@ -206,10 +210,13 @@ export class Workspace implements IWorkspace { this.remove(index); } - openEditorWindowById(id: string) { + async openEditorWindowById(id: string) { const window = this.editorWindowMap.get(id); if (window) { this.window = window; + if (window.sleep) { + await window.init(); + } this.emitChangeActiveWindow(); } } @@ -252,6 +259,7 @@ export class Workspace implements IWorkspace { this.editorWindowMap.set(window.id, window); if (!sleep) { this.window = window; + await this.window.init(); } this.emitChangeWindow(); this.emitChangeActiveWindow(); From 8b44ed44295aa66105c9799fcd41f360c411e324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E6=9E=97?= <chenglin@dian.so> Date: Wed, 17 May 2023 19:57:15 +0800 Subject: [PATCH 143/469] fix: fix outlinePane treeView render only once --- .../plugin-outline-pane/src/views/pane.tsx | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/plugin-outline-pane/src/views/pane.tsx b/packages/plugin-outline-pane/src/views/pane.tsx index 36a2bfa0b7..4b807ca180 100644 --- a/packages/plugin-outline-pane/src/views/pane.tsx +++ b/packages/plugin-outline-pane/src/views/pane.tsx @@ -17,7 +17,9 @@ export class Pane extends PureComponent<{ }> { private controller; - private dispose: IPublicTypeDisposable; + private simulatorRendererReadyDispose: IPublicTypeDisposable; + private changeDocumentDispose: IPublicTypeDisposable; + private removeDocumentDispose: IPublicTypeDisposable; constructor(props: any) { super(props); @@ -26,16 +28,22 @@ export class Pane extends PureComponent<{ this.state = { tree: treeMaster.currentTree, }; - this.dispose = this.props.treeMaster.pluginContext?.project?.onSimulatorRendererReady(() => { - this.setState({ - tree: this.props.treeMaster.currentTree, - }); - }); + this.simulatorRendererReadyDispose = this.props.treeMaster.pluginContext?.project?.onSimulatorRendererReady(this.changeTree); + this.changeDocumentDispose = this.props.treeMaster.pluginContext?.project?.onChangeDocument(this.changeTree); + this.removeDocumentDispose = this.props.treeMaster.pluginContext?.project?.onRemoveDocument(this.changeTree); } + changeTree = () => { + this.setState({ + tree: this.props.treeMaster.currentTree, + }); + }; + componentWillUnmount() { this.controller.purge(); - this.dispose && this.dispose(); + this.simulatorRendererReadyDispose?.(); + this.changeDocumentDispose?.(); + this.removeDocumentDispose?.(); } render() { From be4b16440ec7a6597c72112d75df389e2bcd18b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Thu, 18 May 2023 17:25:08 +0800 Subject: [PATCH 144/469] fix: skip internal dep when type is pages, closes #2049 --- modules/code-generator/src/parser/SchemaParser.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/code-generator/src/parser/SchemaParser.ts b/modules/code-generator/src/parser/SchemaParser.ts index c6263877c1..b4f7424ce5 100644 --- a/modules/code-generator/src/parser/SchemaParser.ts +++ b/modules/code-generator/src/parser/SchemaParser.ts @@ -106,6 +106,11 @@ function processChildren(schema: IPublicTypeNodeSchema): void { } } +function getInternalDep(internalDeps: Record<string, IInternalDependency>, depName: string) { + const dep = internalDeps[depName]; + return (dep && dep.type !== InternalDependencyType.PAGE) ? dep : null; +} + export class SchemaParser implements ISchemaParser { validate(schema: IPublicTypeProjectSchema): boolean { if (SUPPORT_SCHEMA_VERSION_LIST.indexOf(schema.version) < 0) { @@ -221,12 +226,11 @@ export class SchemaParser implements ISchemaParser { } }); - // 分析容器内部组件依赖 containers.forEach((container) => { const depNames = this.getComponentNames(container); // eslint-disable-next-line no-param-reassign container.deps = uniqueArray<string>(depNames, (i: string) => i) - .map((depName) => internalDeps[depName] || compDeps[depName]) + .map((depName) => getInternalDep(internalDeps, depName) || compDeps[depName]) .filter(Boolean); // container.deps = Object.keys(compDeps).map((depName) => compDeps[depName]); }); From fa5168b4a824feee0ee9522990ba65e0583d3a0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Fri, 19 May 2023 11:23:05 +0800 Subject: [PATCH 145/469] fix: add Fusion-UI style for code generation --- .../code-generator/src/plugins/common/styleImport.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/modules/code-generator/src/plugins/common/styleImport.ts b/modules/code-generator/src/plugins/common/styleImport.ts index c340900eab..23e1293025 100644 --- a/modules/code-generator/src/plugins/common/styleImport.ts +++ b/modules/code-generator/src/plugins/common/styleImport.ts @@ -21,6 +21,7 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { if (ir && ir.deps && ir.deps.length > 0) { let lowcodeMaterialsStyleAdded = false; + let fusionUIStyleAdded = false; let nextStyleAddedMap: Record<string, boolean> = {}; ir.deps.forEach((dep: any) => { if (dep.package === '@alifd/next' && !nextStyleAddedMap[dep.exportName]) { @@ -41,6 +42,15 @@ const pluginFactory: BuilderComponentPluginFactory<unknown> = () => { linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], }); lowcodeMaterialsStyleAdded = true; + } else if (dep.package === '@alifd/fusion-ui' && !fusionUIStyleAdded) { + chunks.push({ + type: ChunkType.STRING, + fileType: FileType.JSX, + name: COMMON_CHUNK_NAME.InternalDepsImport, + content: 'import \'@alifd/fusion-ui/lib/style\';', + linkAfter: [COMMON_CHUNK_NAME.ExternalDepsImport], + }); + fusionUIStyleAdded = true; } }); } From ee8717bb97b4ebd815197355d278909e77fd54a7 Mon Sep 17 00:00:00 2001 From: LiGuangNian <792841450@qq.com> Date: Fri, 19 May 2023 16:09:56 +0800 Subject: [PATCH 146/469] Update node-children.md --- docs/docs/api/model/node-children.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/api/model/node-children.md b/docs/docs/api/model/node-children.md index 219e6bbc18..5507fcbfb8 100644 --- a/docs/docs/api/model/node-children.md +++ b/docs/docs/api/model/node-children.md @@ -62,11 +62,11 @@ delete(node: IPublicModelNode): boolean; ```typescript /** - * 删除指定节点 - * delete the node + * 插入一个节点 + * insert the node * @param node */ -delete(node: IPublicModelNode): boolean; +insert(node: IPublicModelNode): boolean; ``` 相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) From 62288a139f6fc550e91c9ffbf0cc7fc1c6e64188 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 18 May 2023 10:43:58 +0800 Subject: [PATCH 147/469] feat: canvas.activeTracker.target returns add null --- packages/shell/src/model/active-tracker.ts | 8 +++++++- packages/types/src/shell/model/active-tracker.ts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/shell/src/model/active-tracker.ts b/packages/shell/src/model/active-tracker.ts index e6170b7a68..32d4c04eb9 100644 --- a/packages/shell/src/model/active-tracker.ts +++ b/packages/shell/src/model/active-tracker.ts @@ -13,7 +13,13 @@ export class ActiveTracker implements IPublicModelActiveTracker { } get target() { - const { node: innerNode, detail, instance } = this[activeTrackerSymbol]._target; + const _target = this[activeTrackerSymbol]._target; + + if (!_target) { + return null; + } + + const { node: innerNode, detail, instance } = _target; const publicNode = ShellNode.create(innerNode); return { node: publicNode!, diff --git a/packages/types/src/shell/model/active-tracker.ts b/packages/types/src/shell/model/active-tracker.ts index 2538a26017..ac116a9473 100644 --- a/packages/types/src/shell/model/active-tracker.ts +++ b/packages/types/src/shell/model/active-tracker.ts @@ -6,7 +6,7 @@ export interface IPublicModelActiveTracker { /** * @since 1.1.7 */ - target: IPublicTypeActiveTarget; + target: IPublicTypeActiveTarget | null; onChange(fn: (target: IPublicTypeActiveTarget) => void): () => void; From b984ef72d28f98a6e7a72ea3d051dc254f402749 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 19 May 2023 17:19:31 +0800 Subject: [PATCH 148/469] feat: workspace window add onSave api --- docs/docs/api/model/window.md | 15 +++++++++++++++ packages/plugin-outline-pane/src/index.tsx | 10 ++++++---- packages/shell/src/model/window.ts | 4 ++++ packages/types/src/shell/model/plugin-context.ts | 4 ++-- packages/types/src/shell/model/window.ts | 6 ++++++ packages/workspace/src/window.ts | 13 ++++++++++++- 6 files changed, 45 insertions(+), 7 deletions(-) diff --git a/docs/docs/api/model/window.md b/docs/docs/api/model/window.md index 3cc8b5d5e7..9db39996fa 100644 --- a/docs/docs/api/model/window.md +++ b/docs/docs/api/model/window.md @@ -45,6 +45,8 @@ sidebar_position: 12 关联模型 [IPublicModelEditorView](./editor-view) +**@since v1.1.7** + ### editorViews 窗口所有视图 @@ -53,6 +55,7 @@ sidebar_position: 12 关联模型 [IPublicModelEditorView](./editor-view) +**@since v1.1.7** ## 方法 @@ -90,3 +93,15 @@ 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** diff --git a/packages/plugin-outline-pane/src/index.tsx b/packages/plugin-outline-pane/src/index.tsx index 95b219a4b1..180b424ea5 100644 --- a/packages/plugin-outline-pane/src/index.tsx +++ b/packages/plugin-outline-pane/src/index.tsx @@ -4,7 +4,7 @@ import { IPublicModelPluginContext, IPublicModelDocumentModel } from '@alilc/low import { MasterPaneName, BackupPaneName } from './helper/consts'; import { TreeMaster } from './controllers/tree-master'; import { PaneController } from './controllers/pane-controller'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; export function OutlinePaneContext(props: { treeMaster?: TreeMaster; @@ -19,9 +19,11 @@ export function OutlinePaneContext(props: { }) { const treeMaster = props.treeMaster || new TreeMaster(props.pluginContext, props.options); const [masterPaneController, setMasterPaneController] = useState(new PaneController(props.paneName || MasterPaneName, treeMaster)); - treeMaster.onPluginContextChange(() => { - setMasterPaneController(new PaneController(props.paneName || MasterPaneName, treeMaster)); - }); + useEffect(() => { + return treeMaster.onPluginContextChange(() => { + setMasterPaneController(new PaneController(props.paneName || MasterPaneName, treeMaster)); + }); + }, []); return ( <Pane diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index f539e95678..3e6bd64507 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -43,6 +43,10 @@ export class Window implements IPublicModelWindow { return await this[windowSymbol].save(); } + onSave(fn: () => void) { + return this[windowSymbol].onSave(fn); + } + get currentEditorView() { if (this[windowSymbol].editorView) { return new EditorView(this[windowSymbol].editorView).toProxy() as any; diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts index ea6fb71023..1f3d3b5e85 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -13,7 +13,7 @@ import { IPublicApiWorkspace, } from '../api'; import { IPublicEnumPluginRegisterLevel } from '../enum'; -import { IPublicModelEngineConfig, IPublicModelEditorView } from './'; +import { IPublicModelEngineConfig, IPublicModelWindow } from './'; export interface IPublicModelPluginContext { @@ -108,7 +108,7 @@ export interface IPublicModelPluginContext { */ get registerLevel(): IPublicEnumPluginRegisterLevel; - get editorWindow(): IPublicModelEditorView; + get editorWindow(): IPublicModelWindow; } /** diff --git a/packages/types/src/shell/model/window.ts b/packages/types/src/shell/model/window.ts index a33be6ceb1..95ab738bc1 100644 --- a/packages/types/src/shell/model/window.ts +++ b/packages/types/src/shell/model/window.ts @@ -42,4 +42,10 @@ export interface IPublicModelWindow< /** 窗口视图变更事件 */ onChangeViewType(fn: (viewName: string) => void): IPublicTypeDisposable; + + /** + * 窗口视图保存事件 + * @since 1.1.7 + */ + onSave(fn: () => void): IPublicTypeDisposable; } \ No newline at end of file diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index 0e37b4986e..6fb706632a 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -77,7 +77,18 @@ export class EditorWindow implements IEditorWindow { const saveResult = await this.editorViews.get(name)?.save(); value[name] = saveResult; } - return await this.resource.save(value); + const result = await this.resource.save(value); + this.emitter.emit('handle.save'); + + return result; + } + + onSave(fn: () => void) { + this.emitter.on('handle.save', fn); + + return () => { + this.emitter.off('handle.save', fn); + }; } async init() { From 5dcd946dcaef10da291c686a6e22e99190f6d6ed Mon Sep 17 00:00:00 2001 From: Justin-lu <gdjyluxiaoyong@gmail.com> Date: Mon, 22 May 2023 16:22:46 +0800 Subject: [PATCH 149/469] fix: this bind error --- packages/shell/src/api/setters.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/shell/src/api/setters.ts b/packages/shell/src/api/setters.ts index 56f42d18ba..7750a5152e 100644 --- a/packages/shell/src/api/setters.ts +++ b/packages/shell/src/api/setters.ts @@ -47,11 +47,11 @@ export class Setters implements IPublicApiSetters { * 获取已注册的所有 settersMap * @returns */ - getSettersMap(): Map<string, IPublicTypeRegisteredSetter & { + getSettersMap = (): Map<string, IPublicTypeRegisteredSetter & { type: string; - }> { + }> => { return this[settersSymbol].getSettersMap(); - } + }; /** * 注册一个 setter From c78dd80c289495799f76709d7dde60b170b3a56e Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 23 May 2023 17:37:29 +0800 Subject: [PATCH 150/469] feat: update modals visible state in outline pane --- .../plugin-outline-pane/src/controllers/tree-node.ts | 4 +++- packages/plugin-outline-pane/src/controllers/tree.ts | 5 +++++ .../plugin-outline-pane/src/views/tree-title.tsx | 12 +++++++++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/plugin-outline-pane/src/controllers/tree-node.ts b/packages/plugin-outline-pane/src/controllers/tree-node.ts index af82904ee1..079ed77d65 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-node.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-node.ts @@ -244,7 +244,9 @@ export default class TreeNode { if (this.node.conditionGroup) { return; } - this.node.visible = !flag; + if (this.node.visible !== !flag) { + this.node.visible = !flag; + } this.event.emit(EVENT_NAMES.hiddenChanged, flag); } diff --git a/packages/plugin-outline-pane/src/controllers/tree.ts b/packages/plugin-outline-pane/src/controllers/tree.ts index 7b9ad0593f..ab0d64b0f5 100644 --- a/packages/plugin-outline-pane/src/controllers/tree.ts +++ b/packages/plugin-outline-pane/src/controllers/tree.ts @@ -40,6 +40,11 @@ export class Tree { treeNode?.notifyConditionChanged(); } }); + + doc?.onChangeNodeVisible((node: IPublicModelNode, visible: boolean) => { + const treeNode = this.getTreeNodeById(node.id); + treeNode?.setHidden(!visible); + }); } setNodeSelected(nodeId: string): void { diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 9232132383..6f35c6a614 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -28,6 +28,7 @@ export default class TreeTitle extends PureComponent<{ editing: boolean; title: string; condition?: boolean; + visible?: boolean; } = { editing: false, title: '', @@ -93,6 +94,11 @@ export default class TreeTitle extends PureComponent<{ condition: treeNode.condition, }); }); + treeNode.onHiddenChanged((hidden: boolean) => { + this.setState({ + visible: !hidden, + }); + }); } render() { @@ -132,7 +138,7 @@ export default class TreeTitle extends PureComponent<{ data-id={treeNode.id} onClick={() => { if (isModal) { - if (node.visible) { + if (this.state.visible) { node.document?.modalNodesManager?.setInvisible(node); } else { node.document?.modalNodesManager?.setVisible(node); @@ -144,7 +150,7 @@ export default class TreeTitle extends PureComponent<{ } }} > - {isModal && node.visible && ( + {isModal && this.state.visible && ( <div onClick={() => { node.document?.modalNodesManager?.setInvisible(node); }} @@ -152,7 +158,7 @@ export default class TreeTitle extends PureComponent<{ <IconRadioActive className="tree-node-modal-radio-active" /> </div> )} - {isModal && !node.visible && ( + {isModal && !this.state.visible && ( <div onClick={() => { node.document?.modalNodesManager?.setVisible(node); }} From addcdeb9d7f77a550921a5543b9676e9a968d412 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 23 May 2023 18:19:38 +0800 Subject: [PATCH 151/469] chore(docs): publish 1.0.29 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 80f146513f..676c727911 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.28", + "version": "1.0.29", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 878a934511da58343478a913a9ad30045a4d77fc Mon Sep 17 00:00:00 2001 From: lukeup <jun.lukesmail@gmail.com> Date: Thu, 25 May 2023 14:16:42 +0800 Subject: [PATCH 152/469] =?UTF-8?q?docs:=20=E5=8A=A0=E5=85=A5=E5=9B=BE?= =?UTF-8?q?=E7=BC=96=E6=8E=92=E6=89=A9=E5=B1=95=E4=BD=BF=E7=94=A8=E8=AF=B4?= =?UTF-8?q?=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/guide/expand/editor/graph.md | 155 +++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 docs/docs/guide/expand/editor/graph.md diff --git a/docs/docs/guide/expand/editor/graph.md b/docs/docs/guide/expand/editor/graph.md new file mode 100644 index 0000000000..2d5127054e --- /dev/null +++ b/docs/docs/guide/expand/editor/graph.md @@ -0,0 +1,155 @@ +--- +title: 图编排扩展 +sidebar_position: 9 +--- +## 项目运行 +### 前置准备 +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即通过图编排引擎加入了几个简单的物料而来,已经是可以面向真是用户的产品界面。 +![image.png](https://img.alicdn.com/imgextra/i1/O1CN016TbCI31hM2sJy8qkR_!!6000000004262-2-tps-5120-2726.png) +### 区域组成 +#### 顶部:操作区​ +- 右侧:保存到本地、重置页面、自定义按钮 +#### 顶部:工具区 +- 左侧:删除、撤销、重做、放大、缩小 +#### 左侧:面板与操作区​ +- 物料面板:可以查找节点,并在此拖动节点到编辑器画布中 +#### 中部:可视化页面编辑画布区域​ +- 点击节点/边在右侧面板中能够显示出对应组件的属性配置选项 +- 拖拽修改节点的排列顺序 +#### 右侧:组件级别配置​ +- 选中的组件:从页面开始一直到当前选中的节点/边位置,点击对应的名称可以切换到对应的节点上 +- 选中组件的配置:属性:节点的基础属性值设置 + +> 每个区域的组成都可以被替换和自定义来生成开发者需要的业务产品。 + +## 目录介绍 +![image.png](https://img.alicdn.com/imgextra/i3/O1CN01Luc8gr1tLq5QTbpb9_!!6000000005886-0-tps-832-1522.jpg) + +- 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(<div>自定义 react 标签</div>, 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 +``` +![image.png](https://img.alicdn.com/imgextra/i3/O1CN01DCCqO82ADuhS8ztCt_!!6000000008170-2-tps-546-208.png) + +仓库初始化完成 +![image.png](https://img.alicdn.com/imgextra/i2/O1CN01qK2rUe1JNpdqbdhoW_!!6000000001017-0-tps-5120-2830.jpg) + +接下来即可编写物料内容了 +图物料与低代码的dom场景存在画布的差异,因此暂不支持物料单独调试,须通过项目demo进行物料调试 + +### 资产描述 +```bash +npm run lowcode:build +``` +如果物料是个React组件,则在执行上述命令时会自动生成对应的meta.ts,<b>但图物料很多时候并非一个React组件,因此须手动生产meta.ts</b> + +可参考: 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 + }, +] +``` +![image.png](https://img.alicdn.com/imgextra/i4/O1CN01HyXfL12992sDkOmOg_!!6000000008024-0-tps-5120-2824.jpg) + +本地启动 +```bash +npm run lowcode:dev +``` +#### 项目侧 +通过@alilc/lce-graph-core加载物料的天然支持了debug,因此无须特殊处理。 +若项目中自行加载,则参考 https://lowcode-engine.cn/site/docs/guide/expand/editor/cli +项目访问地址后拼接query "?debug"即可进入物料调试 +![image.png](https://img.alicdn.com/imgextra/i2/O1CN01ke58hT1aRoYJzkutk_!!6000000003327-2-tps-5120-2790.png) + + From 9d2214e0fc3b70adad1717b3e2ea5281a0ad23aa Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 25 May 2023 16:23:34 +0800 Subject: [PATCH 153/469] =?UTF-8?q?Revert=20"docs:=20=E5=8A=A0=E5=85=A5?= =?UTF-8?q?=E5=9B=BE=E7=BC=96=E6=8E=92=E6=89=A9=E5=B1=95=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E8=AF=B4=E6=98=8E"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 878a934511da58343478a913a9ad30045a4d77fc. --- docs/docs/guide/expand/editor/graph.md | 155 ------------------------- 1 file changed, 155 deletions(-) delete mode 100644 docs/docs/guide/expand/editor/graph.md diff --git a/docs/docs/guide/expand/editor/graph.md b/docs/docs/guide/expand/editor/graph.md deleted file mode 100644 index 2d5127054e..0000000000 --- a/docs/docs/guide/expand/editor/graph.md +++ /dev/null @@ -1,155 +0,0 @@ ---- -title: 图编排扩展 -sidebar_position: 9 ---- -## 项目运行 -### 前置准备 -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即通过图编排引擎加入了几个简单的物料而来,已经是可以面向真是用户的产品界面。 -![image.png](https://img.alicdn.com/imgextra/i1/O1CN016TbCI31hM2sJy8qkR_!!6000000004262-2-tps-5120-2726.png) -### 区域组成 -#### 顶部:操作区​ -- 右侧:保存到本地、重置页面、自定义按钮 -#### 顶部:工具区 -- 左侧:删除、撤销、重做、放大、缩小 -#### 左侧:面板与操作区​ -- 物料面板:可以查找节点,并在此拖动节点到编辑器画布中 -#### 中部:可视化页面编辑画布区域​ -- 点击节点/边在右侧面板中能够显示出对应组件的属性配置选项 -- 拖拽修改节点的排列顺序 -#### 右侧:组件级别配置​ -- 选中的组件:从页面开始一直到当前选中的节点/边位置,点击对应的名称可以切换到对应的节点上 -- 选中组件的配置:属性:节点的基础属性值设置 - -> 每个区域的组成都可以被替换和自定义来生成开发者需要的业务产品。 - -## 目录介绍 -![image.png](https://img.alicdn.com/imgextra/i3/O1CN01Luc8gr1tLq5QTbpb9_!!6000000005886-0-tps-832-1522.jpg) - -- 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(<div>自定义 react 标签</div>, 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 -``` -![image.png](https://img.alicdn.com/imgextra/i3/O1CN01DCCqO82ADuhS8ztCt_!!6000000008170-2-tps-546-208.png) - -仓库初始化完成 -![image.png](https://img.alicdn.com/imgextra/i2/O1CN01qK2rUe1JNpdqbdhoW_!!6000000001017-0-tps-5120-2830.jpg) - -接下来即可编写物料内容了 -图物料与低代码的dom场景存在画布的差异,因此暂不支持物料单独调试,须通过项目demo进行物料调试 - -### 资产描述 -```bash -npm run lowcode:build -``` -如果物料是个React组件,则在执行上述命令时会自动生成对应的meta.ts,<b>但图物料很多时候并非一个React组件,因此须手动生产meta.ts</b> - -可参考: 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 - }, -] -``` -![image.png](https://img.alicdn.com/imgextra/i4/O1CN01HyXfL12992sDkOmOg_!!6000000008024-0-tps-5120-2824.jpg) - -本地启动 -```bash -npm run lowcode:dev -``` -#### 项目侧 -通过@alilc/lce-graph-core加载物料的天然支持了debug,因此无须特殊处理。 -若项目中自行加载,则参考 https://lowcode-engine.cn/site/docs/guide/expand/editor/cli -项目访问地址后拼接query "?debug"即可进入物料调试 -![image.png](https://img.alicdn.com/imgextra/i2/O1CN01ke58hT1aRoYJzkutk_!!6000000003327-2-tps-5120-2790.png) - - From ea073d7fdaedab8bdf8eabafc597b153e20eed56 Mon Sep 17 00:00:00 2001 From: lukeup <jun.lukesmail@gmail.com> Date: Thu, 25 May 2023 16:33:22 +0800 Subject: [PATCH 154/469] =?UTF-8?q?docs:=20=E5=8A=A0=E5=85=A5=E5=9B=BE?= =?UTF-8?q?=E7=BC=96=E6=8E=92=E6=89=A9=E5=B1=95=E4=BD=BF=E7=94=A8=E8=AF=B4?= =?UTF-8?q?=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/guide/expand/editor/graph.md | 155 +++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 docs/docs/guide/expand/editor/graph.md diff --git a/docs/docs/guide/expand/editor/graph.md b/docs/docs/guide/expand/editor/graph.md new file mode 100644 index 0000000000..2d5127054e --- /dev/null +++ b/docs/docs/guide/expand/editor/graph.md @@ -0,0 +1,155 @@ +--- +title: 图编排扩展 +sidebar_position: 9 +--- +## 项目运行 +### 前置准备 +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即通过图编排引擎加入了几个简单的物料而来,已经是可以面向真是用户的产品界面。 +![image.png](https://img.alicdn.com/imgextra/i1/O1CN016TbCI31hM2sJy8qkR_!!6000000004262-2-tps-5120-2726.png) +### 区域组成 +#### 顶部:操作区​ +- 右侧:保存到本地、重置页面、自定义按钮 +#### 顶部:工具区 +- 左侧:删除、撤销、重做、放大、缩小 +#### 左侧:面板与操作区​ +- 物料面板:可以查找节点,并在此拖动节点到编辑器画布中 +#### 中部:可视化页面编辑画布区域​ +- 点击节点/边在右侧面板中能够显示出对应组件的属性配置选项 +- 拖拽修改节点的排列顺序 +#### 右侧:组件级别配置​ +- 选中的组件:从页面开始一直到当前选中的节点/边位置,点击对应的名称可以切换到对应的节点上 +- 选中组件的配置:属性:节点的基础属性值设置 + +> 每个区域的组成都可以被替换和自定义来生成开发者需要的业务产品。 + +## 目录介绍 +![image.png](https://img.alicdn.com/imgextra/i3/O1CN01Luc8gr1tLq5QTbpb9_!!6000000005886-0-tps-832-1522.jpg) + +- 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(<div>自定义 react 标签</div>, 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 +``` +![image.png](https://img.alicdn.com/imgextra/i3/O1CN01DCCqO82ADuhS8ztCt_!!6000000008170-2-tps-546-208.png) + +仓库初始化完成 +![image.png](https://img.alicdn.com/imgextra/i2/O1CN01qK2rUe1JNpdqbdhoW_!!6000000001017-0-tps-5120-2830.jpg) + +接下来即可编写物料内容了 +图物料与低代码的dom场景存在画布的差异,因此暂不支持物料单独调试,须通过项目demo进行物料调试 + +### 资产描述 +```bash +npm run lowcode:build +``` +如果物料是个React组件,则在执行上述命令时会自动生成对应的meta.ts,<b>但图物料很多时候并非一个React组件,因此须手动生产meta.ts</b> + +可参考: 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 + }, +] +``` +![image.png](https://img.alicdn.com/imgextra/i4/O1CN01HyXfL12992sDkOmOg_!!6000000008024-0-tps-5120-2824.jpg) + +本地启动 +```bash +npm run lowcode:dev +``` +#### 项目侧 +通过@alilc/lce-graph-core加载物料的天然支持了debug,因此无须特殊处理。 +若项目中自行加载,则参考 https://lowcode-engine.cn/site/docs/guide/expand/editor/cli +项目访问地址后拼接query "?debug"即可进入物料调试 +![image.png](https://img.alicdn.com/imgextra/i2/O1CN01ke58hT1aRoYJzkutk_!!6000000003327-2-tps-5120-2790.png) + + From 2004350c0d981f9bdccf2b78370fb3761eb2cc1b Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 25 May 2023 16:37:29 +0800 Subject: [PATCH 155/469] chore(docs): publish 1.0.30 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 676c727911..efac589fa9 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.29", + "version": "1.0.30", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From ecca076d502c51e42c275632bcb03fe057b04bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Fri, 26 May 2023 14:20:14 +0800 Subject: [PATCH 156/469] fix: comp which has no npm info should be regarded as lowCode comp --- .../designer/src/document/document-model.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 2d39ed1151..9521fef383 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -839,13 +839,18 @@ export class DocumentModel implements IDocumentModel { } // 合并外界传入的自定义渲染的组件 if (Array.isArray(extraComps)) { - extraComps.forEach(c => { - if (c && !exsitingMap[c]) { - const m = this.getComponentMeta(c); - if (m && m.npm?.package) { + extraComps.forEach((componentName) => { + if (componentName && !exsitingMap[componentName]) { + const meta = this.getComponentMeta(componentName); + if (meta?.npm?.package) { componentsMap.push({ - ...m?.npm, - componentName: c, + ...meta?.npm, + componentName, + }); + } else { + componentsMap.push({ + devMode: 'lowCode', + componentName, }); } } From 503793fdfc4ccc76fe190fad4ba841f86496037d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Mon, 29 May 2023 10:12:42 +0800 Subject: [PATCH 157/469] fix: supportVariable SHOULD take precedence over supportVariableGlobally (#1997) * fix: supportVariable should take precedence over supportVariableGlobally --- .../src/components/settings/settings-pane.tsx | 38 +++++++++++-------- packages/utils/src/misc.ts | 15 ++++++++ packages/utils/test/src/misc.test.ts | 9 +++++ 3 files changed, 46 insertions(+), 16 deletions(-) create mode 100644 packages/utils/test/src/misc.test.ts diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index 9cc8d9caed..1d651bb5a3 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -1,6 +1,6 @@ import { Component, MouseEvent, Fragment, ReactNode } from 'react'; import { shallowIntl, observer, obx, engineConfig, runInAction } from '@alilc/lowcode-editor-core'; -import { createContent, isJSSlot, isSetterConfig } from '@alilc/lowcode-utils'; +import { createContent, isJSSlot, isSetterConfig, shouldUseVariableSetter } from '@alilc/lowcode-utils'; import { Skeleton, Stage } from '@alilc/lowcode-editor-skeleton'; import { IPublicApiSetters, IPublicTypeCustomView, IPublicTypeDynamicProps } from '@alilc/lowcode-types'; import { ISettingEntry, IComponentMeta, ISettingField, isSettingField, ISettingTopEntry } from '@alilc/lowcode-designer'; @@ -155,23 +155,29 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView const supportVariable = this.field.extraProps?.supportVariable; // supportVariableGlobally 只对标准组件生效,vc 需要单独配置 const supportVariableGlobally = engineConfig.get('supportVariableGlobally', false) && isStandardComponent(componentMeta); - if (supportVariable || supportVariableGlobally) { - if (setterType === 'MixedSetter') { - // VariableSetter 不单独使用 - if (Array.isArray(setterProps.setters) && !setterProps.setters.includes('VariableSetter')) { - setterProps.setters.push('VariableSetter'); - } - } else { - setterType = 'MixedSetter'; - setterProps = { - setters: [ - setter, - 'VariableSetter', - ], - }; - } + const isUseVariableSetter = shouldUseVariableSetter(supportVariable, supportVariableGlobally); + if (isUseVariableSetter === false) { + return { + setterProps, + initialValue, + setterType, + }; } + if (setterType === 'MixedSetter') { + // VariableSetter 不单独使用 + if (Array.isArray(setterProps.setters) && !setterProps.setters.includes('VariableSetter')) { + setterProps.setters.push('VariableSetter'); + } + } else { + setterType = 'MixedSetter'; + setterProps = { + setters: [ + setter, + 'VariableSetter', + ], + }; + } return { setterProps, initialValue, diff --git a/packages/utils/src/misc.ts b/packages/utils/src/misc.ts index 4510e8643f..89f121065b 100644 --- a/packages/utils/src/misc.ts +++ b/packages/utils/src/misc.ts @@ -81,6 +81,7 @@ const stageList = [ 'init', 'upgrade', ]; + /** * 兼容原来的数字版本的枚举对象 * @param stage @@ -108,4 +109,18 @@ export function deprecate(fail: any, message: string, alterative?: string) { export function isRegExp(obj: any): obj is RegExp { return obj && obj.test && obj.exec && obj.compile; +} + +/** + * The prop supportVariable SHOULD take precedence over default global supportVariable. + * @param propSupportVariable prop supportVariable + * @param globalSupportVariable global supportVariable + * @returns + */ +export function shouldUseVariableSetter( + propSupportVariable: boolean | undefined, + globalSupportVariable: boolean, +) { + if (propSupportVariable === false) return false; + return propSupportVariable || globalSupportVariable; } \ No newline at end of file diff --git a/packages/utils/test/src/misc.test.ts b/packages/utils/test/src/misc.test.ts new file mode 100644 index 0000000000..8873dc4c80 --- /dev/null +++ b/packages/utils/test/src/misc.test.ts @@ -0,0 +1,9 @@ +import { shouldUseVariableSetter } from '../../src/misc'; + +it('shouldUseVariableSetter', () => { + expect(shouldUseVariableSetter(false, true)).toBeFalsy(); + expect(shouldUseVariableSetter(true, true)).toBeTruthy(); + expect(shouldUseVariableSetter(true, false)).toBeTruthy(); + expect(shouldUseVariableSetter(undefined, false)).toBeFalsy(); + expect(shouldUseVariableSetter(undefined, true)).toBeTruthy(); +}); \ No newline at end of file From 75a4a80935ea69cff8c179a08119bbad833d3988 Mon Sep 17 00:00:00 2001 From: AprChell <smile_zchi@163.com> Date: Mon, 29 May 2023 14:11:12 +0800 Subject: [PATCH 158/469] =?UTF-8?q?feat(code-gen):=20=E5=87=BA=E7=A0=81?= =?UTF-8?q?=E7=94=9F=E6=88=90=E7=9A=84*.ts=E5=92=8C*.tsx=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=BD=BF=E7=94=A8babel=E6=A0=BC=E5=BC=8F=E5=8C=96=20(#2088)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/code-generator/src/postprocessor/prettier/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/src/postprocessor/prettier/index.ts b/modules/code-generator/src/postprocessor/prettier/index.ts index b4c3188f3f..075fc66e7a 100644 --- a/modules/code-generator/src/postprocessor/prettier/index.ts +++ b/modules/code-generator/src/postprocessor/prettier/index.ts @@ -20,7 +20,7 @@ const factory: PostProcessorFactory<ProcessorConfig> = (config?: ProcessorConfig const codePrettier: PostProcessor = (content: string, fileType: string) => { let parser: prettier.BuiltInParserName | any; - if (fileType === 'js' || fileType === 'jsx') { + if (fileType === 'js' || fileType === 'jsx' || fileType === 'ts' || fileType === 'tsx') { parser = 'babel'; } else if (fileType === 'json') { parser = 'json-stringify'; From 9695add27cc1b8b30cc7b2d7eff147f25c72f159 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Wed, 31 May 2023 14:48:47 +0800 Subject: [PATCH 159/469] chore(release): publish 1.1.7 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index dd7f87e45e..67ffb648e2 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.6", + "version": "1.1.7", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index e3b5ca968c..cb73cdeb92 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.6", + "version": "1.1.7", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.1.6", - "@alilc/lowcode-types": "1.1.6", - "@alilc/lowcode-utils": "1.1.6", + "@alilc/lowcode-editor-core": "1.1.7", + "@alilc/lowcode-types": "1.1.7", + "@alilc/lowcode-utils": "1.1.7", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 2701199d57..efb73bb2ca 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.1.6", + "version": "1.1.7", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.6", - "@alilc/lowcode-utils": "1.1.6", + "@alilc/lowcode-types": "1.1.7", + "@alilc/lowcode-utils": "1.1.7", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index ff9c9a782b..9199e1cb3d 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.1.6", + "version": "1.1.7", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.1.6", - "@alilc/lowcode-editor-core": "1.1.6", - "@alilc/lowcode-types": "1.1.6", - "@alilc/lowcode-utils": "1.1.6", + "@alilc/lowcode-designer": "1.1.7", + "@alilc/lowcode-editor-core": "1.1.7", + "@alilc/lowcode-types": "1.1.7", + "@alilc/lowcode-utils": "1.1.7", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index ca63f42f4a..4a2d7f07a3 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.6", + "version": "1.1.7", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.1.6", - "@alilc/lowcode-editor-core": "1.1.6", - "@alilc/lowcode-editor-skeleton": "1.1.6", + "@alilc/lowcode-designer": "1.1.7", + "@alilc/lowcode-editor-core": "1.1.7", + "@alilc/lowcode-editor-skeleton": "1.1.7", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.6", - "@alilc/lowcode-plugin-outline-pane": "1.1.6", - "@alilc/lowcode-shell": "1.1.6", - "@alilc/lowcode-utils": "1.1.6", - "@alilc/lowcode-workspace": "1.1.6", + "@alilc/lowcode-plugin-designer": "1.1.7", + "@alilc/lowcode-plugin-outline-pane": "1.1.7", + "@alilc/lowcode-shell": "1.1.7", + "@alilc/lowcode-utils": "1.1.7", + "@alilc/lowcode-workspace": "1.1.7", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 7fa6ab0730..2448ce0fc0 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.6", + "version": "1.1.7", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 5ffc7e96f3..302d224915 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.1.6", + "version": "1.1.7", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.6", - "@alilc/lowcode-editor-core": "1.1.6", - "@alilc/lowcode-utils": "1.1.6", + "@alilc/lowcode-designer": "1.1.7", + "@alilc/lowcode-editor-core": "1.1.7", + "@alilc/lowcode-utils": "1.1.7", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index cbba2bc456..b191969208 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.1.6", + "version": "1.1.7", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.6", - "@alilc/lowcode-utils": "1.1.6", + "@alilc/lowcode-types": "1.1.7", + "@alilc/lowcode-utils": "1.1.7", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 489cf14093..3910afe41e 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.1.6", + "version": "1.1.7", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.1.6", - "@alilc/lowcode-utils": "1.1.6", + "@alilc/lowcode-renderer-core": "1.1.7", + "@alilc/lowcode-utils": "1.1.7", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 4f8bc7ad18..0e29b10919 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.1.6", + "version": "1.1.7", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.6", - "@alilc/lowcode-rax-renderer": "1.1.6", - "@alilc/lowcode-types": "1.1.6", - "@alilc/lowcode-utils": "1.1.6", + "@alilc/lowcode-designer": "1.1.7", + "@alilc/lowcode-rax-renderer": "1.1.7", + "@alilc/lowcode-types": "1.1.7", + "@alilc/lowcode-utils": "1.1.7", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 744c1cac09..451ef1ee3d 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.1.6", + "version": "1.1.7", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.1.6" + "@alilc/lowcode-renderer-core": "1.1.7" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index ad7673b620..adb5526c73 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.1.6", + "version": "1.1.7", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.6", - "@alilc/lowcode-react-renderer": "1.1.6", - "@alilc/lowcode-types": "1.1.6", - "@alilc/lowcode-utils": "1.1.6", + "@alilc/lowcode-designer": "1.1.7", + "@alilc/lowcode-react-renderer": "1.1.7", + "@alilc/lowcode-types": "1.1.7", + "@alilc/lowcode-utils": "1.1.7", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 1a6fd6090a..ce633dd546 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.1.6", + "version": "1.1.7", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.1.6", - "@alilc/lowcode-utils": "1.1.6", + "@alilc/lowcode-types": "1.1.7", + "@alilc/lowcode-utils": "1.1.7", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.1.6", + "@alilc/lowcode-designer": "1.1.7", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 521befb2eb..9ec85ec5c2 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.6", + "version": "1.1.7", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.6", - "@alilc/lowcode-editor-core": "1.1.6", - "@alilc/lowcode-editor-skeleton": "1.1.6", - "@alilc/lowcode-types": "1.1.6", - "@alilc/lowcode-utils": "1.1.6", - "@alilc/lowcode-workspace": "1.1.6", + "@alilc/lowcode-designer": "1.1.7", + "@alilc/lowcode-editor-core": "1.1.7", + "@alilc/lowcode-editor-skeleton": "1.1.7", + "@alilc/lowcode-types": "1.1.7", + "@alilc/lowcode-utils": "1.1.7", + "@alilc/lowcode-workspace": "1.1.7", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index b92d2efb66..0b05893ca1 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.6", + "version": "1.1.7", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index d52f6deef2..6a0880b007 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.6", + "version": "1.1.7", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.6", + "@alilc/lowcode-types": "1.1.7", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 52a45567d4..569d652037 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.6", + "version": "1.1.7", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.6", - "@alilc/lowcode-editor-core": "1.1.6", - "@alilc/lowcode-editor-skeleton": "1.1.6", - "@alilc/lowcode-types": "1.1.6", - "@alilc/lowcode-utils": "1.1.6", + "@alilc/lowcode-designer": "1.1.7", + "@alilc/lowcode-editor-core": "1.1.7", + "@alilc/lowcode-editor-skeleton": "1.1.7", + "@alilc/lowcode-types": "1.1.7", + "@alilc/lowcode-utils": "1.1.7", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From f10b694c42ae97ebdd337758361031d8745349d8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 31 May 2023 18:01:00 +0800 Subject: [PATCH 160/469] feat(renderer-core): optimize the judgment of whether leaf hoc has children --- packages/renderer-core/src/hoc/leaf.tsx | 17 +++++---- .../renderer-core/tests/hoc/leaf.test.tsx | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index 98b2674750..432f22a5e5 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -521,16 +521,11 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { } get hasChildren(): boolean { - let { children } = this.props; - if (this.state.childrenInState) { - children = this.state.nodeChildren; - } - - if (Array.isArray(children)) { - return Boolean(children && children.length); + if (!this.state.childrenInState) { + return 'children' in this.props; } - return Boolean(children); + return true; } get children(): any { @@ -576,7 +571,11 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { delete compProps.__inner__; - return engine.createElement(Comp, compProps, this.hasChildren ? this.children : null); + if (this.hasChildren) { + return engine.createElement(Comp, compProps, this.children); + } + + return engine.createElement(Comp, compProps); } } diff --git a/packages/renderer-core/tests/hoc/leaf.test.tsx b/packages/renderer-core/tests/hoc/leaf.test.tsx index d4a65e578a..c21a10be92 100644 --- a/packages/renderer-core/tests/hoc/leaf.test.tsx +++ b/packages/renderer-core/tests/hoc/leaf.test.tsx @@ -504,6 +504,41 @@ describe('onChildrenChange', () => { DivNode.emitChildrenChange(); makeSnapshot(component); }); + + it('children is 0', () => { + DivNode.schema.children = 0 + DivNode.emitChildrenChange(); + const componentInstance = component.root; + expect(componentInstance.findByType(components.Div).props.children).toEqual(0); + }); + + it('children is false', () => { + DivNode.schema.children = false + DivNode.emitChildrenChange(); + const componentInstance = component.root; + expect(componentInstance.findByType(components.Div).props.children).toEqual(false); + }); + + it('children is []', () => { + DivNode.schema.children = [] + DivNode.emitChildrenChange(); + const componentInstance = component.root; + expect(componentInstance.findByType(components.Div).props.children).toEqual([]); + }); + + it('children is null', () => { + DivNode.schema.children = null + DivNode.emitChildrenChange(); + const componentInstance = component.root; + expect(componentInstance.findByType(components.Div).props.children).toEqual(null); + }); + + it('children is undefined', () => { + DivNode.schema.children = undefined; + DivNode.emitChildrenChange(); + const componentInstance = component.root; + expect(componentInstance.findByType(components.Div).props.children).toEqual(undefined); + }); }); describe('not render leaf', () => { From d82bcfdf2a4d469fe844632cb0683945ff7aadb9 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 31 May 2023 18:12:28 +0800 Subject: [PATCH 161/469] feat(renderer-core): optimize the judgment of whether leaf hoc has children --- packages/renderer-core/jest.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/renderer-core/jest.config.js b/packages/renderer-core/jest.config.js index 2489490fa2..e3267c5177 100644 --- a/packages/renderer-core/jest.config.js +++ b/packages/renderer-core/jest.config.js @@ -12,6 +12,7 @@ const jestConfig = { // testMatch: ['(/tests?/.*(test))\\.[jt]s$'], // testMatch: ['**/*/base.test.tsx'], // testMatch: ['**/utils/common.test.ts'], + // testMatch: ['**/*/leaf.test.tsx'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], From 035c213b1681bddee5d9c00c9fe3240910dc0e80 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 31 May 2023 18:18:52 +0800 Subject: [PATCH 162/469] fix: fix that the prop model is not reused and the update is not triggered --- packages/designer/package.json | 1 + .../designer/src/document/node/props/prop.ts | 16 ++++++---------- .../tests/document/node/props/prop.test.ts | 1 - 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/designer/package.json b/packages/designer/package.json index cb73cdeb92..4deaa27219 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -15,6 +15,7 @@ }, "license": "MIT", "dependencies": { + "@alilc/build-plugin-lce": "^0.0.4-beta.2", "@alilc/lowcode-editor-core": "1.1.7", "@alilc/lowcode-types": "1.1.7", "@alilc/lowcode-utils": "1.1.7", diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 37017d72d8..01b2dc26b9 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -148,15 +148,13 @@ export class Prop implements IProp, IPropParent { @obx.shallow private _items: IProp[] | null = null; - @obx.shallow private _maps: Map<string | number, IProp> | null = null; - /** - * 作为 _maps 的一层缓存机制,主要是复用部分已存在的 Prop,保持响应式关系,比如: + * 作为一层缓存机制,主要是复用部分已存在的 Prop,保持响应式关系,比如: * 当前 Prop#_value 值为 { a: 1 },当调用 setValue({ a: 2 }) 时,所有原来的子 Prop 均被销毁, * 导致假如外部有 mobx reaction(常见于 observer),此时响应式链路会被打断, * 因为 reaction 监听的是原 Prop(a) 的 _value,而不是新 Prop(a) 的 _value。 */ - private _prevMaps: Map<string | number, IProp> | null = null; + @obx.shallow private _maps: Map<string | number, IProp> | null = null; /** * 构造 items 属性,同时构造 maps 属性 @@ -171,8 +169,8 @@ export class Prop implements IProp, IPropParent { data.forEach((item: any, idx: number) => { items = items || []; let prop; - if (this._prevMaps?.has(idx.toString())) { - prop = this._prevMaps.get(idx.toString())!; + if (this._maps?.has(idx.toString())) { + prop = this._maps.get(idx.toString())!; prop.setValue(item); } else { prop = new Prop(this, item, idx); @@ -187,8 +185,8 @@ export class Prop implements IProp, IPropParent { const keys = Object.keys(data); for (const key of keys) { let prop: IProp; - if (this._prevMaps?.has(key)) { - prop = this._prevMaps.get(key)!; + if (this._maps?.has(key)) { + prop = this._maps.get(key)!; prop.setValue(data[key]); } else { prop = new Prop(this, data[key], key); @@ -419,8 +417,6 @@ export class Prop implements IProp, IPropParent { items.forEach((prop) => prop.purge()); } this._items = null; - this._prevMaps = this._maps; - this._maps = null; if (this._type !== 'slot' && this._slotNode) { this._slotNode.remove(); this._slotNode = undefined; diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 177bc5247f..58c24a4ea4 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -379,7 +379,6 @@ describe('Prop 类测试', () => { prop.dispose(); expect(prop._items).toBeNull(); - expect(prop._maps).toBeNull(); }); }); From 980957f3adabaef76fd7e42a9162661904f4db36 Mon Sep 17 00:00:00 2001 From: "knight.chen" <knightchen@knx.com.cn> Date: Wed, 31 May 2023 22:48:49 +0800 Subject: [PATCH 163/469] feat: extract simulator type --- .../src/builtin-simulator/renderer.ts | 26 ++------------- packages/types/src/shell/type/index.ts | 1 + .../src/shell/type/simulator-renderer.ts | 32 +++++++++++++++++++ 3 files changed, 35 insertions(+), 24 deletions(-) create mode 100644 packages/types/src/shell/type/simulator-renderer.ts diff --git a/packages/designer/src/builtin-simulator/renderer.ts b/packages/designer/src/builtin-simulator/renderer.ts index bd94f24f65..15664757bc 100644 --- a/packages/designer/src/builtin-simulator/renderer.ts +++ b/packages/designer/src/builtin-simulator/renderer.ts @@ -1,29 +1,7 @@ import { Component } from '../simulator'; -import { IPublicTypeComponentInstance, IPublicTypeNodeInstance, Asset, IPublicTypeComponentSchema, IPublicTypeProjectSchema, IPublicTypeLowCodeComponent } from '@alilc/lowcode-types'; +import { IPublicTypeComponentInstance, IPublicTypeSimulatorRenderer } from '@alilc/lowcode-types'; -export interface BuiltinSimulatorRenderer { - readonly isSimulatorRenderer: true; - autoRepaintNode?: boolean; - components: Record<string, Component>; - rerender: () => void; - createComponent(schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>): Component | null; - getComponent(componentName: string): Component; - getClosestNodeInstance( - from: IPublicTypeComponentInstance, - nodeId?: string, - ): IPublicTypeNodeInstance<IPublicTypeComponentInstance> | null; - findDOMNodes(instance: IPublicTypeComponentInstance): Array<Element | Text> | null; - getClientRects(element: Element | Text): DOMRect[]; - setNativeSelection(enableFlag: boolean): void; - setDraggingState(state: boolean): void; - setCopyState(state: boolean): void; - loadAsyncLibrary(asyncMap: { [index: string]: any }): void; - clearState(): void; - stopAutoRepaintNode(): void; - enableAutoRepaintNode(): void; - run(): void; - load(asset: Asset): Promise<any>; -} +export type BuiltinSimulatorRenderer = IPublicTypeSimulatorRenderer<Component, IPublicTypeComponentInstance>; export function isSimulatorRenderer(obj: any): obj is BuiltinSimulatorRenderer { return obj && obj.isSimulatorRenderer; diff --git a/packages/types/src/shell/type/index.ts b/packages/types/src/shell/type/index.ts index b5dad9bb61..7232ffbbdc 100644 --- a/packages/types/src/shell/type/index.ts +++ b/packages/types/src/shell/type/index.ts @@ -90,3 +90,4 @@ export * from './editor-view-config'; export * from './hotkey-callback-config'; export * from './hotkey-callbacks'; export * from './scrollable'; +export * from './simulator-renderer'; diff --git a/packages/types/src/shell/type/simulator-renderer.ts b/packages/types/src/shell/type/simulator-renderer.ts new file mode 100644 index 0000000000..14aa16ab88 --- /dev/null +++ b/packages/types/src/shell/type/simulator-renderer.ts @@ -0,0 +1,32 @@ +import { Asset } from '../../assets'; +import { + IPublicTypeNodeInstance, + IPublicTypeProjectSchema, + IPublicTypeComponentSchema, +} from './'; + +export interface IPublicTypeSimulatorRenderer<Component, ComponentInstance> { + readonly isSimulatorRenderer: true; + autoRepaintNode?: boolean; + components: Record<string, Component>; + rerender: () => void; + createComponent( + schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>, + ): Component | null; + getComponent(componentName: string): Component; + getClosestNodeInstance( + from: ComponentInstance, + nodeId?: string, + ): IPublicTypeNodeInstance<ComponentInstance> | null; + findDOMNodes(instance: ComponentInstance): Array<Element | Text> | null; + getClientRects(element: Element | Text): DOMRect[]; + setNativeSelection(enableFlag: boolean): void; + setDraggingState(state: boolean): void; + setCopyState(state: boolean): void; + loadAsyncLibrary(asyncMap: { [index: string]: any }): void; + clearState(): void; + stopAutoRepaintNode(): void; + enableAutoRepaintNode(): void; + run(): void; + load(asset: Asset): Promise<any>; +} From 5feeab5aecb07071923f5b26ce22e3f72911be28 Mon Sep 17 00:00:00 2001 From: Cai HongYuan <pccai1983@hotmail.com> Date: Thu, 1 Jun 2023 14:46:38 +0800 Subject: [PATCH 164/469] Update pluginContextMenu.md (#2108) * update pluginContextMenu.md --- docs/docs/guide/expand/editor/pluginContextMenu.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/docs/guide/expand/editor/pluginContextMenu.md b/docs/docs/guide/expand/editor/pluginContextMenu.md index e9dbdf3c48..cd293b73e7 100644 --- a/docs/docs/guide/expand/editor/pluginContextMenu.md +++ b/docs/docs/guide/expand/editor/pluginContextMenu.md @@ -18,8 +18,7 @@ import { Icon, Message } from '@alifd/next'; const addHelloAction = (ctx: IPublicModelPluginContext) => { return { async init() { - const { addBuiltinComponentAction } = ctx.material; - addBuiltinComponentAction({ + ctx.material.addBuiltinComponentAction({ name: 'hello', content: { icon: <Icon type="atm" />, @@ -54,8 +53,7 @@ import { IPublicModelPluginContext } from '@alilc/lowcode-types'; const removeCopyAction = (ctx: IPublicModelPluginContext) => { return { async init() { - const { removeBuiltinComponentAction } = ctx.material; - removeBuiltinComponentAction('copy'); + ctx.material.removeBuiltinComponentAction('copy'); } } }; From 03495ba9efd2c7b950b52756022c2ca2807dc085 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 1 Jun 2023 14:39:17 +0800 Subject: [PATCH 165/469] feat: add componentMeta?.advanced?.callbacks?.onSelectHook api --- packages/designer/jest.config.js | 1 + packages/designer/src/document/node/node.ts | 9 +++++++++ packages/designer/src/document/selection.ts | 19 ++++++++++++++++++- .../designer/tests/document/selection.test.ts | 9 +-------- packages/types/src/shell/type/metadata.ts | 3 +++ 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index 82c76fad88..1ecebd9388 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -19,6 +19,7 @@ const jestConfig = { // testMatch: ['**/setting-field.test.ts'], // testMatch: ['**/node.test.ts'], // testMatch: ['**/builtin-hotkey.test.ts'], + // testMatch: ['**/selection.test.ts'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 456595b048..b0e509bce8 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -159,6 +159,9 @@ export interface IBaseNode<Schema extends IPublicTypeNodeSchema = IPublicTypeNod setProps(props?: IPublicTypePropsMap | IPublicTypePropsList | Props | null): void; mergeProps(props: IPublicTypePropsMap): void; + + /** 是否可以选中 */ + canSelect(): boolean; } /** @@ -644,6 +647,12 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> return !!this.getExtraProp('isLocked')?.getValue(); } + canSelect(): boolean { + const onSelectHook = this.componentMeta?.advanced?.callbacks?.onSelectHook; + const canSelect = typeof onSelectHook === 'function' ? onSelectHook(this.internalToShellNode()!) : true; + return canSelect; + } + /** * 选择当前节点 */ diff --git a/packages/designer/src/document/selection.ts b/packages/designer/src/document/selection.ts index 93ec04ffe9..6147e188d8 100644 --- a/packages/designer/src/document/selection.ts +++ b/packages/designer/src/document/selection.ts @@ -32,6 +32,12 @@ export class Selection implements ISelection { return; } + const node = this.doc.getNode(id); + + if (!node?.canSelect()) { + return; + } + this._selected = [id]; this.emitter.emit('selectionchange', this._selected); } @@ -40,7 +46,18 @@ export class Selection implements ISelection { * 批量选中 */ selectAll(ids: string[]) { - this._selected = ids; + const selectIds: string[] = []; + + ids.forEach(d => { + const node = this.doc.getNode(d); + + if (node?.canSelect()) { + selectIds.push(d); + } + }); + + this._selected = selectIds; + this.emitter.emit('selectionchange', this._selected); } diff --git a/packages/designer/tests/document/selection.test.ts b/packages/designer/tests/document/selection.test.ts index b8b5ad4343..0af22b5cef 100644 --- a/packages/designer/tests/document/selection.test.ts +++ b/packages/designer/tests/document/selection.test.ts @@ -122,7 +122,7 @@ describe('选择区测试', () => { selectionChangeHandler.mockClear(); }); - it('dispose 方法', () => { + it('selectAll 包含不存在的 id', () => { const project = new Project(designer, { componentsTree: [ formSchema, @@ -135,14 +135,7 @@ describe('选择区测试', () => { selection.selectAll(['form', 'node_k1ow3cbj', 'form2']); - const selectionChangeHandler = jest.fn(); - selection.onSelectionChange(selectionChangeHandler); - selection.dispose(); - - expect(selectionChangeHandler).toHaveBeenCalledTimes(1); - expect(selectionChangeHandler.mock.calls[0][0]).toEqual(['form', 'node_k1ow3cbj']); expect(selection.selected).toEqual(['form', 'node_k1ow3cbj']); - selectionChangeHandler.mockClear(); }); it('dispose 方法 - 选中的节点没有被删除的', () => { diff --git a/packages/types/src/shell/type/metadata.ts b/packages/types/src/shell/type/metadata.ts index 3122ab7d7d..573be16899 100644 --- a/packages/types/src/shell/type/metadata.ts +++ b/packages/types/src/shell/type/metadata.ts @@ -195,6 +195,9 @@ export interface IPublicTypeCallbacks { onMoveHook?: (currentNode: IPublicModelNode) => boolean; // thinkof 限制性拖拽 onHoverHook?: (currentNode: IPublicModelNode) => boolean; + + /** 选中 hook,如果返回值是 false,可以控制组件不可被选中 */ + onSelectHook?: (currentNode: IPublicModelNode) => boolean; onChildMoveHook?: (childNode: IPublicModelNode, currentNode: IPublicModelNode) => boolean; // events From 622806f59c31c7a615f01552e61c9ac8f379cd0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Mon, 5 Jun 2023 16:10:35 +0800 Subject: [PATCH 166/469] fix(code-gen): fix types error --- modules/code-generator/src/utils/expressionParser.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/code-generator/src/utils/expressionParser.ts b/modules/code-generator/src/utils/expressionParser.ts index cbc950bbc8..15320b9637 100644 --- a/modules/code-generator/src/utils/expressionParser.ts +++ b/modules/code-generator/src/utils/expressionParser.ts @@ -167,7 +167,7 @@ export function parseExpressionGetKeywords(expr: string | null | undefined): str ], }); - const addIdentifierIfNeeded = (x: Record<string, unknown> | number | null | undefined) => { + const addIdentifierIfNeeded = (x: Node | null | undefined) => { if (typeof x === 'object' && isIdentifier(x) && JS_KEYWORDS.includes(x.name)) { keywordVars.add(x.name); } @@ -189,7 +189,7 @@ export function parseExpressionGetKeywords(expr: string | null | undefined): str addIdentifierIfNeeded(item); }); } else { - addIdentifierIfNeeded(fieldValue as Record<string, unknown> | null); + addIdentifierIfNeeded(fieldValue as any); } } }); @@ -217,7 +217,7 @@ export function parseExpressionGetGlobalVariables( const ast = parser.parse(`!(${expr});`); const addUndeclaredIdentifierIfNeeded = ( - x: Record<string, unknown> | number | null | undefined, + x: Node | null | undefined, path: NodePath<Node>, ) => { if (typeof x === 'object' && isIdentifier(x) && !path.scope.hasBinding(x.name)) { @@ -241,7 +241,7 @@ export function parseExpressionGetGlobalVariables( addUndeclaredIdentifierIfNeeded(item, path); }); } else { - addUndeclaredIdentifierIfNeeded(fieldValue as Record<string, unknown> | null, path); + addUndeclaredIdentifierIfNeeded(fieldValue as any, path); } } }); From 33efde964bc9d820183adf3f152ef88ee6498b54 Mon Sep 17 00:00:00 2001 From: eternalsky <wsj7552715@hotmail.com> Date: Mon, 5 Jun 2023 18:52:41 +0800 Subject: [PATCH 167/469] fix: invalid jsx attr name error (#2131) --- modules/code-generator/src/utils/nodeToJSX.ts | 7 +- .../p0-condition-at-root.test.ts.snap | 72 +++++++++++++++++++ .../plugins/jsx/p0-condition-at-root.test.ts | 18 +++++ 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/modules/code-generator/src/utils/nodeToJSX.ts b/modules/code-generator/src/utils/nodeToJSX.ts index ad79288bab..d29f28762c 100644 --- a/modules/code-generator/src/utils/nodeToJSX.ts +++ b/modules/code-generator/src/utils/nodeToJSX.ts @@ -19,6 +19,7 @@ import { executeFunctionStack } from './aopHelper'; import { encodeJsxStringNode } from './encodeJsxAttrString'; import { unwrapJsExprQuoteInJsx } from './jsxHelpers'; import { transformThis2Context } from '../core/jsx/handlers/transformThis2Context'; +import { isValidIdentifier } from './validate'; function mergeNodeGeneratorConfig( cfg1: NodeGeneratorConfig, @@ -126,11 +127,13 @@ function generateAttrs( if (props) { if (!Array.isArray(props)) { Object.keys(props).forEach((propName: string) => { - pieces = pieces.concat(generateAttr(propName, props[propName] as IPublicTypeCompositeValue, scope, config)); + if (isValidIdentifier(propName)) { + pieces = pieces.concat(generateAttr(propName, props[propName] as IPublicTypeCompositeValue, scope, config)); + } }); } else { props.forEach((prop) => { - if (prop.name && !prop.spread) { + if (prop.name && isValidIdentifier(prop.name) && !prop.spread) { pieces = pieces.concat(generateAttr(prop.name, prop.value, scope, config)); } diff --git a/modules/code-generator/tests/plugins/jsx/__snapshots__/p0-condition-at-root.test.ts.snap b/modules/code-generator/tests/plugins/jsx/__snapshots__/p0-condition-at-root.test.ts.snap index 391e492f6e..8bce3cc106 100644 --- a/modules/code-generator/tests/plugins/jsx/__snapshots__/p0-condition-at-root.test.ts.snap +++ b/modules/code-generator/tests/plugins/jsx/__snapshots__/p0-condition-at-root.test.ts.snap @@ -281,3 +281,75 @@ Object { }, } `; + +exports[`condition at root invalid attr name should not be generated 1`] = ` +Object { + "chunks": Array [ + Object { + "content": " + const __$$context = this._context || this; + const { state } = __$$context; + return <Page><Text a={1}>Hello world!</Text></Page>; + ", + "fileType": "jsx", + "linkAfter": Array [ + "ReactComponentClassRenderStart", + "ReactComponentClassRenderPre", + ], + "name": "ReactComponentClassRenderJSX", + "type": "string", + }, + Object { + "content": " + function __$$eval(expr) { + try { + return expr(); + } catch (error) { + + } + } + + function __$$evalArray(expr) { + const res = __$$eval(expr); + return Array.isArray(res) ? res : []; + } + + + function __$$createChildContext(oldContext, ext) { + const childContext = { + ...oldContext, + ...ext, + }; + childContext.__proto__ = oldContext; + return childContext; + } + ", + "fileType": "jsx", + "linkAfter": Array [ + "CommonFileExport", + ], + "name": "CommonCustomContent", + "type": "string", + }, + ], + "contextData": Object {}, + "depNames": Array [], + "ir": Object { + "children": Array [ + Object { + "children": "Hello world!", + "componentName": "Text", + "props": Object { + "a": 1, + "a.b": 2, + }, + }, + ], + "componentName": "Page", + "condition": null, + "containerType": "Page", + "fileName": "test", + "moduleName": "test", + }, +} +`; diff --git a/modules/code-generator/tests/plugins/jsx/p0-condition-at-root.test.ts b/modules/code-generator/tests/plugins/jsx/p0-condition-at-root.test.ts index 984c848303..31e73d63ea 100644 --- a/modules/code-generator/tests/plugins/jsx/p0-condition-at-root.test.ts +++ b/modules/code-generator/tests/plugins/jsx/p0-condition-at-root.test.ts @@ -83,4 +83,22 @@ describe('condition at root', () => { }); expect(result).toMatchSnapshot(); }); + + test('invalid attr name should not be generated', async () => { + const containerIr: IContainerInfo = { + containerType: 'Page', + moduleName: 'test', + componentName: 'Page', + fileName: 'test', + condition: null, + children: [{ componentName: 'Text', children: 'Hello world!', props: { 'a': 1, 'a.b': 2 } }], + }; + const result = await jsx()({ + ir: containerIr, + contextData: {}, + chunks: [], + depNames: [], + }); + expect(result).toMatchSnapshot(); + }) }); From 76686370b98feee70c9260ebcd7334b5d6121ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Mon, 5 Jun 2023 18:59:52 +0800 Subject: [PATCH 168/469] chore(release): code-generator - 1.1.3 --- modules/code-generator/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index f830b23ede..80b2c13f2f 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-code-generator", - "version": "1.1.2", + "version": "1.1.3", "description": "出码引擎 for LowCode Engine", "license": "MIT", "main": "lib/index.js", From b50f7e1e624fad6708f3ebd42aecf826d209c610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E8=BD=A9?= <1277180540@qq.com> Date: Tue, 6 Jun 2023 14:15:28 +0800 Subject: [PATCH 169/469] docs: fix link issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit markdown语法少了个[ --- docs/docs/guide/design/renderer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/guide/design/renderer.md b/docs/docs/guide/design/renderer.md index bef13694a1..4c3021b54e 100644 --- a/docs/docs/guide/design/renderer.md +++ b/docs/docs/guide/design/renderer.md @@ -22,7 +22,7 @@ sidebar_position: 4 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01i4IiSR1cMtUFXaWQq_!!6000000003587-2-tps-1686-1062.png) -- 协议层:基于《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec) 产出的 Schema 作为我们的规范协议。 +- 协议层:基于[《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec) 产出的 Schema 作为我们的规范协议。 - 能力层:提供组件、区块、页面等渲染所需的核心能力,包括 Props 解析、样式注入、条件渲染等。 - 适配层:由于我们使用的运行时框架不是统一的,所以统一使用适配层将不同运行框架的差异部分,通过接口对外,让渲染层注册/适配对应所需的方法。能保障渲染层和能力层直接通过适配层连接起来,能起到独立可扩展的作用。 - 渲染层:提供核心的渲染方法,由于不同运行时框架提供的渲染方法是不同的,所以其通过适配层进行注入,只需要提供适配层所需的接口,即可实现渲染。 From ee0d120bbdc2c0bceb3829a2a4c3e4ca05d51e1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Wed, 7 Jun 2023 17:20:28 +0800 Subject: [PATCH 170/469] feat: add config.customPluginTransducer to debugger plugins (#2147) --- packages/designer/src/plugin/plugin-manager.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/designer/src/plugin/plugin-manager.ts b/packages/designer/src/plugin/plugin-manager.ts index 071bfa9d14..f30ccdc8f3 100644 --- a/packages/designer/src/plugin/plugin-manager.ts +++ b/packages/designer/src/plugin/plugin-manager.ts @@ -83,7 +83,10 @@ export class LowCodePluginManager implements ILowCodePluginManager { } const ctx = this._getLowCodePluginContext({ pluginName, meta }); const customFilterValidOptions = engineConfig.get('customPluginFilterOptions', filterValidOptions); - const config = pluginModel(ctx, customFilterValidOptions(options, preferenceDeclaration!)); + const pluginTransducer = engineConfig.get('customPluginTransducer', null); + const newOptions = customFilterValidOptions(options, preferenceDeclaration!); + const newPluginModel = pluginTransducer ? await pluginTransducer(pluginModel, ctx, newOptions) : pluginModel; + const config = newPluginModel(ctx, newOptions); // compat the legacy way to declare pluginName // @ts-ignore pluginName = pluginName || config.name; From dc029c252a5a135ffbce17c66040f72ea4b7fe00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Wed, 7 Jun 2023 17:21:10 +0800 Subject: [PATCH 171/469] feat(workspace): add resourceTypeList api (#2148) --- packages/shell/src/api/workspace.ts | 15 +++++++++++++++ packages/shell/src/model/resource.ts | 4 ++++ packages/types/src/shell/model/resource.ts | 2 ++ packages/workspace/src/resource.ts | 2 ++ packages/workspace/src/workspace.ts | 6 ++++-- 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index 8192ac67d4..d51f670e9d 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -34,6 +34,21 @@ export class Workspace implements IPublicApiWorkspace { return new ShellWindow(this[workspaceSymbol].window); } + get resourceTypeList() { + return Array.from(this[workspaceSymbol].resourceTypeMap.values()).map((d) => { + const { name: resourceName, type: resourceType } = d; + const { + description, + } = d.resourceTypeModel({} as any, {}); + + return { + resourceName, + resourceType, + description, + }; + }); + } + onWindowRendererReady(fn: () => void): IPublicTypeDisposable { return this[workspaceSymbol].onWindowRendererReady(fn); } diff --git a/packages/shell/src/model/resource.ts b/packages/shell/src/model/resource.ts index 43f28fbd8d..6a1a07e499 100644 --- a/packages/shell/src/model/resource.ts +++ b/packages/shell/src/model/resource.ts @@ -37,6 +37,10 @@ export class Resource implements IPublicModelResource { return this[resourceSymbol].category; } + get description() { + return this[resourceSymbol].description; + } + get children() { return this[resourceSymbol].children.map((child) => new Resource(child)); } diff --git a/packages/types/src/shell/model/resource.ts b/packages/types/src/shell/model/resource.ts index 1f59845e69..0d791412b9 100644 --- a/packages/types/src/shell/model/resource.ts +++ b/packages/types/src/shell/model/resource.ts @@ -19,6 +19,8 @@ export interface IBaseModelResource< get viewName(): string | undefined; + get description(): string | undefined; + get config(): { disableBehaviors?: ('copy' | 'remove')[]; } | undefined; diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index 4b695d036d..1d328b6c6c 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -12,6 +12,8 @@ export interface IBaseResource<T> extends IBaseModelResource<T> { skeleton: ISkeleton; + description?: string; + get editorViews(): IPublicTypeEditorView[]; get defaultViewType(): string; diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 46c8c4a0e1..bedae86801 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -33,6 +33,8 @@ export interface IWorkspace extends Omit<IPublicApiWorkspace< plugins: ILowCodePluginManager; + resourceTypeMap: Map<string, ResourceType>; + getResourceList(): IResource[]; getResourceType(resourceName: string): IResourceType; @@ -55,12 +57,12 @@ export class Workspace implements IWorkspace { enableAutoOpenFirstWindow: boolean; + resourceTypeMap: Map<string, ResourceType> = new Map(); + private emitter: IEventBus = createModuleEventBus('workspace'); private _isActive = false; - private resourceTypeMap: Map<string, ResourceType> = new Map(); - private resourceList: IResource[] = []; get skeleton() { From 182fdae78f5a37c8979d70d6f582b7bdf528d628 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Wed, 7 Jun 2023 17:31:00 +0800 Subject: [PATCH 172/469] chore(docs): publish 1.0.31 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index efac589fa9..20efc6c630 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.30", + "version": "1.0.31", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 6015c5d1d16db21f6f6f5bbd1ac9d307c5246daa Mon Sep 17 00:00:00 2001 From: xiaohuoni <xiaohuoni@dingtalk.com> Date: Wed, 7 Jun 2023 17:51:30 +0800 Subject: [PATCH 173/469] chore: set repo --- modules/code-generator/package.json | 7 ++- modules/material-parser/package.json | 8 +++- packages/designer/package.json | 4 +- packages/editor-core/package.json | 4 +- packages/editor-skeleton/package.json | 4 +- packages/engine/package.json | 4 +- packages/ignitor/package.json | 8 +++- packages/plugin-designer/package.json | 4 +- packages/plugin-outline-pane/package.json | 4 +- packages/rax-renderer/package.json | 5 ++- packages/rax-simulator-renderer/package.json | 5 ++- packages/react-renderer/package.json | 5 ++- .../react-simulator-renderer/package.json | 4 +- packages/renderer-core/package.json | 4 +- packages/shell/package.json | 4 +- packages/types/package.json | 4 +- packages/utils/package.json | 4 +- packages/workspace/package.json | 6 ++- scripts/set-repo.js | 45 +++++++++++++++++++ 19 files changed, 111 insertions(+), 22 deletions(-) create mode 100644 scripts/set-repo.js diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index 80b2c13f2f..7bcf9b1739 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -144,5 +144,10 @@ "access": "public", "registry": "https://registry.npmjs.org/" }, - "repository": "git@github.com:alibaba/lowcode-engine.git" + "repository": { + "type": "http", + "url": "https://github.com/alibaba/lowcode-engine/tree/main/modules/code-generator" + }, + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/modules/material-parser/package.json b/modules/material-parser/package.json index 7d7ea57c25..8b68c02955 100644 --- a/modules/material-parser/package.json +++ b/modules/material-parser/package.json @@ -66,5 +66,11 @@ }, "engines": { "node": ">=10.0.0" - } + }, + "repository": { + "type": "http", + "url": "https://github.com/alibaba/lowcode-engine/tree/main/modules/material-parser" + }, + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/designer/package.json b/packages/designer/package.json index 4deaa27219..fe25d1818d 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -53,5 +53,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/designer" }, - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index efb73bb2ca..64720bc033 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -47,5 +47,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/editor-core" }, - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 9199e1cb3d..cbec0fc0b2 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -42,5 +42,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/editor-skeleton" }, - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/engine/package.json b/packages/engine/package.json index 4a2d7f07a3..0df6fb6332 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -53,5 +53,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/engine" }, - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 2448ce0fc0..d81489d2d8 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -16,5 +16,11 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "fs-extra": "^10.0.0" - } + }, + "repository": { + "type": "http", + "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/ignitor" + }, + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 302d224915..65e45d9aab 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -37,5 +37,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/plugin-designer" }, - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index b191969208..74875dc9d4 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -38,5 +38,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/plugin-outline-pane" }, - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 3910afe41e..0af3a5eecf 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -48,6 +48,7 @@ "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/rax-renderer" }, "license": "MIT", - "homepage": "https://unpkg.alibaba-inc.com/@alilc/lowcode-rax-renderer@0.1.2/build/index.html", - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "homepage": "https://github.com/alibaba/lowcode-engine/#readme", + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues" } diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 0e29b10919..8513b30d39 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -49,6 +49,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/rax-simulator-renderer" }, - "homepage": "https://unpkg.alibaba-inc.com/@alilc/lowcode-rax-simulator-renderer@1.0.73/build/index.html", - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "homepage": "https://github.com/alibaba/lowcode-engine/#readme", + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues" } diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 451ef1ee3d..6039d4ceae 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -41,6 +41,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/react-renderer" }, - "homepage": "https://unpkg.alibaba-inc.com/@alilc/lowcode-react-renderer@1.0.21/build/index.html", - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "homepage": "https://github.com/alibaba/lowcode-engine/#readme", + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues" } diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index adb5526c73..2d56ffef5f 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -43,5 +43,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/react-simulator-renderer" }, - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index ce633dd546..9d5a3f3f25 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -55,5 +55,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/renderer-core" }, - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/shell/package.json b/packages/shell/package.json index 9ec85ec5c2..a885e34e7f 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -48,5 +48,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/shell" }, - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/types/package.json b/packages/types/package.json index 0b05893ca1..2888420177 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -29,5 +29,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/types" }, - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/utils/package.json b/packages/utils/package.json index 6a0880b007..cf253042f2 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -32,5 +32,7 @@ "type": "http", "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/utils" }, - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 569d652037..e0721c797e 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -47,7 +47,9 @@ }, "repository": { "type": "http", - "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/shell" + "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/workspace" }, - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6" + "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", + "bugs": "https://github.com/alibaba/lowcode-engine/issues", + "homepage": "https://github.com/alibaba/lowcode-engine/#readme" } diff --git a/scripts/set-repo.js b/scripts/set-repo.js new file mode 100644 index 0000000000..9bae66d053 --- /dev/null +++ b/scripts/set-repo.js @@ -0,0 +1,45 @@ +#!/usr/bin/env node + +const path = require('path'); +const fs = require('fs-extra'); + +(async () => { + const root = path.join(__dirname, '../'); + const workspaces = ['modules', 'packages']; + for (const workspace of workspaces) { + const pkgDir = path.join(root, workspace); + const pkgs = await fs.readdir(pkgDir); + for (const pkg of pkgs) { + if (pkg.charAt(0) === '.') continue; + if (!(await fs.statSync(path.join(pkgDir, pkg))).isDirectory()) continue; + await setRepo({ + workspace, + pkgDir, + pkg, + }); + } + } + + async function setRepo(opts) { + const pkgDir = path.join(opts.pkgDir, opts.pkg); + const pkgPkgJSONPath = path.join(pkgDir, 'package.json'); + if (!fs.existsSync(pkgPkgJSONPath)) { + console.log(`${opts.pkg} exists`); + } else { + const pkgPkgJSON = require(pkgPkgJSONPath); + fs.writeJSONSync( + pkgPkgJSONPath, + Object.assign(pkgPkgJSON, { + repository: { + type: 'http', + url: `https://github.com/alibaba/lowcode-engine/tree/main/${opts.workspace}/${opts.pkg}`, + }, + bugs: 'https://github.com/alibaba/lowcode-engine/issues', + homepage: 'https://github.com/alibaba/lowcode-engine/#readme', + }), + { spaces: ' ' }, + ); + console.log(`[Write] ${opts.pkg}`); + } + } +})(); From 7eed0966e9dded8c9024525771bf0d986e6d49c8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 7 Jun 2023 17:58:54 +0800 Subject: [PATCH 174/469] fix(outline-pane): tree does not change when doc.importSchema call --- .../src/controllers/pane-controller.ts | 8 ++++---- .../plugin-outline-pane/src/controllers/tree-node.ts | 10 ++++++---- packages/plugin-outline-pane/src/controllers/tree.ts | 4 ++++ .../plugin-outline-pane/src/views/tree-branches.tsx | 8 ++++---- packages/plugin-outline-pane/src/views/tree-node.tsx | 2 +- packages/plugin-outline-pane/src/views/tree-title.tsx | 2 +- packages/plugin-outline-pane/src/views/tree.tsx | 7 ++++++- 7 files changed, 26 insertions(+), 15 deletions(-) diff --git a/packages/plugin-outline-pane/src/controllers/pane-controller.ts b/packages/plugin-outline-pane/src/controllers/pane-controller.ts index e7c41892c6..6a9ae7c40c 100644 --- a/packages/plugin-outline-pane/src/controllers/pane-controller.ts +++ b/packages/plugin-outline-pane/src/controllers/pane-controller.ts @@ -593,7 +593,7 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTy // at this moment, it is possible that pane is not ready yet, so // put ui related operations to the next loop setTimeout(() => { - tree.setNodeSelected(treeNode.id); + tree.setNodeSelected(treeNode.nodeId); this.scrollToNode(treeNode, null, 4); }, 0); } @@ -615,21 +615,21 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTy if (!this._shell) { return undefined; } - return this._shell.querySelector(`.tree-node[data-id="${treeNode.id}"]`)?.getBoundingClientRect(); + return this._shell.querySelector(`.tree-node[data-id="${treeNode.nodeId}"]`)?.getBoundingClientRect(); } private getTreeTitleRect(treeNode: TreeNode): DOMRect | undefined { if (!this._shell) { return undefined; } - return this._shell.querySelector(`.tree-node-title[data-id="${treeNode.id}"]`)?.getBoundingClientRect(); + return this._shell.querySelector(`.tree-node-title[data-id="${treeNode.nodeId}"]`)?.getBoundingClientRect(); } private getTreeSlotsRect(treeNode: TreeNode): DOMRect | undefined { if (!this._shell) { return undefined; } - return this._shell.querySelector(`.tree-node-slots[data-id="${treeNode.id}"]`)?.getBoundingClientRect(); + return this._shell.querySelector(`.tree-node-slots[data-id="${treeNode.nodeId}"]`)?.getBoundingClientRect(); } } diff --git a/packages/plugin-outline-pane/src/controllers/tree-node.ts b/packages/plugin-outline-pane/src/controllers/tree-node.ts index 079ed77d65..92bf374d86 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-node.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-node.ts @@ -4,7 +4,7 @@ import { IPublicModelNode, IPublicTypeDisposable, } from '@alilc/lowcode-types'; -import { isI18nData, isLocationChildrenDetail } from '@alilc/lowcode-utils'; +import { isI18nData, isLocationChildrenDetail, uniqueId } from '@alilc/lowcode-utils'; import EventEmitter from 'events'; import { Tree } from './tree'; import { IOutlinePanelPluginContext } from './tree-master'; @@ -60,7 +60,9 @@ export default class TreeNode { */ private _expanded = false; - get id(): string { + id = uniqueId('treeNode'); + + get nodeId(): string { return this.node.id; } @@ -256,7 +258,7 @@ export default class TreeNode { return false; } return ( - isLocationChildrenDetail(loc.detail) && loc.detail.focus?.type === 'node' && loc.detail?.focus?.node.id === this.id + isLocationChildrenDetail(loc.detail) && loc.detail.focus?.type === 'node' && loc.detail?.focus?.node.id === this.nodeId ); } @@ -278,7 +280,7 @@ export default class TreeNode { if (!loc) { return false; } - return loc.target?.id === this.id; + return loc.target?.id === this.nodeId; } setTitleLabel(label: string) { diff --git a/packages/plugin-outline-pane/src/controllers/tree.ts b/packages/plugin-outline-pane/src/controllers/tree.ts index ab0d64b0f5..463c7919f3 100644 --- a/packages/plugin-outline-pane/src/controllers/tree.ts +++ b/packages/plugin-outline-pane/src/controllers/tree.ts @@ -45,6 +45,10 @@ export class Tree { const treeNode = this.getTreeNodeById(node.id); treeNode?.setHidden(!visible); }); + + doc?.onImportSchema(() => { + this.treeNodesMap = new Map<string, TreeNode>(); + }); } setNodeSelected(nodeId: string): void { diff --git a/packages/plugin-outline-pane/src/views/tree-branches.tsx b/packages/plugin-outline-pane/src/views/tree-branches.tsx index 2e281071bb..41bd694812 100644 --- a/packages/plugin-outline-pane/src/views/tree-branches.tsx +++ b/packages/plugin-outline-pane/src/views/tree-branches.tsx @@ -169,12 +169,12 @@ class TreeNodeChildren extends PureComponent<{ children.push(insertion); } } - groupContents.push(<TreeNodeView key={child.id} treeNode={child} isModal={isModal} />); + groupContents.push(<TreeNodeView key={child.nodeId} treeNode={child} isModal={isModal} />); } else { if (index === dropIndex) { children.push(insertion); } - children.push(<TreeNodeView key={child.id} treeNode={child} isModal={isModal} />); + children.push(<TreeNodeView key={child.nodeId} treeNode={child} isModal={isModal} />); } }); endGroup(); @@ -201,14 +201,14 @@ class TreeNodeSlots extends PureComponent<{ className={classNames('tree-node-slots', { 'insertion-at-slots': treeNode.dropDetail?.focus?.type === 'slots', })} - data-id={treeNode.id} + data-id={treeNode.nodeId} > <div className="tree-node-slots-title"> {/* @ts-ignore */} <Title title={{ type: 'i18n', intl: this.props.treeNode.pluginContext.intlNode('Slots') }} /> </div> {treeNode.slots.map(tnode => ( - <TreeNodeView key={tnode.id} treeNode={tnode} /> + <TreeNodeView key={tnode.nodeId} treeNode={tnode} /> ))} </div> ); diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx index 882fe15b1a..be6e6ae2c8 100644 --- a/packages/plugin-outline-pane/src/views/tree-node.tsx +++ b/packages/plugin-outline-pane/src/views/tree-node.tsx @@ -225,7 +225,7 @@ export default class TreeNodeView extends PureComponent<{ return ( <div className={className} - data-id={treeNode.id} + data-id={treeNode.nodeId} > <TreeTitle treeNode={treeNode} diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 6f35c6a614..6686ea3cf7 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -135,7 +135,7 @@ export default class TreeTitle extends PureComponent<{ <div className={classNames('tree-node-title', { editing })} style={style} - data-id={treeNode.id} + data-id={treeNode.nodeId} onClick={() => { if (isModal) { if (this.state.visible) { diff --git a/packages/plugin-outline-pane/src/views/tree.tsx b/packages/plugin-outline-pane/src/views/tree.tsx index 4bc5028861..675f70c2b3 100644 --- a/packages/plugin-outline-pane/src/views/tree.tsx +++ b/packages/plugin-outline-pane/src/views/tree.tsx @@ -91,7 +91,7 @@ export default class TreeView extends PureComponent<{ private onDoubleClick = (e: ReactMouseEvent) => { e.preventDefault(); const treeNode = this.getTreeNodeFromEvent(e); - if (treeNode?.id === this.state.root?.id) { + if (treeNode?.nodeId === this.state.root?.nodeId) { return; } if (!treeNode?.expanded) { @@ -188,6 +188,11 @@ export default class TreeView extends PureComponent<{ root: tree.root, }); }); + doc?.onImportSchema(() => { + this.setState({ + root: tree.root, + }); + }); } render() { From 723eb3d4d73f92d0720d0ae5208f2d37326b8677 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 8 Jun 2023 10:50:01 +0800 Subject: [PATCH 175/469] fix: fix the problem caused by props.children is [] by default in leaf --- packages/renderer-core/src/hoc/leaf.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index 432f22a5e5..bb81e88e37 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -538,7 +538,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { if (this.props.children && this.props.children.length) { return this.props.children; } - return []; + return this.props.children; } get leaf(): INode | undefined { From 0dc8120f80b50e0f2cff9bea1de21f036b54bc53 Mon Sep 17 00:00:00 2001 From: yifanwww <yifanw1101@gmail.com> Date: Fri, 9 Jun 2023 11:00:31 +0800 Subject: [PATCH 176/469] fix(lowcode-types): allow `template` field in supports.events --- packages/types/src/shell/type/metadata.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/types/src/shell/type/metadata.ts b/packages/types/src/shell/type/metadata.ts index 573be16899..c07d9802e1 100644 --- a/packages/types/src/shell/type/metadata.ts +++ b/packages/types/src/shell/type/metadata.ts @@ -139,6 +139,7 @@ export interface ConfigureSupportEventConfig { name: string; propType?: IPublicTypePropType; description?: string; + template?: string; } /** From 343954009e920e5db5139df5b9267eae2babb291 Mon Sep 17 00:00:00 2001 From: ChiZng <smile_zchi@163.com> Date: Fri, 9 Jun 2023 15:52:27 +0800 Subject: [PATCH 177/469] =?UTF-8?q?doc(projectapi):=20=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E7=9A=84getCurrentDocument=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/api/project.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/docs/docs/api/project.md b/docs/docs/api/project.md index e31672e25f..7998228e2b 100644 --- a/docs/docs/api/project.md +++ b/docs/docs/api/project.md @@ -182,19 +182,6 @@ importSchema(schema?: IPublicTypeProjectSchema): void; ``` 相关类型:[IPublicTypeProjectSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/project-schema.ts) -### getCurrentDocument -获取当前的 document - -```typescript -/** - * 获取当前的 document - * get current document - * @returns - */ -getCurrentDocument(): IPublicModelDocumentModel | null; -``` -相关类型:[IPublicModelDocumentModel](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/document-model.ts) - ### addPropsTransducer 增加一个属性的管道处理函数 From 3a21709e585f6af7dc8ead1f5beb4c15cd5a2eb9 Mon Sep 17 00:00:00 2001 From: eternalsky <wsj7552715@hotmail.com> Date: Fri, 9 Jun 2023 17:26:02 +0800 Subject: [PATCH 178/469] fix(code-generator): upgrade prettier parser from babel to babel-ts, fix some ts parse error (#2166) --- modules/code-generator/src/postprocessor/prettier/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/src/postprocessor/prettier/index.ts b/modules/code-generator/src/postprocessor/prettier/index.ts index 075fc66e7a..079c45582e 100644 --- a/modules/code-generator/src/postprocessor/prettier/index.ts +++ b/modules/code-generator/src/postprocessor/prettier/index.ts @@ -21,7 +21,7 @@ const factory: PostProcessorFactory<ProcessorConfig> = (config?: ProcessorConfig const codePrettier: PostProcessor = (content: string, fileType: string) => { let parser: prettier.BuiltInParserName | any; if (fileType === 'js' || fileType === 'jsx' || fileType === 'ts' || fileType === 'tsx') { - parser = 'babel'; + parser = 'babel-ts'; } else if (fileType === 'json') { parser = 'json-stringify'; } else if (PARSERS.indexOf(fileType) >= 0) { From 9ccf8536244dc20e4029819ed50c7263d0c8f640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Fri, 9 Jun 2023 17:26:51 +0800 Subject: [PATCH 179/469] chore(release): code-generator - 1.1.4 --- modules/code-generator/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index 7bcf9b1739..ce01f5e4e1 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-code-generator", - "version": "1.1.3", + "version": "1.1.4", "description": "出码引擎 for LowCode Engine", "license": "MIT", "main": "lib/index.js", From 16f5ee71e4e897228e288d3bd832f13e6dce8639 Mon Sep 17 00:00:00 2001 From: stefan-ysh <58702199+stefan-ysh@users.noreply.github.com> Date: Sun, 11 Jun 2023 18:24:02 +0800 Subject: [PATCH 180/469] fix: Corrected a misspelling in the docs --- docs/docs/guide/design/setter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/guide/design/setter.md b/docs/docs/guide/design/setter.md index 968e7bbf8c..7afbbf034f 100644 --- a/docs/docs/guide/design/setter.md +++ b/docs/docs/guide/design/setter.md @@ -32,7 +32,7 @@ sidebar_position: 6 ### SettingTarget 抽象 -如果不是多选,可以直接暴露 `Node` 给到这,但涉及多选编辑的时候,大家的值时通常是不一样的,设置的时候需要批量设置进去,这里主要封装这些逻辑,把多选编辑的复杂性屏蔽掉。 +如果不是多选,可以直接暴露 `Node` 给到这,但涉及多选编辑的时候,大家的值通常是不一样的,设置的时候需要批量设置进去,这里主要封装这些逻辑,把多选编辑的复杂性屏蔽掉。 所选节点所构成的**设置对象**抽象如下: From c838dc70eb71e4aaae37494baf7f3a1d3fec8340 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 12 Jun 2023 11:29:22 +0800 Subject: [PATCH 181/469] feat(workspace): add editorViews to resourceTypeList api --- packages/shell/src/api/workspace.ts | 7 +++++++ packages/shell/src/model/editor-view.ts | 8 ++++++++ packages/types/src/shell/model/editor-view.ts | 6 +++++- packages/workspace/src/context/view-context.ts | 2 ++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index d51f670e9d..1a16d31ce8 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -39,12 +39,19 @@ export class Workspace implements IPublicApiWorkspace { const { name: resourceName, type: resourceType } = d; const { description, + editorViews, } = d.resourceTypeModel({} as any, {}); return { resourceName, resourceType, description, + editorViews: editorViews.map(d => ( + { + viewName: d.viewName, + viewType: d.viewType || 'editor', + } + )), }; }); } diff --git a/packages/shell/src/model/editor-view.ts b/packages/shell/src/model/editor-view.ts index d70a109b1d..92d1a57726 100644 --- a/packages/shell/src/model/editor-view.ts +++ b/packages/shell/src/model/editor-view.ts @@ -24,4 +24,12 @@ export class EditorView { }, }); } + + get viewName() { + return this[editorViewSymbol].viewName; + } + + get viewType() { + return this[editorViewSymbol].viewType; + } } diff --git a/packages/types/src/shell/model/editor-view.ts b/packages/types/src/shell/model/editor-view.ts index 793417845b..d51e4f9ff2 100644 --- a/packages/types/src/shell/model/editor-view.ts +++ b/packages/types/src/shell/model/editor-view.ts @@ -1,3 +1,7 @@ import { IPublicModelPluginContext } from './plugin-context'; -export interface IPublicModelEditorView extends IPublicModelPluginContext {} \ No newline at end of file +export interface IPublicModelEditorView extends IPublicModelPluginContext { + viewName: string; + + viewType: 'editor' | 'webview'; +} \ No newline at end of file diff --git a/packages/workspace/src/context/view-context.ts b/packages/workspace/src/context/view-context.ts index ff4c12eeea..0542f83a95 100644 --- a/packages/workspace/src/context/view-context.ts +++ b/packages/workspace/src/context/view-context.ts @@ -10,6 +10,8 @@ export interface IViewContext extends IBasicContext { editorWindow: IEditorWindow; viewName: string; + + viewType: 'editor' | 'webview'; } export class Context extends BasicContext implements IViewContext { From 11b929b42fb3baf76daed473fa3f76cb431c56f8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 12 Jun 2023 14:45:10 +0800 Subject: [PATCH 182/469] fix(render-core): fix when designMode is false & loop is null, isUseLoop should return true --- packages/renderer-core/jest.config.js | 1 + packages/renderer-core/src/utils/is-use-loop.ts | 8 ++++---- packages/renderer-core/tests/utils/is-use-loop.test.ts | 6 ++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/renderer-core/jest.config.js b/packages/renderer-core/jest.config.js index e3267c5177..1ea4204de5 100644 --- a/packages/renderer-core/jest.config.js +++ b/packages/renderer-core/jest.config.js @@ -13,6 +13,7 @@ const jestConfig = { // testMatch: ['**/*/base.test.tsx'], // testMatch: ['**/utils/common.test.ts'], // testMatch: ['**/*/leaf.test.tsx'], + // testMatch: ['**/*/is-use-loop.test.ts'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], diff --git a/packages/renderer-core/src/utils/is-use-loop.ts b/packages/renderer-core/src/utils/is-use-loop.ts index 509450d942..b6d67a802a 100644 --- a/packages/renderer-core/src/utils/is-use-loop.ts +++ b/packages/renderer-core/src/utils/is-use-loop.ts @@ -8,13 +8,13 @@ export default function isUseLoop(loop: null | any[] | IPublicTypeJSExpression, return true; } - if (!Array.isArray(loop)) { - return false; - } - if (!isDesignMode) { return true; } + if (!Array.isArray(loop)) { + return false; + } + return loop.length > 0; } diff --git a/packages/renderer-core/tests/utils/is-use-loop.test.ts b/packages/renderer-core/tests/utils/is-use-loop.test.ts index 5f502a2e5b..b0a614f2ee 100644 --- a/packages/renderer-core/tests/utils/is-use-loop.test.ts +++ b/packages/renderer-core/tests/utils/is-use-loop.test.ts @@ -5,6 +5,9 @@ describe('base test', () => { it('designMode is true', () => { expect(isUseLoop([], true)).toBeFalsy(); expect(isUseLoop([{}], true)).toBeTruthy(); + expect(isUseLoop(null, true)).toBeFalsy(); + expect(isUseLoop(undefined, true)).toBeFalsy(); + expect(isUseLoop(0, true)).toBeFalsy(); }); it('loop is expression', () => { @@ -21,5 +24,8 @@ describe('base test', () => { it('designMode is false', () => { expect(isUseLoop([], false)).toBeTruthy(); expect(isUseLoop([{}], false)).toBeTruthy(); + expect(isUseLoop(null, false)).toBeTruthy(); + expect(isUseLoop(undefined, false)).toBeTruthy(); + expect(isUseLoop(0, false)).toBeTruthy(); }); }); From f81954fda5113255e0581542e9668aa264b798a8 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 13 Jun 2023 11:38:35 +0800 Subject: [PATCH 183/469] chore(docs): publish 1.0.32 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 20efc6c630..f8617eac0a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.31", + "version": "1.0.32", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 48acc2d2e8c5180a240b9be705fe090274fc82be Mon Sep 17 00:00:00 2001 From: eightHundreds <mingoing@outlook.com> Date: Thu, 15 Jun 2023 09:59:53 +0800 Subject: [PATCH 184/469] feat: make appHelper observable (#2186) * feat: make appHelper observable --- .../designer/src/builtin-simulator/host.ts | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index fdf26c06c1..cdb7642a5a 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -14,6 +14,7 @@ import { createModuleEventBus, IEventBus, } from '@alilc/lowcode-editor-core'; + import { ISimulatorHost, Component, @@ -265,6 +266,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp @obx.ref private _contentDocument?: Document; + @obx.ref private _appHelper?: any; + get contentDocument() { return this._contentDocument; } @@ -310,13 +313,19 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp this.designer = designer; this.scroller = this.designer.createScroller(this.viewport); this.autoRender = !engineConfig.get('disableAutoRender', false); + this._appHelper = engineConfig.get('appHelper'); this.componentsConsumer = new ResourceConsumer<Asset | undefined>(() => this.componentsAsset); this.injectionConsumer = new ResourceConsumer(() => { return { - appHelper: engineConfig.get('appHelper'), + appHelper: this._appHelper, }; }); + engineConfig.onGot('appHelper', (data) => { + // appHelper被config.set修改后触发injectionConsumer.consume回调 + this._appHelper = data; + }); + this.i18nConsumer = new ResourceConsumer(() => this.project.i18n); transactionManager.onStartTransaction(() => { @@ -384,6 +393,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp purge(): void { // todo + } mountViewport(viewport: HTMLElement | null) { @@ -494,7 +504,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp if (Object.keys(this.asyncLibraryMap).length > 0) { // 加载异步 Library await renderer.loadAsyncLibrary(this.asyncLibraryMap); - Object.keys(this.asyncLibraryMap).forEach(key => { + Object.keys(this.asyncLibraryMap).forEach((key) => { delete this.asyncLibraryMap[key]; }); } @@ -521,7 +531,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp if (Object.keys(this.asyncLibraryMap).length > 0) { // 加载异步 Library await this.renderer?.loadAsyncLibrary(this.asyncLibraryMap); - Object.keys(this.asyncLibraryMap).forEach(key => { + Object.keys(this.asyncLibraryMap).forEach((key) => { delete this.asyncLibraryMap[key]; }); } @@ -680,7 +690,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp const x = new Event('click'); x.initEvent('click', true); this._iframe?.dispatchEvent(x); - const target = e.target; + const { target } = e; const customizeIgnoreSelectors = engineConfig.get('customizeIgnoreSelectors'); // TODO: need more elegant solution to ignore click events of components in designer @@ -1497,7 +1507,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp handleAccept({ container }: DropContainer, e: ILocateEvent): boolean { const { dragObject } = e; const document = this.currentDocument!; - const focusNode = document.focusNode; + const { focusNode } = document; if (isRootNode(container) || container.contains(focusNode)) { return document.checkNesting(focusNode!, dragObject as any); } From b6313c0460f9f825920594329c53502fa93233e5 Mon Sep 17 00:00:00 2001 From: LiGuangNian <792841450@qq.com> Date: Mon, 26 Jun 2023 12:19:13 +0800 Subject: [PATCH 185/469] Update material.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit loadIncrementalAssets返回的应当是Promise<void> --- docs/docs/api/material.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index 5a5502fda6..2bf99577cb 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -102,7 +102,7 @@ material.getAssets(); * @param incrementalAssets * @returns */ -loadIncrementalAssets(incrementalAssets: IPublicTypeAssetsJson): void; +loadIncrementalAssets(incrementalAssets: IPublicTypeAssetsJson): Promise<void>; ``` 相关类型:[IPublicTypeAssetsJson](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/assets-json.ts) From 88008a7933a6a829233d770544bf82249f2dd290 Mon Sep 17 00:00:00 2001 From: Rainke <woshihepeng520@163.com> Date: Mon, 26 Jun 2023 17:24:23 +0800 Subject: [PATCH 186/469] remove duplicate code --- packages/engine/src/engine-core.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 84dfd67aa8..204b9b30ab 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -83,7 +83,6 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins plugins.delete(componentMetaParserPlugin.pluginName); plugins.delete(setterRegistry.pluginName); plugins.delete(defaultPanelRegistryPlugin.pluginName); - plugins.delete(defaultPanelRegistryPlugin.pluginName); plugins.delete(builtinHotkey.pluginName); plugins.delete(registerDefaults.pluginName); }; From 731dc58649ffa68a528c7b97e770f03e4252c2c8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 27 Jun 2023 14:07:07 +0800 Subject: [PATCH 187/469] fix: lerna version to 4.0.0 --- packages/types/src/shell/type/node-schema.ts | 11 +++++++---- scripts/setup-skip-build.sh | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/types/src/shell/type/node-schema.ts b/packages/types/src/shell/type/node-schema.ts index b2520ee385..9cbd0a81ac 100644 --- a/packages/types/src/shell/type/node-schema.ts +++ b/packages/types/src/shell/type/node-schema.ts @@ -5,11 +5,14 @@ import { IPublicTypeCompositeValue, IPublicTypePropsMap, IPublicTypeNodeData } f * 搭建基础协议 - 单个组件树节点描述 */ export interface IPublicTypeNodeSchema { + id?: string; + /** * 组件名称 必填、首字母大写 */ componentName: string; + /** * 组件属性对象 */ @@ -17,26 +20,26 @@ export interface IPublicTypeNodeSchema { children?: IPublicTypeNodeData | IPublicTypeNodeData[]; } & IPublicTypePropsMap; // | PropsList; - /** - * 组件属性对象 - */ - leadingComponents?: string; /** * 渲染条件 */ condition?: IPublicTypeCompositeValue; + /** * 循环数据 */ loop?: IPublicTypeCompositeValue; + /** * 循环迭代对象、索引名称 ["item", "index"] */ loopArgs?: [string, string]; + /** * 子节点 */ children?: IPublicTypeNodeData | IPublicTypeNodeData[]; + /** * 是否锁定 */ diff --git a/scripts/setup-skip-build.sh b/scripts/setup-skip-build.sh index d51c33c417..7c0ff6a273 100755 --- a/scripts/setup-skip-build.sh +++ b/scripts/setup-skip-build.sh @@ -1,6 +1,9 @@ #!/usr/bin/env bash rm -rf node_modules package-lock.json yarn.lock + +npm i lerna@4.0.0 + lerna clean -y find ./packages -type f -name "package-lock.json" -exec rm -f {} \; From 30686a5bb8b99ee984d22d2de0d5f79849764624 Mon Sep 17 00:00:00 2001 From: Rainke <woshihepeng520@163.com> Date: Tue, 27 Jun 2023 17:28:13 +0800 Subject: [PATCH 188/469] fix: the selectionDispose function is never executed --- packages/designer/src/designer/designer.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 74c1f51b25..784ebf57bc 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -144,6 +144,8 @@ export class Designer implements IDesigner { private oobxList: OffsetObserver[] = []; + private selectionDispose: undefined | (() => void); + @obx.ref private _componentMetasMap = new Map<string, IComponentMeta>(); @obx.ref private _simulatorComponent?: ComponentType<any>; @@ -265,10 +267,9 @@ export class Designer implements IDesigner { } setupSelection = () => { - let selectionDispose: undefined | (() => void); - if (selectionDispose) { - selectionDispose(); - selectionDispose = undefined; + if (this.selectionDispose) { + this.selectionDispose(); + this.selectionDispose = undefined; } const { currentSelection } = this; // TODO: 避免选中 Page 组件,默认选中第一个子节点;新增规则 或 判断 Live 模式 @@ -284,7 +285,7 @@ export class Designer implements IDesigner { } this.postEvent('selection.change', currentSelection); if (currentSelection) { - selectionDispose = currentSelection.onSelectionChange(() => { + this.selectionDispose = currentSelection.onSelectionChange(() => { this.postEvent('selection.change', currentSelection); }); } From a1a50f25704a56e045d6d645eea4179c25ee60ac Mon Sep 17 00:00:00 2001 From: eightHundreds <mingoing@outlook.com> Date: Fri, 30 Jun 2023 14:27:50 +0800 Subject: [PATCH 189/469] fix: change the return result type to Promise --- packages/types/src/shell/type/plugin-config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/types/src/shell/type/plugin-config.ts b/packages/types/src/shell/type/plugin-config.ts index 8a533f8fe1..e9e65192e0 100644 --- a/packages/types/src/shell/type/plugin-config.ts +++ b/packages/types/src/shell/type/plugin-config.ts @@ -1,5 +1,5 @@ export interface IPublicTypePluginConfig { - init(): void; - destroy?(): void; + init(): Promise<void>; + destroy?(): Promise<void>; exports?(): any; } From cb2e05046f417422d9da98a9e255e9f49a895d6d Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 4 Jul 2023 09:51:17 +0800 Subject: [PATCH 190/469] feat: add document-model shell return types --- docs/docs/api/model/document-model.md | 6 ++++-- packages/shell/src/model/document-model.ts | 2 +- packages/types/src/shell/model/document-model.ts | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/docs/api/model/document-model.md b/docs/docs/api/model/document-model.md index b609f00504..8d813e7678 100644 --- a/docs/docs/api/model/document-model.md +++ b/docs/docs/api/model/document-model.md @@ -139,10 +139,12 @@ importSchema(schema: IPublicTypeRootSchema): void; * @param stage * @returns */ -exportSchema(stage: IPublicEnumTransformStage): any; +exportSchema(stage: IPublicEnumTransformStage): IPublicTypeRootSchema | undefined; ``` -相关类型:[IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts) +相关类型: +- [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 diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts index 06f3cebcd9..2c5c7b632e 100644 --- a/packages/shell/src/model/document-model.ts +++ b/packages/shell/src/model/document-model.ts @@ -164,7 +164,7 @@ export class DocumentModel implements IPublicModelDocumentModel { * @param stage * @returns */ - exportSchema(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render): any { + exportSchema(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render): IPublicTypeRootSchema | undefined { return this[documentSymbol].export(stage); } diff --git a/packages/types/src/shell/model/document-model.ts b/packages/types/src/shell/model/document-model.ts index 2ef0b532be..4c9344eb48 100644 --- a/packages/types/src/shell/model/document-model.ts +++ b/packages/types/src/shell/model/document-model.ts @@ -89,7 +89,7 @@ export interface IPublicModelDocumentModel< * @param stage * @returns */ - exportSchema(stage: IPublicEnumTransformStage): any; + exportSchema(stage: IPublicEnumTransformStage): IPublicTypeRootSchema | undefined; /** * 插入节点 From 323e85f595e3efb5f54caf3ec8350108465df531 Mon Sep 17 00:00:00 2001 From: BARM <chenglin@dian.so> Date: Thu, 6 Jul 2023 11:18:31 +0800 Subject: [PATCH 191/469] fix(code-gen): fix example-solution.ts format problem (#2207) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 林熠 <jack.lianjie@gmail.com> --- modules/code-generator/src/cli/solutions/example-solution.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/code-generator/src/cli/solutions/example-solution.ts b/modules/code-generator/src/cli/solutions/example-solution.ts index fe303f360f..0314151c6e 100644 --- a/modules/code-generator/src/cli/solutions/example-solution.ts +++ b/modules/code-generator/src/cli/solutions/example-solution.ts @@ -289,8 +289,8 @@ codealike.json }, "lifeCycles": { "componentDidMount": { - "type": "JSExpression", - "value": "function() { console.log('componentDidMount'); }" + "type": "JSFunction", + "value": "function componentDidMount() {\\n console.log('componentDidMount');\\n}" } }, "methodsModule": { From 11501e836d150d444c0d6370e6d5f533132a3738 Mon Sep 17 00:00:00 2001 From: BARM <chenglin@dian.so> Date: Thu, 6 Jul 2023 11:20:07 +0800 Subject: [PATCH 192/469] chore(code-gen): export containerInjectConstants function (#2206) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 林熠 <jack.lianjie@gmail.com> --- modules/code-generator/src/solutions/icejs.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/code-generator/src/solutions/icejs.ts b/modules/code-generator/src/solutions/icejs.ts index 6f5bdde599..7dc44f4bec 100644 --- a/modules/code-generator/src/solutions/icejs.ts +++ b/modules/code-generator/src/solutions/icejs.ts @@ -100,11 +100,12 @@ export default function createIceJsProjectBuilder( export const plugins = { containerClass, - containerInitState, containerInjectContext, containerInjectUtils, - containerInjectI18n, containerInjectDataSourceEngine, + containerInjectI18n, + containerInjectConstants, + containerInitState, containerLifeCycle, containerMethod, jsx, From 5cc4715daf510a64b6bf10c51b3a12df2bc62a36 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 7 Jul 2023 17:34:57 +0800 Subject: [PATCH 193/469] chore(release): publish 1.1.8 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 67ffb648e2..52ee714c28 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.7", + "version": "1.1.8", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index fe25d1818d..e3d1535aa5 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.7", + "version": "1.1.8", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -16,9 +16,9 @@ "license": "MIT", "dependencies": { "@alilc/build-plugin-lce": "^0.0.4-beta.2", - "@alilc/lowcode-editor-core": "1.1.7", - "@alilc/lowcode-types": "1.1.7", - "@alilc/lowcode-utils": "1.1.7", + "@alilc/lowcode-editor-core": "1.1.8", + "@alilc/lowcode-types": "1.1.8", + "@alilc/lowcode-utils": "1.1.8", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 64720bc033..939a73183b 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.1.7", + "version": "1.1.8", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.7", - "@alilc/lowcode-utils": "1.1.7", + "@alilc/lowcode-types": "1.1.8", + "@alilc/lowcode-utils": "1.1.8", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index cbec0fc0b2..16cc1cc098 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.1.7", + "version": "1.1.8", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.1.7", - "@alilc/lowcode-editor-core": "1.1.7", - "@alilc/lowcode-types": "1.1.7", - "@alilc/lowcode-utils": "1.1.7", + "@alilc/lowcode-designer": "1.1.8", + "@alilc/lowcode-editor-core": "1.1.8", + "@alilc/lowcode-types": "1.1.8", + "@alilc/lowcode-utils": "1.1.8", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 0df6fb6332..030f14a764 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.7", + "version": "1.1.8", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.1.7", - "@alilc/lowcode-editor-core": "1.1.7", - "@alilc/lowcode-editor-skeleton": "1.1.7", + "@alilc/lowcode-designer": "1.1.8", + "@alilc/lowcode-editor-core": "1.1.8", + "@alilc/lowcode-editor-skeleton": "1.1.8", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.7", - "@alilc/lowcode-plugin-outline-pane": "1.1.7", - "@alilc/lowcode-shell": "1.1.7", - "@alilc/lowcode-utils": "1.1.7", - "@alilc/lowcode-workspace": "1.1.7", + "@alilc/lowcode-plugin-designer": "1.1.8", + "@alilc/lowcode-plugin-outline-pane": "1.1.8", + "@alilc/lowcode-shell": "1.1.8", + "@alilc/lowcode-utils": "1.1.8", + "@alilc/lowcode-workspace": "1.1.8", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index d81489d2d8..d7796db32f 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.7", + "version": "1.1.8", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 65e45d9aab..7d5a434811 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.1.7", + "version": "1.1.8", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.7", - "@alilc/lowcode-editor-core": "1.1.7", - "@alilc/lowcode-utils": "1.1.7", + "@alilc/lowcode-designer": "1.1.8", + "@alilc/lowcode-editor-core": "1.1.8", + "@alilc/lowcode-utils": "1.1.8", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 74875dc9d4..f6a4aea0a5 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.1.7", + "version": "1.1.8", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.7", - "@alilc/lowcode-utils": "1.1.7", + "@alilc/lowcode-types": "1.1.8", + "@alilc/lowcode-utils": "1.1.8", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 0af3a5eecf..b91511afd7 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.1.7", + "version": "1.1.8", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.1.7", - "@alilc/lowcode-utils": "1.1.7", + "@alilc/lowcode-renderer-core": "1.1.8", + "@alilc/lowcode-utils": "1.1.8", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 8513b30d39..8a456b6cf4 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.1.7", + "version": "1.1.8", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.7", - "@alilc/lowcode-rax-renderer": "1.1.7", - "@alilc/lowcode-types": "1.1.7", - "@alilc/lowcode-utils": "1.1.7", + "@alilc/lowcode-designer": "1.1.8", + "@alilc/lowcode-rax-renderer": "1.1.8", + "@alilc/lowcode-types": "1.1.8", + "@alilc/lowcode-utils": "1.1.8", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 6039d4ceae..4af63fa78b 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.1.7", + "version": "1.1.8", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.1.7" + "@alilc/lowcode-renderer-core": "1.1.8" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 2d56ffef5f..43bfd47a87 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.1.7", + "version": "1.1.8", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.7", - "@alilc/lowcode-react-renderer": "1.1.7", - "@alilc/lowcode-types": "1.1.7", - "@alilc/lowcode-utils": "1.1.7", + "@alilc/lowcode-designer": "1.1.8", + "@alilc/lowcode-react-renderer": "1.1.8", + "@alilc/lowcode-types": "1.1.8", + "@alilc/lowcode-utils": "1.1.8", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 9d5a3f3f25..f0b4b3e9cb 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.1.7", + "version": "1.1.8", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.1.7", - "@alilc/lowcode-utils": "1.1.7", + "@alilc/lowcode-types": "1.1.8", + "@alilc/lowcode-utils": "1.1.8", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.1.7", + "@alilc/lowcode-designer": "1.1.8", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index a885e34e7f..c24113d0fe 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.7", + "version": "1.1.8", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.7", - "@alilc/lowcode-editor-core": "1.1.7", - "@alilc/lowcode-editor-skeleton": "1.1.7", - "@alilc/lowcode-types": "1.1.7", - "@alilc/lowcode-utils": "1.1.7", - "@alilc/lowcode-workspace": "1.1.7", + "@alilc/lowcode-designer": "1.1.8", + "@alilc/lowcode-editor-core": "1.1.8", + "@alilc/lowcode-editor-skeleton": "1.1.8", + "@alilc/lowcode-types": "1.1.8", + "@alilc/lowcode-utils": "1.1.8", + "@alilc/lowcode-workspace": "1.1.8", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 2888420177..2aef9019c3 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.7", + "version": "1.1.8", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index cf253042f2..1e4e9fb9f9 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.7", + "version": "1.1.8", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.7", + "@alilc/lowcode-types": "1.1.8", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index e0721c797e..b04a05cf94 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.7", + "version": "1.1.8", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.7", - "@alilc/lowcode-editor-core": "1.1.7", - "@alilc/lowcode-editor-skeleton": "1.1.7", - "@alilc/lowcode-types": "1.1.7", - "@alilc/lowcode-utils": "1.1.7", + "@alilc/lowcode-designer": "1.1.8", + "@alilc/lowcode-editor-core": "1.1.8", + "@alilc/lowcode-editor-skeleton": "1.1.8", + "@alilc/lowcode-types": "1.1.8", + "@alilc/lowcode-utils": "1.1.8", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From eb3b5709c597276075ac928a1f0f2e82e6adad38 Mon Sep 17 00:00:00 2001 From: liangzr <1668890395@qq.com> Date: Fri, 7 Jul 2023 11:28:02 +0800 Subject: [PATCH 194/469] feat: listen for the logic of requestHandlersMap config update --- packages/plugin-designer/src/index.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/plugin-designer/src/index.tsx b/packages/plugin-designer/src/index.tsx index 54eda13651..90eefaaba5 100644 --- a/packages/plugin-designer/src/index.tsx +++ b/packages/plugin-designer/src/index.tsx @@ -67,6 +67,11 @@ export default class DesignerPlugin extends PureComponent<PluginProps, DesignerP locale, }); }); + engineConfig.onGot('requestHandlersMap', (requestHandlersMap) => { + this.setState({ + requestHandlersMap, + }); + }); const { components, packages, extraEnvironment, utils } = assets; const state = { componentMetadatas: components || [], From 7b6181719e28b3b56e71f84266a550d14f8d9bba Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 10 Jul 2023 15:36:34 +0800 Subject: [PATCH 195/469] feat(workspace): add multi foces-tracker in workspace mode --- packages/designer/src/builtin-simulator/host.ts | 4 ++-- .../designer/tests/builtin-simulator/host.test.ts | 5 +++++ packages/editor-core/src/utils/focus-tracker.ts | 12 ++++-------- .../editor-skeleton/src/layouts/left-float-pane.tsx | 4 ++-- packages/editor-skeleton/src/skeleton.ts | 7 ++++++- packages/workspace/src/layouts/left-float-pane.tsx | 4 ++-- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index cdb7642a5a..5e6fc06a62 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -4,7 +4,6 @@ import { reaction, computed, getPublicPath, - focusTracker, engineConfig, globalLocale, IReactionPublic, @@ -519,7 +518,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp // bind hotkey & clipboard const hotkey = this.designer.editor.get('innerHotkey'); hotkey.mount(this._contentWindow); - focusTracker.mount(this._contentWindow); + const innerSkeleton = this.designer.editor.get('skeleton'); + innerSkeleton.focusTracker.mount(this._contentWindow); clipboard.injectCopyPaster(this._contentDocument); // TODO: dispose the bindings diff --git a/packages/designer/tests/builtin-simulator/host.test.ts b/packages/designer/tests/builtin-simulator/host.test.ts index 57e74be579..d74c31d42c 100644 --- a/packages/designer/tests/builtin-simulator/host.test.ts +++ b/packages/designer/tests/builtin-simulator/host.test.ts @@ -24,6 +24,9 @@ import { fireEvent } from '@testing-library/react'; import { shellModelFactory } from '../../../engine/src/modules/shell-model-factory'; import { Setters, Workspace } from '@alilc/lowcode-shell'; import { ILowCodePluginContextApiAssembler, ILowCodePluginContextPrivate, LowCodePluginManager } from '@alilc/lowcode-designer'; +import { + Skeleton as InnerSkeleton, +} from '@alilc/lowcode-editor-skeleton'; describe('Host 测试', () => { let editor: Editor; @@ -45,6 +48,8 @@ describe('Host 测试', () => { const innerPlugins = new LowCodePluginManager(pluginContextApiAssembler); const innerWorkspace = new InnerWorkspace(() => {}, {}); const workspace = new Workspace(innerWorkspace); + const innerSkeleton = new InnerSkeleton(editor); + editor.set('skeleton' as any, innerSkeleton); editor.set('innerHotkey', new InnerHotkey()) editor.set('setters', new Setters(new InnerSetters())); editor.set('innerPlugins' as any, innerPlugins); diff --git a/packages/editor-core/src/utils/focus-tracker.ts b/packages/editor-core/src/utils/focus-tracker.ts index cb88dfc567..23d509053b 100644 --- a/packages/editor-core/src/utils/focus-tracker.ts +++ b/packages/editor-core/src/utils/focus-tracker.ts @@ -1,4 +1,8 @@ export class FocusTracker { + private actives: Focusable[] = []; + + private modals: Array<{ checkDown: (e: MouseEvent) => boolean; checkOpen: () => boolean }> = []; + mount(win: Window) { const checkDown = (e: MouseEvent) => { if (this.checkModalDown(e)) { @@ -16,14 +20,10 @@ export class FocusTracker { }; } - private actives: Focusable[] = []; - get first() { return this.actives[0]; } - private modals: Array<{ checkDown: (e: MouseEvent) => boolean; checkOpen: () => boolean }> = []; - addModal(checkDown: (e: MouseEvent) => boolean, checkOpen: () => boolean) { this.modals.push({ checkDown, @@ -154,7 +154,3 @@ export class Focusable { } } } - -export const focusTracker = new FocusTracker(); - -focusTracker.mount(window); diff --git a/packages/editor-skeleton/src/layouts/left-float-pane.tsx b/packages/editor-skeleton/src/layouts/left-float-pane.tsx index 0be5ea6c3f..7df6993bb5 100644 --- a/packages/editor-skeleton/src/layouts/left-float-pane.tsx +++ b/packages/editor-skeleton/src/layouts/left-float-pane.tsx @@ -1,6 +1,6 @@ import { Component, Fragment } from 'react'; import classNames from 'classnames'; -import { observer, Focusable, focusTracker } from '@alilc/lowcode-editor-core'; +import { observer, Focusable } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; import { Panel } from '../widget/panel'; import { PanelConfig } from '../types'; @@ -31,7 +31,7 @@ export default class LeftFloatPane extends Component<{ area: Area<PanelConfig, P area.skeleton.editor.removeListener('designer.drag', triggerClose); }; - this.focusing = focusTracker.create({ + this.focusing = area.skeleton.focusTracker.create({ range: (e) => { const target = e.target as HTMLElement; if (!target) { diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 616e7f0172..8836434049 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -1,4 +1,4 @@ -import { action, makeObservable, obx, engineConfig, IEditor } from '@alilc/lowcode-editor-core'; +import { action, makeObservable, obx, engineConfig, IEditor, FocusTracker } from '@alilc/lowcode-editor-core'; import { DockConfig, PanelConfig, @@ -83,6 +83,8 @@ export interface ISkeleton extends Omit<IPublicApiSkeleton, readonly widgets: IWidget[]; + readonly focusTracker: FocusTracker; + getPanel(name: string): Panel | undefined; getWidget(name: string): IWidget | undefined; @@ -133,6 +135,8 @@ export class Skeleton { readonly widgets: IWidget[] = []; + readonly focusTracker = new FocusTracker(); + constructor(readonly editor: IEditor, readonly viewName: string = 'global') { makeObservable(this); this.leftArea = new Area( @@ -245,6 +249,7 @@ export class Skeleton { this.setupPlugins(); this.setupEvents(); + this.focusTracker.mount(window); } /** diff --git a/packages/workspace/src/layouts/left-float-pane.tsx b/packages/workspace/src/layouts/left-float-pane.tsx index 832c2598ca..38f70b386d 100644 --- a/packages/workspace/src/layouts/left-float-pane.tsx +++ b/packages/workspace/src/layouts/left-float-pane.tsx @@ -1,6 +1,6 @@ import { Component, Fragment } from 'react'; import classNames from 'classnames'; -import { observer, Focusable, focusTracker } from '@alilc/lowcode-editor-core'; +import { observer, Focusable } from '@alilc/lowcode-editor-core'; import { Area, Panel } from '@alilc/lowcode-editor-skeleton'; @observer @@ -29,7 +29,7 @@ export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }> area.skeleton.editor.removeListener('designer.drag', triggerClose); }; - this.focusing = focusTracker.create({ + this.focusing = area.skeleton.focusTracker.create({ range: (e) => { const target = e.target as HTMLElement; if (!target) { From 7d7042f79921283e8d04aa5ff8d9aebe622bcc26 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 10 Jul 2023 16:51:39 +0800 Subject: [PATCH 196/469] chore(docs): publish 1.0.33 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index f8617eac0a..269bd2df64 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.32", + "version": "1.0.33", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 38dc561b6a04e3267a5f20c175923f41765bd2b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E6=9E=97?= <chenglin@dian.so> Date: Tue, 11 Jul 2023 11:06:21 +0800 Subject: [PATCH 197/469] chore(code-gen): replace deprecated api --- .../src/cli/solutions/example-solution.ts | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/modules/code-generator/src/cli/solutions/example-solution.ts b/modules/code-generator/src/cli/solutions/example-solution.ts index 0314151c6e..fd34c36781 100644 --- a/modules/code-generator/src/cli/solutions/example-solution.ts +++ b/modules/code-generator/src/cli/solutions/example-solution.ts @@ -635,18 +635,18 @@ export default function createHelloWorldProjectBuilder() { template: CodeGen.solutionParts.icejs.template, plugins: { components: [ - CodeGen.plugins.react.reactCommonDeps(), - CodeGen.plugins.common.esmodule({ fileType: 'jsx' }), - CodeGen.plugins.react.containerClass(), - CodeGen.plugins.react.containerInjectContext(), - CodeGen.plugins.react.containerInjectUtils(), - CodeGen.plugins.react.containerInjectDataSourceEngine(), - CodeGen.plugins.react.containerInjectI18n(), - CodeGen.plugins.react.containerInitState(), - CodeGen.plugins.react.containerLifeCycle(), - CodeGen.plugins.react.containerMethod(), + CodeGen.plugins.icejs.reactCommonDeps(), + CodeGen.plugins.common.esModule({ fileType: 'jsx' }), + CodeGen.plugins.icejs.containerClass(), + CodeGen.plugins.icejs.containerInjectContext(), + CodeGen.plugins.icejs.containerInjectUtils(), + CodeGen.plugins.icejs.containerInjectDataSourceEngine(), + CodeGen.plugins.icejs.containerInjectI18n(), + CodeGen.plugins.icejs.containerInitState(), + CodeGen.plugins.icejs.containerLifeCycle(), + CodeGen.plugins.icejs.containerMethod(), examplePlugin(), - CodeGen.plugins.react.jsx({ + CodeGen.plugins.icejs.jsx({ nodeTypeMapping: { Div: 'div', Component: 'div', @@ -657,18 +657,18 @@ export default function createHelloWorldProjectBuilder() { CodeGen.plugins.style.css(), ], pages: [ - CodeGen.plugins.react.reactCommonDeps(), - CodeGen.plugins.common.esmodule({ fileType: 'jsx' }), - CodeGen.plugins.react.containerClass(), - CodeGen.plugins.react.containerInjectContext(), - CodeGen.plugins.react.containerInjectUtils(), - CodeGen.plugins.react.containerInjectDataSourceEngine(), - CodeGen.plugins.react.containerInjectI18n(), - CodeGen.plugins.react.containerInitState(), - CodeGen.plugins.react.containerLifeCycle(), - CodeGen.plugins.react.containerMethod(), + CodeGen.plugins.icejs.reactCommonDeps(), + CodeGen.plugins.common.esModule({ fileType: 'jsx' }), + CodeGen.plugins.icejs.containerClass(), + CodeGen.plugins.icejs.containerInjectContext(), + CodeGen.plugins.icejs.containerInjectUtils(), + CodeGen.plugins.icejs.containerInjectDataSourceEngine(), + CodeGen.plugins.icejs.containerInjectI18n(), + CodeGen.plugins.icejs.containerInitState(), + CodeGen.plugins.icejs.containerLifeCycle(), + CodeGen.plugins.icejs.containerMethod(), examplePlugin(), - CodeGen.plugins.react.jsx({ + CodeGen.plugins.icejs.jsx({ nodeTypeMapping: { Div: 'div', Component: 'div', @@ -679,13 +679,13 @@ export default function createHelloWorldProjectBuilder() { CodeGen.plugins.style.css(), ], router: [ - CodeGen.plugins.common.esmodule(), + CodeGen.plugins.common.esModule(), CodeGen.solutionParts.icejs.plugins.router(), ], entry: [CodeGen.solutionParts.icejs.plugins.entry()], constants: [CodeGen.plugins.project.constants()], utils: [ - CodeGen.plugins.common.esmodule(), + CodeGen.plugins.common.esModule(), CodeGen.plugins.project.utils('react'), ], i18n: [CodeGen.plugins.project.i18n()], From 4e24d512d12f8f9aa77261ba63d4345d43d6d31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E6=9E=97?= <chenglin@dian.so> Date: Tue, 11 Jul 2023 11:15:52 +0800 Subject: [PATCH 198/469] =?UTF-8?q?chore(code-gen):=20icejs=E3=80=81icejs3?= =?UTF-8?q?=20solutions=20plugins.components=20add=20containerInjectConsta?= =?UTF-8?q?nts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/code-generator/src/solutions/icejs.ts | 1 + modules/code-generator/src/solutions/icejs3.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/modules/code-generator/src/solutions/icejs.ts b/modules/code-generator/src/solutions/icejs.ts index 7dc44f4bec..1149098ecb 100644 --- a/modules/code-generator/src/solutions/icejs.ts +++ b/modules/code-generator/src/solutions/icejs.ts @@ -45,6 +45,7 @@ export default function createIceJsProjectBuilder( containerInjectUtils(), containerInjectDataSourceEngine(), containerInjectI18n(), + containerInjectConstants(), containerInitState(), containerLifeCycle(), containerMethod(), diff --git a/modules/code-generator/src/solutions/icejs3.ts b/modules/code-generator/src/solutions/icejs3.ts index c6870dfd07..a8622e74ab 100644 --- a/modules/code-generator/src/solutions/icejs3.ts +++ b/modules/code-generator/src/solutions/icejs3.ts @@ -45,6 +45,7 @@ export default function createIceJsProjectBuilder( containerInjectUtils(), containerInjectDataSourceEngine(), containerInjectI18n(), + containerInjectConstants(), containerInitState(), containerLifeCycle(), containerMethod(), From 7decc3a8db1bd81b09a51c36e50c3099b9f394d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E6=9E=97?= <chenglin@dian.so> Date: Tue, 11 Jul 2023 11:16:28 +0800 Subject: [PATCH 199/469] chore(code-gen): template sync icejs --- modules/code-generator/src/cli/solutions/example-solution.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/code-generator/src/cli/solutions/example-solution.ts b/modules/code-generator/src/cli/solutions/example-solution.ts index fd34c36781..bfb9d079b1 100644 --- a/modules/code-generator/src/cli/solutions/example-solution.ts +++ b/modules/code-generator/src/cli/solutions/example-solution.ts @@ -637,11 +637,13 @@ export default function createHelloWorldProjectBuilder() { components: [ CodeGen.plugins.icejs.reactCommonDeps(), CodeGen.plugins.common.esModule({ fileType: 'jsx' }), + CodeGen.plugins.common.styleImport(), CodeGen.plugins.icejs.containerClass(), CodeGen.plugins.icejs.containerInjectContext(), CodeGen.plugins.icejs.containerInjectUtils(), CodeGen.plugins.icejs.containerInjectDataSourceEngine(), CodeGen.plugins.icejs.containerInjectI18n(), + CodeGen.plugins.icejs.containerInjectConstants(), CodeGen.plugins.icejs.containerInitState(), CodeGen.plugins.icejs.containerLifeCycle(), CodeGen.plugins.icejs.containerMethod(), @@ -659,11 +661,13 @@ export default function createHelloWorldProjectBuilder() { pages: [ CodeGen.plugins.icejs.reactCommonDeps(), CodeGen.plugins.common.esModule({ fileType: 'jsx' }), + CodeGen.plugins.common.styleImport(), CodeGen.plugins.icejs.containerClass(), CodeGen.plugins.icejs.containerInjectContext(), CodeGen.plugins.icejs.containerInjectUtils(), CodeGen.plugins.icejs.containerInjectDataSourceEngine(), CodeGen.plugins.icejs.containerInjectI18n(), + CodeGen.plugins.icejs.containerInjectConstants(), CodeGen.plugins.icejs.containerInitState(), CodeGen.plugins.icejs.containerLifeCycle(), CodeGen.plugins.icejs.containerMethod(), From 19935cfc93de111e82691502eaf4f186a84cae37 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 11 Jul 2023 16:14:55 +0800 Subject: [PATCH 200/469] feat: add new cache from diff origin component --- packages/renderer-core/src/hoc/leaf.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index bb81e88e37..1ff91cb147 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -193,8 +193,8 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { getNode, }); - if (curDocumentId && cache.component.has(componentCacheId)) { - return cache.component.get(componentCacheId); + if (curDocumentId && cache.component.has(componentCacheId) && (cache.component.get(componentCacheId).Comp === Comp)) { + return cache.component.get(componentCacheId).LeafWrapper; } class LeafHoc extends Component { @@ -590,7 +590,10 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { LeafWrapper.displayName = (Comp as any).displayName; - cache.component.set(componentCacheId, LeafWrapper); + cache.component.set(componentCacheId, { + LeafWrapper, + Comp, + }); return LeafWrapper; } \ No newline at end of file From 2d98f1c9b5d8c8bbda5100ddecb83ceb08943b36 Mon Sep 17 00:00:00 2001 From: AndyJin <jjj706@163.com> Date: Wed, 12 Jul 2023 11:27:37 +0800 Subject: [PATCH 201/469] fix: the action of history would not update outline tree --- packages/plugin-outline-pane/src/controllers/tree.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/plugin-outline-pane/src/controllers/tree.ts b/packages/plugin-outline-pane/src/controllers/tree.ts index 463c7919f3..ca5a43c554 100644 --- a/packages/plugin-outline-pane/src/controllers/tree.ts +++ b/packages/plugin-outline-pane/src/controllers/tree.ts @@ -30,6 +30,10 @@ export class Tree { treeNode?.notifyExpandableChanged(); }); + doc?.history.onChangeCursor(() => { + this.root?.notifyExpandableChanged(); + }); + doc?.onChangeNodeProp((info: IPublicTypePropChangeOptions) => { const { node, key } = info; if (key === '___title___') { From aa1bb1c0d720d972e64049f92358456b14069310 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 12 Jul 2023 18:01:45 +0800 Subject: [PATCH 202/469] feat: add config.workspaceEmptyComponent --- packages/editor-core/src/config.ts | 4 ++++ packages/workspace/src/layouts/workbench.tsx | 18 +++++++++++++++++- packages/workspace/src/workspace.ts | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/editor-core/src/config.ts b/packages/editor-core/src/config.ts index c325c2bb85..85e6097801 100644 --- a/packages/editor-core/src/config.ts +++ b/packages/editor-core/src/config.ts @@ -155,6 +155,10 @@ const VALID_ENGINE_OPTIONS = { description: '是否开启应用级设计模式', default: false, }, + workspaceEmptyComponent: { + type: 'function', + description: '应用级设计模式下,窗口为空时展示的占位组件', + }, }; const getStrictModeValue = (engineOptions: IPublicTypeEngineOptions, defaultValue: boolean): boolean => { diff --git a/packages/workspace/src/layouts/workbench.tsx b/packages/workspace/src/layouts/workbench.tsx index 0c69f9717c..08d6dc1a93 100644 --- a/packages/workspace/src/layouts/workbench.tsx +++ b/packages/workspace/src/layouts/workbench.tsx @@ -1,5 +1,5 @@ import { Component } from 'react'; -import { TipContainer, observer } from '@alilc/lowcode-editor-core'; +import { TipContainer, engineConfig, observer } from '@alilc/lowcode-editor-core'; import { WindowView } from '../view/window-view'; import classNames from 'classnames'; import TopArea from './top-area'; @@ -21,17 +21,29 @@ export class Workbench extends Component<{ components?: PluginClassSet; className?: string; topAreaItemClassName?: string; +}, { + workspaceEmptyComponent: any; }> { constructor(props: any) { super(props); const { config, components, workspace } = this.props; const { skeleton } = workspace; skeleton.buildFromConfig(config, components); + engineConfig.onGot('workspaceEmptyComponent', (workspaceEmptyComponent) => { + this.setState({ + workspaceEmptyComponent, + }); + }); + this.state = { + workspaceEmptyComponent: engineConfig.get('workspaceEmptyComponent'), + }; } render() { const { workspace, className, topAreaItemClassName } = this.props; const { skeleton } = workspace; + const WorkspaceEmptyComponent = this.state.workspaceEmptyComponent; + return ( <div className={classNames('lc-workspace-workbench', className)}> <SkeletonContext.Provider value={skeleton}> @@ -53,6 +65,10 @@ export class Workbench extends Component<{ /> )) } + + { + !workspace.windows.length && WorkspaceEmptyComponent ? <WorkspaceEmptyComponent /> : null + } </div> </div> <MainArea area={skeleton.mainArea} /> diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index bedae86801..6c35d8b35c 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -199,7 +199,7 @@ export class Workspace implements IWorkspace { this.windows.splice(index, 1); if (this.window === window) { this.window = this.windows[index] || this.windows[index + 1] || this.windows[index - 1]; - if (this.window.sleep) { + if (this.window?.sleep) { this.window.init(); } this.emitChangeActiveWindow(); From 7a1b9802a4ff695094e7277ce8a1a1ee1c88c6ed Mon Sep 17 00:00:00 2001 From: eternalsky <wsj7552715@hotmail.com> Date: Thu, 13 Jul 2023 15:33:35 +0800 Subject: [PATCH 203/469] feat(codegen): add new option exclude for plugin containerLifeCycle --- .../plugins/component/react/containerLifeCycle.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts b/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts index 75dcada63d..5f7d6d22a7 100644 --- a/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts +++ b/modules/code-generator/src/plugins/component/react/containerLifeCycle.ts @@ -16,13 +16,14 @@ import { isJSFunction, isJSExpression } from '@alilc/lowcode-types'; import { isJSExpressionFn } from '../../../utils/common'; export interface PluginConfig { - fileType: string; - exportNameMapping: Record<string, string>; - normalizeNameMapping: Record<string, string>; + fileType?: string; + exportNameMapping?: Record<string, string>; + normalizeNameMapping?: Record<string, string>; + exclude?: string[]; } const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => { - const cfg: PluginConfig = { + const cfg = { fileType: FileType.JSX, exportNameMapping: {}, normalizeNameMapping: {}, @@ -56,6 +57,10 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => normalizeName = cfg.normalizeNameMapping[lifeCycleName] || lifeCycleName; } + if (cfg?.exclude?.includes(normalizeName)) { + return null; + } + const exportName = cfg.exportNameMapping[lifeCycleName] || lifeCycleName; if (normalizeName === 'constructor') { return { @@ -97,7 +102,7 @@ const pluginFactory: BuilderComponentPluginFactory<PluginConfig> = (config?) => }), linkAfter: [...DEFAULT_LINK_AFTER[CLASS_DEFINE_CHUNK_NAME.InsMethod]], }; - }); + }).filter((i) => !!i); next.chunks.push(...chunks.filter((x): x is ICodeChunk => x !== null)); } From 87a40764273a63bb3775b78e248d8993a3c45845 Mon Sep 17 00:00:00 2001 From: eternalsky <wsj7552715@hotmail.com> Date: Thu, 13 Jul 2023 17:47:12 +0800 Subject: [PATCH 204/469] chore(release): code-generator - 1.1.5 --- modules/code-generator/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index ce01f5e4e1..193951fb03 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-code-generator", - "version": "1.1.4", + "version": "1.1.5", "description": "出码引擎 for LowCode Engine", "license": "MIT", "main": "lib/index.js", From 841442574080d6399d549a1a974c71d5b4a572f0 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 14 Jul 2023 12:25:12 +0800 Subject: [PATCH 205/469] feat: add hotkey in workspace plugins --- packages/editor-core/src/hotkey.ts | 4 ++-- packages/workspace/src/workspace.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/editor-core/src/hotkey.ts b/packages/editor-core/src/hotkey.ts index adc74262a8..d0dd40cc24 100644 --- a/packages/editor-core/src/hotkey.ts +++ b/packages/editor-core/src/hotkey.ts @@ -317,8 +317,8 @@ function getKeyInfo(combination: string, action?: string): KeyInfo { function fireCallback(callback: IPublicTypeHotkeyCallback, e: KeyboardEvent, combo?: string, sequence?: string): void { try { const workspace = globalContext.get('workspace'); - const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); - const designer = editor.get('designer'); + const editor = workspace.isActive ? workspace.window?.editor : globalContext.get('editor'); + const designer = editor?.get('designer'); const node = designer?.currentSelection?.getNodes()?.[0]; const npm = node?.componentMeta?.npm; const selected = diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 6c35d8b35c..6410c6e207 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -103,6 +103,7 @@ export class Workspace implements IWorkspace { readonly shellModelFactory: any, ) { this.context = new BasicContext(this, '', IPublicEnumPluginRegisterLevel.Workspace); + this.context.innerHotkey.activate(true); makeObservable(this); } From 412cb16628222d529fc67ac1180598c6d51e3900 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 17 Jul 2023 14:18:15 +0800 Subject: [PATCH 206/469] fix: fix left-pane cant hidden when iframe click --- packages/editor-skeleton/src/layouts/left-float-pane.tsx | 6 ++++++ packages/workspace/src/layouts/left-float-pane.tsx | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/packages/editor-skeleton/src/layouts/left-float-pane.tsx b/packages/editor-skeleton/src/layouts/left-float-pane.tsx index 7df6993bb5..15f4926199 100644 --- a/packages/editor-skeleton/src/layouts/left-float-pane.tsx +++ b/packages/editor-skeleton/src/layouts/left-float-pane.tsx @@ -4,6 +4,7 @@ import { observer, Focusable } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; import { Panel } from '../widget/panel'; import { PanelConfig } from '../types'; +import { IPublicApiProject } from '@alilc/lowcode-types'; @observer export default class LeftFloatPane extends Component<{ area: Area<PanelConfig, Panel> }> { @@ -31,6 +32,8 @@ export default class LeftFloatPane extends Component<{ area: Area<PanelConfig, P area.skeleton.editor.removeListener('designer.drag', triggerClose); }; + const project: IPublicApiProject | undefined = area.skeleton.editor.get('project'); + this.focusing = area.skeleton.focusTracker.create({ range: (e) => { const target = e.target as HTMLElement; @@ -44,6 +47,9 @@ export default class LeftFloatPane extends Component<{ area: Area<PanelConfig, P if ((document.querySelector('.lc-simulator-content-frame') as HTMLIFrameElement)?.contentWindow?.document.documentElement.contains(target)) { return false; } + if (project?.simulatorHost?.contentWindow?.document.documentElement.contains(target)) { + return false; + } // 点击设置区 if (document.querySelector('.lc-right-area')?.contains(target)) { return false; diff --git a/packages/workspace/src/layouts/left-float-pane.tsx b/packages/workspace/src/layouts/left-float-pane.tsx index 38f70b386d..3df3e197c2 100644 --- a/packages/workspace/src/layouts/left-float-pane.tsx +++ b/packages/workspace/src/layouts/left-float-pane.tsx @@ -2,6 +2,7 @@ import { Component, Fragment } from 'react'; import classNames from 'classnames'; import { observer, Focusable } from '@alilc/lowcode-editor-core'; import { Area, Panel } from '@alilc/lowcode-editor-skeleton'; +import { IPublicApiProject } from '@alilc/lowcode-types'; @observer export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }> { @@ -29,6 +30,8 @@ export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }> area.skeleton.editor.removeListener('designer.drag', triggerClose); }; + const project: IPublicApiProject | undefined = area.skeleton.editor.get('project'); + this.focusing = area.skeleton.focusTracker.create({ range: (e) => { const target = e.target as HTMLElement; @@ -42,6 +45,9 @@ export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }> if ((document.querySelector('.lc-simulator-content-frame') as HTMLIFrameElement)?.contentWindow?.document.documentElement.contains(target)) { return false; } + if (project?.simulatorHost?.contentWindow?.document.documentElement.contains(target)) { + return false; + } // 点击设置区 if (document.querySelector('.lc-right-area')?.contains(target)) { return false; From 16fde64deea5e3ccc53eb9410cdc8f31f59db9d8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 19 Jul 2023 11:16:17 +0800 Subject: [PATCH 207/469] style: update workbench styles --- packages/editor-skeleton/src/layouts/workbench.less | 2 +- packages/shell/src/api/setters.ts | 2 +- packages/shell/src/api/skeleton.ts | 2 +- packages/workspace/src/layouts/workbench.less | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index f97e1f46f2..fccdad4c2d 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -318,7 +318,7 @@ body { align-items: center; .lc-title { flex-direction: column; - width: 46px; + width: calc(var(--left-area-width) - 2px); height: 46px; display: flex; align-items: center; diff --git a/packages/shell/src/api/setters.ts b/packages/shell/src/api/setters.ts index 7750a5152e..b7f2d40ecf 100644 --- a/packages/shell/src/api/setters.ts +++ b/packages/shell/src/api/setters.ts @@ -19,7 +19,7 @@ export class Setters implements IPublicApiSetters { const workspace = globalContext.get('workspace'); if (workspace.isActive) { return untracked(() => { - if (!workspace.window.innerSetters) { + if (!workspace.window?.innerSetters) { logger.error('setter api 调用时机出现问题,请检查'); return this[innerSettersSymbol]; } diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index b48747598e..238931a25e 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -22,7 +22,7 @@ export class Skeleton implements IPublicApiSkeleton { } const workspace = globalContext.get('workspace'); if (workspace.isActive) { - if (!workspace.window.innerSkeleton) { + if (!workspace.window?.innerSkeleton) { logger.error('skeleton api 调用时机出现问题,请检查'); return this[innerSkeletonSymbol]; } diff --git a/packages/workspace/src/layouts/workbench.less b/packages/workspace/src/layouts/workbench.less index c8c89d6f0f..05eb5f513b 100644 --- a/packages/workspace/src/layouts/workbench.less +++ b/packages/workspace/src/layouts/workbench.less @@ -276,7 +276,7 @@ body { align-items: center; .lc-title { flex-direction: column; - width: 46px; + width: calc(var(--left-area-width) - 2px); height: 46px; display: flex; align-items: center; From 02a3361f4104b8cfa00149199bea89504581b584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Wed, 19 Jul 2023 14:34:15 +0800 Subject: [PATCH 208/469] fix: lock some ice libs && next resource 404 --- .../plugins/project/framework/icejs3/plugins/packageJSON.ts | 4 ++-- .../project/framework/icejs3/template/files/document.ts | 2 +- .../icejs3-app/demo1/expected/demo-project/package.json | 4 ++-- .../icejs3-app/demo1/expected/demo-project/src/document.tsx | 2 +- .../demo2-utils-name-alias/expected/demo-project/package.json | 4 ++-- .../expected/demo-project/src/document.tsx | 2 +- .../icejs3-app/demo2/expected/demo-project/package.json | 4 ++-- .../icejs3-app/demo2/expected/demo-project/src/document.tsx | 2 +- .../icejs3-app/demo3/expected/demo-project/package.json | 4 ++-- .../icejs3-app/demo3/expected/demo-project/src/document.tsx | 2 +- .../icejs3-app/demo4/expected/demo-project/package.json | 4 ++-- .../icejs3-app/demo4/expected/demo-project/src/document.tsx | 2 +- .../icejs3-app/demo5/expected/demo-project/package.json | 4 ++-- .../icejs3-app/demo5/expected/demo-project/src/document.tsx | 2 +- .../expected/demo-project/package.json | 4 ++-- .../expected/demo-project/src/document.tsx | 2 +- .../expected/demo-project/package.json | 4 ++-- .../expected/demo-project/src/document.tsx | 2 +- .../demo8-datasource-prop/expected/demo-project/package.json | 4 ++-- .../expected/demo-project/src/document.tsx | 2 +- .../expected/demo-project/package.json | 4 ++-- .../expected/demo-project/src/document.tsx | 2 +- .../demo_10-jsslot/expected/demo-project/package.json | 4 ++-- .../demo_10-jsslot/expected/demo-project/src/document.tsx | 2 +- .../demo_11-jsslot-2/expected/demo-project/package.json | 4 ++-- .../demo_11-jsslot-2/expected/demo-project/src/document.tsx | 2 +- 26 files changed, 39 insertions(+), 39 deletions(-) diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/plugins/packageJSON.ts b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/packageJSON.ts index 11248a0b5d..3c39ba7399 100644 --- a/modules/code-generator/src/plugins/project/framework/icejs3/plugins/packageJSON.ts +++ b/modules/code-generator/src/plugins/project/framework/icejs3/plugins/packageJSON.ts @@ -67,12 +67,12 @@ const pluginFactory: BuilderComponentPluginFactory<IceJs3PackageJsonPluginConfig 'react-router-dom': '^6.9.0', 'intl-messageformat': '^9.3.6', '@alifd/next': '1.26.15', - '@ice/runtime': '^1.0.0', + '@ice/runtime': '~1.1.0', // 数据源相关的依赖: ...buildDataSourceDependencies(ir, cfg?.datasourceConfig), }, devDependencies: { - '@ice/app': '^3.0.0', + '@ice/app': '~3.1.0', '@types/react': '^18.0.0', '@types/react-dom': '^18.0.0', '@types/node': '^18.11.17', diff --git a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/document.ts b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/document.ts index 17978b20dc..3345625557 100644 --- a/modules/code-generator/src/plugins/project/framework/icejs3/template/files/document.ts +++ b/modules/code-generator/src/plugins/project/framework/icejs3/template/files/document.ts @@ -27,7 +27,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/package.json index 54a1e4e121..38f24df0b1 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/package.json @@ -10,13 +10,13 @@ "react-router-dom": "^6.9.0", "intl-messageformat": "^9.3.6", "@alifd/next": "1.19.18", - "@ice/runtime": "^1.0.0", + "@ice/runtime": "~1.1.0", "@alilc/lowcode-datasource-engine": "^1.0.0", "@alilc/lowcode-datasource-url-params-handler": "^1.0.0", "@alilc/lowcode-datasource-fetch-handler": "^1.0.0" }, "devDependencies": { - "@ice/app": "^3.0.0", + "@ice/app": "~3.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/node": "^18.11.17", diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/document.tsx index 286be9f8ca..aff0231d95 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/document.tsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo1/expected/demo-project/src/document.tsx @@ -19,7 +19,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/package.json index e234f0da02..3a0015c9bd 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/package.json @@ -10,7 +10,7 @@ "react-router-dom": "^6.9.0", "intl-messageformat": "^9.3.6", "@alifd/next": "1.26.15", - "@ice/runtime": "^1.0.0", + "@ice/runtime": "~1.1.0", "@alilc/lowcode-datasource-engine": "^1.0.0", "@alilc/lowcode-datasource-url-params-handler": "^1.0.0", "@alilc/b6-page": "^0.1.0", @@ -20,7 +20,7 @@ "@alilc/b6-util-mocks": "1.x" }, "devDependencies": { - "@ice/app": "^3.0.0", + "@ice/app": "~3.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/node": "^18.11.17", diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/document.tsx index 286be9f8ca..aff0231d95 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/document.tsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2-utils-name-alias/expected/demo-project/src/document.tsx @@ -19,7 +19,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/package.json index 63717e3193..8f02ff1c7e 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/package.json @@ -10,11 +10,11 @@ "react-router-dom": "^6.9.0", "intl-messageformat": "^9.3.6", "@alifd/next": "1.19.18", - "@ice/runtime": "^1.0.0", + "@ice/runtime": "~1.1.0", "@alilc/lowcode-datasource-engine": "^1.0.0" }, "devDependencies": { - "@ice/app": "^3.0.0", + "@ice/app": "~3.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/node": "^18.11.17", diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/document.tsx index 286be9f8ca..aff0231d95 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/document.tsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo2/expected/demo-project/src/document.tsx @@ -19,7 +19,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/package.json index 63717e3193..8f02ff1c7e 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/package.json @@ -10,11 +10,11 @@ "react-router-dom": "^6.9.0", "intl-messageformat": "^9.3.6", "@alifd/next": "1.19.18", - "@ice/runtime": "^1.0.0", + "@ice/runtime": "~1.1.0", "@alilc/lowcode-datasource-engine": "^1.0.0" }, "devDependencies": { - "@ice/app": "^3.0.0", + "@ice/app": "~3.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/node": "^18.11.17", diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/document.tsx index 286be9f8ca..aff0231d95 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/document.tsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo3/expected/demo-project/src/document.tsx @@ -19,7 +19,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/package.json index 43f4440856..393be4663e 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/package.json @@ -10,14 +10,14 @@ "react-router-dom": "^6.9.0", "intl-messageformat": "^9.3.6", "@alifd/next": "1.26.15", - "@ice/runtime": "^1.0.0", + "@ice/runtime": "~1.1.0", "@alilc/lowcode-datasource-engine": "^1.0.0", "@alilc/lowcode-datasource-fetch-handler": "^1.0.0", "@alife/container": "^1.0.0", "@alife/mc-assets-1935": "0.1.9" }, "devDependencies": { - "@ice/app": "^3.0.0", + "@ice/app": "~3.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/node": "^18.11.17", diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/document.tsx index 286be9f8ca..aff0231d95 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/document.tsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo4/expected/demo-project/src/document.tsx @@ -19,7 +19,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/package.json index a62526e762..d007025a60 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/package.json @@ -10,7 +10,7 @@ "react-router-dom": "^6.9.0", "intl-messageformat": "^9.3.6", "@alifd/next": "1.26.15", - "@ice/runtime": "^1.0.0", + "@ice/runtime": "~1.1.0", "@alilc/lowcode-datasource-engine": "^1.0.0", "undefined": "*", "@alife/container": "0.3.7", @@ -18,7 +18,7 @@ "@alife/mc-assets-1935": "0.1.16" }, "devDependencies": { - "@ice/app": "^3.0.0", + "@ice/app": "~3.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/node": "^18.11.17", diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/document.tsx index 286be9f8ca..aff0231d95 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/document.tsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo5/expected/demo-project/src/document.tsx @@ -19,7 +19,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/package.json index 54a1e4e121..38f24df0b1 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/package.json @@ -10,13 +10,13 @@ "react-router-dom": "^6.9.0", "intl-messageformat": "^9.3.6", "@alifd/next": "1.19.18", - "@ice/runtime": "^1.0.0", + "@ice/runtime": "~1.1.0", "@alilc/lowcode-datasource-engine": "^1.0.0", "@alilc/lowcode-datasource-url-params-handler": "^1.0.0", "@alilc/lowcode-datasource-fetch-handler": "^1.0.0" }, "devDependencies": { - "@ice/app": "^3.0.0", + "@ice/app": "~3.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/node": "^18.11.17", diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/document.tsx index 286be9f8ca..aff0231d95 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/document.tsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo6-literal-condition/expected/demo-project/src/document.tsx @@ -19,7 +19,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/package.json index 399ff4333b..fcdfc7bd4b 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/package.json @@ -10,14 +10,14 @@ "react-router-dom": "^6.9.0", "intl-messageformat": "^9.3.6", "@alifd/next": "1.26.15", - "@ice/runtime": "^1.0.0", + "@ice/runtime": "~1.1.0", "@alilc/lowcode-datasource-engine": "^1.0.0", "undefined": "*", "@alilc/antd-lowcode": "0.8.0", "@alife/container": "0.3.7" }, "devDependencies": { - "@ice/app": "^3.0.0", + "@ice/app": "~3.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/node": "^18.11.17", diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/document.tsx index 286be9f8ca..aff0231d95 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/document.tsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo7-literal-condition2/expected/demo-project/src/document.tsx @@ -19,7 +19,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/package.json index 45c8e304a9..342a5a0774 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/package.json @@ -10,13 +10,13 @@ "react-router-dom": "^6.9.0", "intl-messageformat": "^9.3.6", "@alifd/next": "1.26.15", - "@ice/runtime": "^1.0.0", + "@ice/runtime": "~1.1.0", "@alilc/lowcode-datasource-engine": "^1.0.0", "@alilc/lowcode-datasource-http-handler": "^1.0.0", "@alilc/lowcode-components": "^1.0.0" }, "devDependencies": { - "@ice/app": "^3.0.0", + "@ice/app": "~3.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/node": "^18.11.17", diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/document.tsx index 286be9f8ca..aff0231d95 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/document.tsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo8-datasource-prop/expected/demo-project/src/document.tsx @@ -19,7 +19,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/package.json index 87ad385141..d7d07dc6ed 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/package.json @@ -10,12 +10,12 @@ "react-router-dom": "^6.9.0", "intl-messageformat": "^9.3.6", "@alifd/next": "1.19.18", - "@ice/runtime": "^1.0.0", + "@ice/runtime": "~1.1.0", "@alilc/lowcode-datasource-engine": "^1.0.0", "@alilc/lowcode-datasource-jsonp-handler": "^1.0.0" }, "devDependencies": { - "@ice/app": "^3.0.0", + "@ice/app": "~3.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/node": "^18.11.17", diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/document.tsx index 286be9f8ca..aff0231d95 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/document.tsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo9-datasource-engine/expected/demo-project/src/document.tsx @@ -19,7 +19,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/package.json index cad3038d99..fb35f3cf46 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/package.json @@ -10,7 +10,7 @@ "react-router-dom": "^6.9.0", "intl-messageformat": "^9.3.6", "@alifd/next": "1.26.15", - "@ice/runtime": "^1.0.0", + "@ice/runtime": "~1.1.0", "@alilc/lowcode-datasource-engine": "^1.0.0", "undefined": "*", "@alilc/antd-lowcode-materials": "0.9.4", @@ -18,7 +18,7 @@ "@alife/container": "0.3.7" }, "devDependencies": { - "@ice/app": "^3.0.0", + "@ice/app": "~3.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/node": "^18.11.17", diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/document.tsx index 286be9f8ca..aff0231d95 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/document.tsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_10-jsslot/expected/demo-project/src/document.tsx @@ -19,7 +19,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/package.json b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/package.json index 32b4ea8772..89f693efcb 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/package.json +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/package.json @@ -10,7 +10,7 @@ "react-router-dom": "^6.9.0", "intl-messageformat": "^9.3.6", "@alifd/next": "1.26.15", - "@ice/runtime": "^1.0.0", + "@ice/runtime": "~1.1.0", "@alilc/lowcode-datasource-engine": "^1.0.0", "undefined": "*", "@alilc/antd-lowcode-materials": "0.11.0", @@ -18,7 +18,7 @@ "@alife/container": "0.3.7" }, "devDependencies": { - "@ice/app": "^3.0.0", + "@ice/app": "~3.1.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@types/node": "^18.11.17", diff --git a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/document.tsx b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/document.tsx index 286be9f8ca..aff0231d95 100644 --- a/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/document.tsx +++ b/modules/code-generator/tests/fixtures/test-cases/icejs3-app/demo_11-jsslot-2/expected/demo-project/src/document.tsx @@ -19,7 +19,7 @@ export default function Document() { <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/??react-router/6.9.0/react-router.production.min.js,react-router-dom/6.9.0/react-router-dom.production.min.js" /> - <script crossOrigin="anonymous" src="//alifd.alicdn.com/npm/@alifd/next/1.26.15/next.min.js" /> + <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/alifd__next/1.26.22/next.min.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js" /> <script crossOrigin="anonymous" src="//g.alicdn.com/platform/c/??lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js" /> <Scripts /> From e875e33dc543f64010ad033a97856b08275edba2 Mon Sep 17 00:00:00 2001 From: liangzr <1668890395@qq.com> Date: Thu, 20 Jul 2023 10:36:10 +0800 Subject: [PATCH 209/469] feat: generateTemplate fun support context --- modules/code-generator/src/generator/ProjectBuilder.ts | 5 +++-- modules/code-generator/src/types/core.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/code-generator/src/generator/ProjectBuilder.ts b/modules/code-generator/src/generator/ProjectBuilder.ts index c1db28fe9d..a910b49002 100644 --- a/modules/code-generator/src/generator/ProjectBuilder.ts +++ b/modules/code-generator/src/generator/ProjectBuilder.ts @@ -111,8 +111,6 @@ export class ProjectBuilder implements IProjectBuilder { // Init const { schemaParser } = this; - const projectRoot = await this.template.generateTemplate(); - let schema: IPublicTypeProjectSchema = typeof originalSchema === 'string' ? JSON.parse(originalSchema) : originalSchema; @@ -131,6 +129,9 @@ export class ProjectBuilder implements IProjectBuilder { // Collect Deps // Parse JSExpression const parseResult: IParseResult = schemaParser.parse(schema); + + const projectRoot = await this.template.generateTemplate(parseResult); + let buildResult: IModuleInfo[] = []; const builders = this.createModuleBuilders({ diff --git a/modules/code-generator/src/types/core.ts b/modules/code-generator/src/types/core.ts index fb2a780c10..1219a1e767 100644 --- a/modules/code-generator/src/types/core.ts +++ b/modules/code-generator/src/types/core.ts @@ -127,7 +127,7 @@ export interface ISchemaParser { export interface IProjectTemplate { slots: Record<string, IProjectSlot>; - generateTemplate: () => ResultDir | Promise<ResultDir>; + generateTemplate: (data: IParseResult) => ResultDir | Promise<ResultDir>; } export interface IProjectSlot { From d267fecc67f3c3eec08c224aeb62c1957ff39187 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 25 Jul 2023 10:28:05 +0800 Subject: [PATCH 210/469] feat: add state for workspace windows --- packages/workspace/src/window.ts | 33 +++++++++++++++++++++++++++++ packages/workspace/src/workspace.ts | 9 +++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index 6fb706632a..b6e345f19e 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -26,6 +26,22 @@ export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'chan sleep?: boolean; init(): void; + + updateState(state: WINDOW_STATE): void; +} + +export enum WINDOW_STATE { + // 睡眠 + sleep = 'sleep', + + // 激活 + active = 'active', + + // 未激活 + inactive = 'inactive', + + // 销毁 + destroyed = 'destroyed' } export class EditorWindow implements IEditorWindow { @@ -51,6 +67,22 @@ export class EditorWindow implements IEditorWindow { this.title = config.title; this.icon = resource.icon; this.sleep = config.sleep; + if (config.sleep) { + this.updateState(WINDOW_STATE.sleep); + } + } + + updateState(state: WINDOW_STATE): void { + switch (state) { + case WINDOW_STATE.active: + this.editorView?.setActivate(true); + break; + case WINDOW_STATE.inactive: + this.editorView?.setActivate(false); + break; + case WINDOW_STATE.destroyed: + break; + } } async importSchema(schema: any) { @@ -102,6 +134,7 @@ export class EditorWindow implements IEditorWindow { this.initReady = true; this.workspace.checkWindowQueue(); this.sleep = false; + this.updateState(WINDOW_STATE.active); } initViewTypes = async () => { diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 6410c6e207..e180d4a2fb 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -2,7 +2,7 @@ import { IDesigner, ILowCodePluginManager, LowCodePluginManager } from '@alilc/l import { createModuleEventBus, Editor, IEditor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; import { IPublicApiPlugins, IPublicApiWorkspace, IPublicEnumPluginRegisterLevel, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types'; import { BasicContext } from './context/base-context'; -import { EditorWindow } from './window'; +import { EditorWindow, WINDOW_STATE } from './window'; import type { IEditorWindow } from './window'; import { IResource, Resource } from './resource'; import { IResourceType, ResourceType } from './resource-type'; @@ -198,6 +198,7 @@ export class Workspace implements IWorkspace { } const window = this.windows[index]; this.windows.splice(index, 1); + this.window?.updateState(WINDOW_STATE.destroyed); if (this.window === window) { this.window = this.windows[index] || this.windows[index + 1] || this.windows[index - 1]; if (this.window?.sleep) { @@ -206,6 +207,7 @@ export class Workspace implements IWorkspace { this.emitChangeActiveWindow(); } this.emitChangeWindow(); + this.window?.updateState(WINDOW_STATE.active); } removeEditorWindow(resourceName: string, title: string) { @@ -215,6 +217,7 @@ export class Workspace implements IWorkspace { async openEditorWindowById(id: string) { const window = this.editorWindowMap.get(id); + this.window?.updateState(WINDOW_STATE.inactive); if (window) { this.window = window; if (window.sleep) { @@ -222,6 +225,7 @@ export class Workspace implements IWorkspace { } this.emitChangeActiveWindow(); } + this.window?.updateState(WINDOW_STATE.active); } async openEditorWindow(name: string, title: string, options: Object, viewType?: string, sleep?: boolean) { @@ -236,6 +240,7 @@ export class Workspace implements IWorkspace { console.error(`${name} resourceType is not available`); return; } + this.window?.updateState(WINDOW_STATE.inactive); const filterWindows = this.windows.filter(d => (d.resource?.name === name && d.resource.title == title)); if (filterWindows && filterWindows.length) { this.window = filterWindows[0]; @@ -245,6 +250,7 @@ export class Workspace implements IWorkspace { this.checkWindowQueue(); } this.emitChangeActiveWindow(); + this.window?.updateState(WINDOW_STATE.active); return; } const resource = new Resource({ @@ -266,6 +272,7 @@ export class Workspace implements IWorkspace { } this.emitChangeWindow(); this.emitChangeActiveWindow(); + this.window?.updateState(WINDOW_STATE.active); } onChangeWindows(fn: () => void) { From e578f82272affec3871b580ad68787c55da0dab0 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 25 Jul 2023 15:27:07 +0800 Subject: [PATCH 211/469] feat: skeleton item add visible prop --- packages/shell/src/model/skeleton-item.ts | 4 ++++ packages/types/src/shell/model/skeleton-item.ts | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/packages/shell/src/model/skeleton-item.ts b/packages/shell/src/model/skeleton-item.ts index b91e5a19a0..cda8486ad0 100644 --- a/packages/shell/src/model/skeleton-item.ts +++ b/packages/shell/src/model/skeleton-item.ts @@ -13,6 +13,10 @@ export class SkeletonItem implements IPublicModelSkeletonItem { return this[skeletonItemSymbol].name; } + get visible() { + return this[skeletonItemSymbol].visible; + } + disable() { this[skeletonItemSymbol].disable?.(); } diff --git a/packages/types/src/shell/model/skeleton-item.ts b/packages/types/src/shell/model/skeleton-item.ts index ca262ccbf0..c505a677c6 100644 --- a/packages/types/src/shell/model/skeleton-item.ts +++ b/packages/types/src/shell/model/skeleton-item.ts @@ -2,5 +2,15 @@ * @since 1.1.7 */ export interface IPublicModelSkeletonItem { + name: string; + visible: boolean; + + disable(): void; + + enable(): void; + + hide(): void; + + show(): void; } \ No newline at end of file From 288dbd63948884666a4582efab14d260be315cca Mon Sep 17 00:00:00 2001 From: eternalsky <wsj7552715@hotmail.com> Date: Tue, 25 Jul 2023 20:00:04 +0800 Subject: [PATCH 212/469] chore(release): code-generator - 1.1.6 --- modules/code-generator/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index 193951fb03..6ff1ecb63f 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-code-generator", - "version": "1.1.5", + "version": "1.1.6", "description": "出码引擎 for LowCode Engine", "license": "MIT", "main": "lib/index.js", From d67eab0041aa0344cf3e1f9b5cbaa74dc3d4f3b9 Mon Sep 17 00:00:00 2001 From: keuby <knightchen@knx.com.cn> Date: Wed, 26 Jul 2023 14:04:19 +0800 Subject: [PATCH 213/469] feat(designer): add setRendererReady declaration (#2320) --- packages/designer/src/project/project.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 75e621d5e2..94913d9fa7 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -2,14 +2,13 @@ import { obx, computed, makeObservable, action, IEventBus, createModuleEventBus import { IDesigner } from '../designer'; import { DocumentModel, isDocumentModel } from '../document'; import type { IDocumentModel } from '../document'; -import { - IPublicTypeComponentsMap, - IPublicEnumTransformStage, - IBaseApiProject, -} from '@alilc/lowcode-types'; +import { IPublicEnumTransformStage } from '@alilc/lowcode-types'; import type { + IBaseApiProject, IPublicTypeProjectSchema, IPublicTypeRootSchema, + IPublicTypeComponentsMap, + IPublicTypeSimulatorRenderer, } from '@alilc/lowcode-types'; import { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils'; import { ISimulatorHost } from '../simulator'; @@ -87,6 +86,8 @@ export interface IProject extends Omit<IBaseApiProject< get(key: string): unknown; checkExclusive(activeDoc: DocumentModel): void; + + setRendererReady(renderer: IPublicTypeSimulatorRenderer<any, any>): void; } export class Project implements IProject { From 561598c7a219dfd460f322ba80c6e37f8edb713c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= <yuanlihao1988@gmail.com> Date: Wed, 26 Jul 2023 17:07:01 +0800 Subject: [PATCH 214/469] chore: fix window typo --- docs/docs/guide/quickStart/start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/guide/quickStart/start.md b/docs/docs/guide/quickStart/start.md index 7999d1701a..b2b728b9fe 100644 --- a/docs/docs/guide/quickStart/start.md +++ b/docs/docs/guide/quickStart/start.md @@ -11,7 +11,7 @@ title: 快速开始 ## 环境准备 -### WSL(Window 电脑) +### WSL(Windows 电脑) Window 环境需要使用 WSL 在 windows 下进行低代码引擎相关的开发。安装教程 ➡️ [WSL 安装教程](https://docs.microsoft.com/zh-cn/windows/wsl/install)。<br />**对于 Window 环境来说,之后所有需要执行命令的操作都是在 WSL 终端执行的。** From d08aa67b0a62475b1bd9979e02e2ce02233a6d57 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 27 Jul 2023 09:49:02 +0800 Subject: [PATCH 215/469] chore(release): publish 1.1.9 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 52ee714c28..9d3eb758a1 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.8", + "version": "1.1.9", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index e3d1535aa5..0b2178c3b8 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.8", + "version": "1.1.9", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -16,9 +16,9 @@ "license": "MIT", "dependencies": { "@alilc/build-plugin-lce": "^0.0.4-beta.2", - "@alilc/lowcode-editor-core": "1.1.8", - "@alilc/lowcode-types": "1.1.8", - "@alilc/lowcode-utils": "1.1.8", + "@alilc/lowcode-editor-core": "1.1.9", + "@alilc/lowcode-types": "1.1.9", + "@alilc/lowcode-utils": "1.1.9", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 939a73183b..58e8eb4814 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.1.8", + "version": "1.1.9", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.8", - "@alilc/lowcode-utils": "1.1.8", + "@alilc/lowcode-types": "1.1.9", + "@alilc/lowcode-utils": "1.1.9", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 16cc1cc098..b1802795dd 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.1.8", + "version": "1.1.9", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.1.8", - "@alilc/lowcode-editor-core": "1.1.8", - "@alilc/lowcode-types": "1.1.8", - "@alilc/lowcode-utils": "1.1.8", + "@alilc/lowcode-designer": "1.1.9", + "@alilc/lowcode-editor-core": "1.1.9", + "@alilc/lowcode-types": "1.1.9", + "@alilc/lowcode-utils": "1.1.9", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 030f14a764..4d5e4681f6 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.8", + "version": "1.1.9", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.1.8", - "@alilc/lowcode-editor-core": "1.1.8", - "@alilc/lowcode-editor-skeleton": "1.1.8", + "@alilc/lowcode-designer": "1.1.9", + "@alilc/lowcode-editor-core": "1.1.9", + "@alilc/lowcode-editor-skeleton": "1.1.9", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.8", - "@alilc/lowcode-plugin-outline-pane": "1.1.8", - "@alilc/lowcode-shell": "1.1.8", - "@alilc/lowcode-utils": "1.1.8", - "@alilc/lowcode-workspace": "1.1.8", + "@alilc/lowcode-plugin-designer": "1.1.9", + "@alilc/lowcode-plugin-outline-pane": "1.1.9", + "@alilc/lowcode-shell": "1.1.9", + "@alilc/lowcode-utils": "1.1.9", + "@alilc/lowcode-workspace": "1.1.9", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index d7796db32f..4064e585bf 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.8", + "version": "1.1.9", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 7d5a434811..16905f6159 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.1.8", + "version": "1.1.9", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.8", - "@alilc/lowcode-editor-core": "1.1.8", - "@alilc/lowcode-utils": "1.1.8", + "@alilc/lowcode-designer": "1.1.9", + "@alilc/lowcode-editor-core": "1.1.9", + "@alilc/lowcode-utils": "1.1.9", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index f6a4aea0a5..c49e11c2ef 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.1.8", + "version": "1.1.9", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.8", - "@alilc/lowcode-utils": "1.1.8", + "@alilc/lowcode-types": "1.1.9", + "@alilc/lowcode-utils": "1.1.9", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index b91511afd7..ddd160f004 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.1.8", + "version": "1.1.9", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.1.8", - "@alilc/lowcode-utils": "1.1.8", + "@alilc/lowcode-renderer-core": "1.1.9", + "@alilc/lowcode-utils": "1.1.9", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 8a456b6cf4..d2c39c0c81 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.1.8", + "version": "1.1.9", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.8", - "@alilc/lowcode-rax-renderer": "1.1.8", - "@alilc/lowcode-types": "1.1.8", - "@alilc/lowcode-utils": "1.1.8", + "@alilc/lowcode-designer": "1.1.9", + "@alilc/lowcode-rax-renderer": "1.1.9", + "@alilc/lowcode-types": "1.1.9", + "@alilc/lowcode-utils": "1.1.9", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 4af63fa78b..410d24a6bf 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.1.8", + "version": "1.1.9", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.1.8" + "@alilc/lowcode-renderer-core": "1.1.9" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 43bfd47a87..8fb1e979b3 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.1.8", + "version": "1.1.9", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.8", - "@alilc/lowcode-react-renderer": "1.1.8", - "@alilc/lowcode-types": "1.1.8", - "@alilc/lowcode-utils": "1.1.8", + "@alilc/lowcode-designer": "1.1.9", + "@alilc/lowcode-react-renderer": "1.1.9", + "@alilc/lowcode-types": "1.1.9", + "@alilc/lowcode-utils": "1.1.9", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index f0b4b3e9cb..49c9d30fe5 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.1.8", + "version": "1.1.9", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.1.8", - "@alilc/lowcode-utils": "1.1.8", + "@alilc/lowcode-types": "1.1.9", + "@alilc/lowcode-utils": "1.1.9", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.1.8", + "@alilc/lowcode-designer": "1.1.9", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index c24113d0fe..c9663e4a77 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.8", + "version": "1.1.9", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.8", - "@alilc/lowcode-editor-core": "1.1.8", - "@alilc/lowcode-editor-skeleton": "1.1.8", - "@alilc/lowcode-types": "1.1.8", - "@alilc/lowcode-utils": "1.1.8", - "@alilc/lowcode-workspace": "1.1.8", + "@alilc/lowcode-designer": "1.1.9", + "@alilc/lowcode-editor-core": "1.1.9", + "@alilc/lowcode-editor-skeleton": "1.1.9", + "@alilc/lowcode-types": "1.1.9", + "@alilc/lowcode-utils": "1.1.9", + "@alilc/lowcode-workspace": "1.1.9", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 2aef9019c3..317fbbeb73 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.8", + "version": "1.1.9", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 1e4e9fb9f9..dcc1ccdd21 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.8", + "version": "1.1.9", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.8", + "@alilc/lowcode-types": "1.1.9", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index b04a05cf94..36e8dac0f1 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.8", + "version": "1.1.9", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.8", - "@alilc/lowcode-editor-core": "1.1.8", - "@alilc/lowcode-editor-skeleton": "1.1.8", - "@alilc/lowcode-types": "1.1.8", - "@alilc/lowcode-utils": "1.1.8", + "@alilc/lowcode-designer": "1.1.9", + "@alilc/lowcode-editor-core": "1.1.9", + "@alilc/lowcode-editor-skeleton": "1.1.9", + "@alilc/lowcode-types": "1.1.9", + "@alilc/lowcode-utils": "1.1.9", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 1e3fd1951b17f3344fcd17754dedf87050f98e8f Mon Sep 17 00:00:00 2001 From: 1ncounter <1ncounter.100@gmail.com> Date: Thu, 27 Jul 2023 14:08:20 +0800 Subject: [PATCH 216/469] feat: add application level specs (#2325) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add application level specs:router,pages,etc * fix: add description to change parts --------- Co-authored-by: 林熠 <jack.lianjie@gmail.com> --- docs/docs/specs/lowcode-spec.md | 289 +++++++++++++++++++++++++++++++- 1 file changed, 281 insertions(+), 8 deletions(-) diff --git a/docs/docs/specs/lowcode-spec.md b/docs/docs/specs/lowcode-spec.md index 297381fe69..59ff85586c 100644 --- a/docs/docs/specs/lowcode-spec.md +++ b/docs/docs/specs/lowcode-spec.md @@ -25,7 +25,7 @@ sidebar_position: 0 ### 1.3 版本号 -1.0.0 +1.1.0 ### 1.4 协议版本号规范(A) @@ -124,7 +124,8 @@ sidebar_position: 0 - config: { Object } 当前应用配置信息 - meta: { Object } 当前应用元数据信息 - dataSource: { Array } 当前应用的公共数据源 - +- router: { Object } 当前应用的路由配置信息 +- pages: { Array } 当前应用的所有页面信息 描述举例: @@ -163,6 +164,7 @@ sidebar_position: 0 } }], "componentsTree": [{ // 描述内容,值类型 Array + "id": "page1", "componentName": "Page", // 单个页面,枚举类型 Page|Block|Component "fileName": "Page1", "props": {}, @@ -213,7 +215,7 @@ sidebar_position: 0 "css": "body {font-size: 12px;} .table { width: 100px;}", "config": { // 当前应用配置信息 "sdkVersion": "1.0.3", // 渲染模块版本 - "historyMode": "hash", // 浏览器路由:browser 哈希路由:hash + "historyMode": "hash", // 不推荐,推荐在 router 字段中配置 "targetRootID": "J_Container", "layout": { "componentName": "BasicLayout", @@ -250,7 +252,23 @@ sidebar_position: 0 "i18n-jwg27yo4": "Hello", "i18n-jwg27yo3": "China" } - } + }, + "router": { + "baseUrl": "/", + "historyMode": "hash", // 浏览器路由:browser 哈希路由:hash + "routes": [ + { + "path": "home", + "page": "page1" + } + ] + }, + "pages": [ + { + "id": "page1", + "treeId": "page1" + } + ] } ``` @@ -1252,7 +1270,7 @@ export const recordEvent = function(logkey, gmkey, gokey, reqMethod) { ### 2.8 当前应用配置信息(AA) -用于描述当前应用的配置信息,比如当前应用的路由模式、Shell/Layout、主题等。 +用于描述当前应用的配置信息,比如当前应用的 Shell/Layout、主题等。 > 注意:该字段为扩展字段,消费方式由各自场景自己决定,包括运行时和出码。 @@ -1267,6 +1285,192 @@ export const recordEvent = function(logkey, gmkey, gokey, reqMethod) { 用于描述当前应用的公共数据源,数据结构跟容器结构里的 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 文件目录 @@ -1320,9 +1524,78 @@ export const recordEvent = function(logkey, gmkey, gokey, reqMethod) { ### 3.2 应用级别 APIs > 下文中 `xxx` 代指任意 API #### 3.2.1 路由 Router API - - this.location.`xxx` - - this.history.`xxx` - - this.match.`xxx` + - 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` From 2bbb4099e315d9b075afc45a51b5d9b5a106fdcb Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 27 Jul 2023 14:16:33 +0800 Subject: [PATCH 217/469] chore(docs): publish docs 1.1.0, which upgrade lowcode-spec --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 269bd2df64..a2299251e4 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.33", + "version": "1.1.0", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 14390f000d93f7fc2e1f09e54d3d972a39593ca5 Mon Sep 17 00:00:00 2001 From: AndyJin <jjj706@163.com> Date: Tue, 1 Aug 2023 09:54:14 +0800 Subject: [PATCH 218/469] fix: Optimize the initialization method for masterPaneController (#2333) --- packages/plugin-outline-pane/src/index.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/plugin-outline-pane/src/index.tsx b/packages/plugin-outline-pane/src/index.tsx index 180b424ea5..addebbb402 100644 --- a/packages/plugin-outline-pane/src/index.tsx +++ b/packages/plugin-outline-pane/src/index.tsx @@ -18,7 +18,9 @@ export function OutlinePaneContext(props: { hideFilter?: boolean; }) { const treeMaster = props.treeMaster || new TreeMaster(props.pluginContext, props.options); - const [masterPaneController, setMasterPaneController] = useState(new PaneController(props.paneName || MasterPaneName, treeMaster)); + const [masterPaneController, setMasterPaneController] = useState( + () => new PaneController(props.paneName || MasterPaneName, treeMaster), + ); useEffect(() => { return treeMaster.onPluginContextChange(() => { setMasterPaneController(new PaneController(props.paneName || MasterPaneName, treeMaster)); @@ -40,7 +42,9 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { const { skeleton, config, canvas, project } = ctx; let isInFloatArea = true; - const hasPreferenceForOutline = config.getPreference().contains('outline-pane-pinned-status-isFloat', 'skeleton'); + const hasPreferenceForOutline = config + .getPreference() + .contains('outline-pane-pinned-status-isFloat', 'skeleton'); if (hasPreferenceForOutline) { isInFloatArea = config.getPreference().get('outline-pane-pinned-status-isFloat', 'skeleton'); } @@ -160,4 +164,4 @@ OutlinePlugin.meta = { ], }, }; -OutlinePlugin.pluginName = 'OutlinePlugin'; \ No newline at end of file +OutlinePlugin.pluginName = 'OutlinePlugin'; From 8117b450baa6a25412707797eccdc749b89960b9 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 1 Aug 2023 14:45:31 +0800 Subject: [PATCH 219/469] docs: add setterDetails category --- docs/config/sidebars.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/config/sidebars.js b/docs/config/sidebars.js index 77a2e1f22d..b8a7587d91 100644 --- a/docs/config/sidebars.js +++ b/docs/config/sidebars.js @@ -64,6 +64,11 @@ module.exports = { href: 'https://github.com/alibaba/lowcode-engine/releases', }, ...getDocsFromDir('guide/appendix'), + { + type: 'category', + label: '预置设置器详情', + items: getDocsFromDir('guide/appendix/setterDetails'), + }, ], }, { From 89b666dab85174d3521a17cc1aaedf13b59be4d9 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 10 Aug 2023 15:50:08 +0800 Subject: [PATCH 220/469] refactor: defaultViewType renamed to defaultViewName --- packages/shell/src/model/window.ts | 2 +- .../types/src/shell/type/resource-type-config.ts | 8 +++++++- packages/workspace/src/resource.ts | 8 ++++---- packages/workspace/src/window.ts | 16 ++++++++-------- packages/workspace/src/workspace.ts | 10 +++++----- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index 3e6bd64507..2b5e0dd8c3 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -32,7 +32,7 @@ export class Window implements IPublicModelWindow { } changeViewType(viewName: string) { - this[windowSymbol].changeViewType(viewName, false); + this[windowSymbol].changeViewName(viewName, false); } onChangeViewType(fun: (viewName: string) => void): IPublicTypeDisposable { diff --git a/packages/types/src/shell/type/resource-type-config.ts b/packages/types/src/shell/type/resource-type-config.ts index e47afb53d5..474987b529 100644 --- a/packages/types/src/shell/type/resource-type-config.ts +++ b/packages/types/src/shell/type/resource-type-config.ts @@ -8,8 +8,14 @@ export interface IPublicResourceTypeConfig { /** 资源 icon 标识 */ icon?: React.ReactElement; + /** + * 默认视图类型 + * @deprecated + */ + defaultViewType?: string; + /** 默认视图类型 */ - defaultViewType: string; + defaultViewName: string; /** 资源视图 */ editorViews: IPublicTypeEditorView[]; diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index 1d328b6c6c..a7ecc59b2e 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -16,7 +16,7 @@ export interface IBaseResource<T> extends IBaseModelResource<T> { get editorViews(): IPublicTypeEditorView[]; - get defaultViewType(): string; + get defaultViewName(): string | undefined; getEditorView(name: string): IPublicTypeEditorView | undefined; @@ -41,7 +41,7 @@ export class Resource implements IResource { } get viewName() { - return this.resourceData.viewName || (this.resourceData as any).viewType || this.defaultViewType; + return this.resourceData.viewName || (this.resourceData as any).viewType || this.defaultViewName; } get description() { @@ -116,8 +116,8 @@ export class Resource implements IResource { return this.resourceTypeInstance.editorViews; } - get defaultViewType() { - return this.resourceTypeInstance.defaultViewType; + get defaultViewName() { + return this.resourceTypeInstance.defaultViewName || this.resourceTypeInstance.defaultViewType; } getEditorView(name: string) { diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index b6e345f19e..2c670346fb 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -8,7 +8,7 @@ import { IPublicModelWindow, IPublicTypeDisposable } from '@alilc/lowcode-types' interface IWindowCOnfig { title: string | undefined; options?: Object; - viewType?: string | undefined; + viewName?: string | undefined; sleep?: boolean; } @@ -19,7 +19,7 @@ export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'chan editorView: IViewContext; - changeViewType: (name: string, ignoreEmit?: boolean) => void; + changeViewName: (name: string, ignoreEmit?: boolean) => void; initReady: boolean; @@ -130,7 +130,7 @@ export class EditorWindow implements IEditorWindow { this.workspace.emitWindowRendererReady(); }); this.url = await this.resource.url(); - this.setDefaultViewType(); + this.setDefaultViewName(); this.initReady = true; this.workspace.checkWindowQueue(); this.sleep = false; @@ -146,7 +146,7 @@ export class EditorWindow implements IEditorWindow { const name = editorViews[i].viewName; await this.initViewType(name); if (!this.editorView) { - this.changeViewType(name); + this.changeViewName(name); } } }; @@ -166,13 +166,13 @@ export class EditorWindow implements IEditorWindow { } for (let i = 0; i < editorViews.length; i++) { const name = editorViews[i].viewName; - this.changeViewType(name); + this.changeViewName(name); await this.editorViews.get(name)?.init(); } }; - setDefaultViewType = () => { - this.changeViewType(this.config.viewType ?? this.resource.defaultViewType); + setDefaultViewName = () => { + this.changeViewName(this.config.viewName ?? this.resource.defaultViewName!); }; get resourceType() { @@ -188,7 +188,7 @@ export class EditorWindow implements IEditorWindow { this.editorViews.set(name, editorView); }; - changeViewType = (name: string, ignoreEmit: boolean = true) => { + changeViewName = (name: string, ignoreEmit: boolean = true) => { this.editorView?.setActivate(false); this.editorView = this.editorViews.get(name)!; diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index e180d4a2fb..41be09fcf3 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -95,7 +95,7 @@ export class Workspace implements IWorkspace { name: string; title: string; options: Object; - viewType?: string; + viewName?: string; }[] = []; constructor( @@ -114,7 +114,7 @@ export class Workspace implements IWorkspace { const windowInfo = this.windowQueue.shift(); if (windowInfo) { - this.openEditorWindow(windowInfo.name, windowInfo.title, windowInfo.options, windowInfo.viewType); + this.openEditorWindow(windowInfo.name, windowInfo.title, windowInfo.options, windowInfo.viewName); } } @@ -228,10 +228,10 @@ export class Workspace implements IWorkspace { this.window?.updateState(WINDOW_STATE.active); } - async openEditorWindow(name: string, title: string, options: Object, viewType?: string, sleep?: boolean) { + async openEditorWindow(name: string, title: string, options: Object, viewName?: string, sleep?: boolean) { if (this.window && !this.window?.initReady && !sleep) { this.windowQueue.push({ - name, title, options, viewType, + name, title, options, viewName, }); return; } @@ -261,7 +261,7 @@ export class Workspace implements IWorkspace { const window = new EditorWindow(resource, this, { title, options, - viewType, + viewName, sleep, }); this.windows = [...this.windows, window]; From 0eeee1feee3268ca5f970250fda1cfb52725191f Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 11 Aug 2023 16:35:30 +0800 Subject: [PATCH 221/469] feat(skeleton): add skeleton.getPanel api --- docs/docs/api/skeleton.md | 15 +++++++++++++++ packages/shell/src/api/skeleton.ts | 9 +++++++++ packages/shell/src/model/skeleton-item.ts | 4 ++++ packages/types/src/shell/api/skeleton.ts | 7 +++++++ packages/types/src/shell/model/skeleton-item.ts | 5 +++++ 5 files changed, 40 insertions(+) diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index bcf4225db0..c378792de0 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -178,6 +178,21 @@ IWidgetBaseConfig 定义如下: 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 diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index 238931a25e..0d17075257 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -76,6 +76,15 @@ export class Skeleton implements IPublicApiSkeleton { return this[skeletonSymbol][normalizeArea(areaName)].container.items?.map(d => new SkeletonItem(d)); } + getPanel(name: string) { + const item = this[skeletonSymbol].getPanel(name); + if (!item) { + return; + } + + return new SkeletonItem(item); + } + /** * 显示面板 * @param name diff --git a/packages/shell/src/model/skeleton-item.ts b/packages/shell/src/model/skeleton-item.ts index cda8486ad0..7f1224c0d9 100644 --- a/packages/shell/src/model/skeleton-item.ts +++ b/packages/shell/src/model/skeleton-item.ts @@ -32,4 +32,8 @@ export class SkeletonItem implements IPublicModelSkeletonItem { show() { this[skeletonItemSymbol].show(); } + + toggle() { + this[skeletonItemSymbol].toggle(); + } } \ No newline at end of file diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts index 13ba3468b4..2ad561518b 100644 --- a/packages/types/src/shell/api/skeleton.ts +++ b/packages/types/src/shell/api/skeleton.ts @@ -20,6 +20,13 @@ export interface IPublicApiSkeleton { */ remove(config: IPublicTypeSkeletonConfig): number | undefined; + /** + * 获取面板实例 + * @param name 面板名称 + * @since v1.1.10 + */ + getPanel(name: string): IPublicModelSkeletonItem | undefined; + /** * 展示指定 Panel 实例 * show panel by name diff --git a/packages/types/src/shell/model/skeleton-item.ts b/packages/types/src/shell/model/skeleton-item.ts index c505a677c6..beb18f2228 100644 --- a/packages/types/src/shell/model/skeleton-item.ts +++ b/packages/types/src/shell/model/skeleton-item.ts @@ -13,4 +13,9 @@ export interface IPublicModelSkeletonItem { hide(): void; show(): void; + + /** + * @since v1.1.10 + */ + toggle(): void; } \ No newline at end of file From c458b1b2ec657d98d60638678fe718ea0e908820 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 11 Aug 2023 17:20:32 +0800 Subject: [PATCH 222/469] fix(material): when the assets exist, use onChangeAssets api, the callback is called immediately --- packages/editor-core/src/editor.ts | 10 ++++++++++ packages/shell/src/api/material.ts | 2 +- packages/types/src/shell/model/editor.ts | 14 ++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index e1d25bdfff..de2191f18f 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -222,6 +222,16 @@ export class Editor extends EventEmitter implements IEditor { }; } + onChange<T = undefined, KeyOrType extends IPublicTypeEditorValueKey = any>( + keyOrType: KeyOrType, + fn: (data: IPublicTypeEditorGetResult<T, KeyOrType>) => void, + ): () => void { + this.setWait(keyOrType, fn); + return () => { + this.delWait(keyOrType, fn); + }; + } + register(data: any, key?: IPublicTypeEditorValueKey): void { this.context.set(key || data, data); this.notifyGot(key || data); diff --git a/packages/shell/src/api/material.ts b/packages/shell/src/api/material.ts index ea9d6e01ba..39b21848e0 100644 --- a/packages/shell/src/api/material.ts +++ b/packages/shell/src/api/material.ts @@ -181,7 +181,7 @@ export class Material implements IPublicApiMaterial { onChangeAssets(fn: () => void): IPublicTypeDisposable { const dispose = [ // 设置 assets,经过 setAssets 赋值 - this[editorSymbol].onGot('assets', fn), + this[editorSymbol].onChange('assets', fn), // 增量设置 assets,经过 loadIncrementalAssets 赋值 this[editorSymbol].eventBus.on('designer.incrementalAssetsReady', fn), ]; diff --git a/packages/types/src/shell/model/editor.ts b/packages/types/src/shell/model/editor.ts index 11d75aac75..e6171f0312 100644 --- a/packages/types/src/shell/model/editor.ts +++ b/packages/types/src/shell/model/editor.ts @@ -15,13 +15,27 @@ export interface IPublicModelEditor extends StrictEventEmitter<EventEmitter, Glo set: (key: IPublicTypeEditorValueKey, data: any) => void | Promise<void>; + /** + * 获取 keyOrType 一次 + */ onceGot: <T = undefined, KeyOrType extends IPublicTypeEditorValueKey = any>(keyOrType: KeyOrType) => Promise<IPublicTypeEditorGetResult<T, KeyOrType>>; + /** + * 获取 keyOrType 多次 + */ onGot: <T = undefined, KeyOrType extends IPublicTypeEditorValueKey = any>( keyOrType: KeyOrType, fn: (data: IPublicTypeEditorGetResult<T, KeyOrType>) => void ) => () => void; + /** + * 监听 keyOrType 变化 + */ + onChange: <T = undefined, KeyOrType extends IPublicTypeEditorValueKey = any>( + keyOrType: KeyOrType, + fn: (data: IPublicTypeEditorGetResult<T, KeyOrType>) => void + ) => () => void; + register: (data: any, key?: IPublicTypeEditorValueKey, options?: IPublicTypeEditorRegisterOptions) => void; get eventBus(): IPublicApiEvent; From abd9ed3adc1ea2871b702faf2ce88657dc08b8cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Tue, 15 Aug 2023 12:04:34 +0800 Subject: [PATCH 223/469] =?UTF-8?q?docs:=20update=20init.md,=20add=20devic?= =?UTF-8?q?e=20=E5=8F=82=E6=95=B0=E8=AF=A6=E7=BB=86=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/api/init.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/docs/api/init.md b/docs/docs/api/init.md index 9917d1f72d..10e7541765 100644 --- a/docs/docs/api/init.md +++ b/docs/docs/api/init.md @@ -118,7 +118,7 @@ init(document.getElementById('engine'), { enableCondition: false, }); ``` -### + ### 默认打开移动端画布 ```typescript import { init } from '@alilc/lowcode-engine'; @@ -126,6 +126,25 @@ import { init } from '@alilc/lowcode-engine'; init({ device: 'mobile', }); +``` +### device 参数详细说明 + +引擎默认支持的 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; +} + ``` ### 使用 utils 第三方工具扩展 From 7c8652057ff6e2679bf249550f8b77acb906d0b8 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 15 Aug 2023 12:56:42 +0800 Subject: [PATCH 224/469] docs: publish docs 1.1.1 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index a2299251e4..02fa91b7c2 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.0", + "version": "1.1.1", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 5738394a2e04d44e4b1d3db6b6b314b17699334a Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 15 Aug 2023 15:25:21 +0800 Subject: [PATCH 225/469] feat: remove IPublicTypeFieldExtraProps.virtual definition --- docs/docs/guide/expand/editor/metaSpec.md | 1 - packages/types/src/shell/type/field-extra-props.ts | 5 ----- 2 files changed, 6 deletions(-) diff --git a/docs/docs/guide/expand/editor/metaSpec.md b/docs/docs/guide/expand/editor/metaSpec.md index 2f874925fd..dda16a9cb3 100644 --- a/docs/docs/guide/expand/editor/metaSpec.md +++ b/docs/docs/guide/expand/editor/metaSpec.md @@ -460,7 +460,6 @@ import parse from '@alilc/lowcode-material-parser'; { name: 'back', title: ' ', - virtual: () => true, display: 'plain', setter: BackwardSetter, } diff --git a/packages/types/src/shell/type/field-extra-props.ts b/packages/types/src/shell/type/field-extra-props.ts index bfaff1a468..3e2df280b7 100644 --- a/packages/types/src/shell/type/field-extra-props.ts +++ b/packages/types/src/shell/type/field-extra-props.ts @@ -43,11 +43,6 @@ export interface IPublicTypeFieldExtraProps { */ autorun?: (target: IPublicModelSettingField) => void; - /** - * is this field is a virtual field that not save to schema - */ - virtual?: (target: IPublicModelSettingField) => boolean; - /** * default collapsed when display accordion */ From 942972c593cbdafb282e0a7fbddafa2ba1e9461e Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 15 Aug 2023 17:38:06 +0800 Subject: [PATCH 226/469] fix(node-children): solve the crash of null in schema.children --- packages/designer/src/document/node/node-children.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index 4fb1c3d226..bf982cbfa7 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -102,7 +102,7 @@ export class NodeChildren implements INodeChildren { options: any = {}, ) { makeObservable(this); - this.children = (Array.isArray(data) ? data : [data]).map((child) => { + this.children = (Array.isArray(data) ? data : [data]).filter(child => !!child).map((child) => { return this.owner.document?.createNode(child, options.checkId); }); } @@ -127,7 +127,7 @@ export class NodeChildren implements INodeChildren { } import(data?: IPublicTypeNodeData | IPublicTypeNodeData[], checkId = false) { - data = data ? (Array.isArray(data) ? data : [data]) : []; + data = (data ? (Array.isArray(data) ? data : [data]) : []).filter(d => !!d); const originChildren = this.children.slice(); this.children.forEach((child) => child.internalSetParent(null)); From f7c1f1e716c855c3e8725cb5acd4ea124a841713 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 16 Aug 2023 11:34:56 +0800 Subject: [PATCH 227/469] feat(event): add event.prependListener api --- docs/docs/api/event.md | 13 +++++++++++++ packages/editor-core/src/event-bus.ts | 8 ++++++++ packages/shell/src/api/event.ts | 14 ++++++++++++++ packages/types/src/shell/api/event.ts | 7 +++++++ 4 files changed, 42 insertions(+) diff --git a/docs/docs/api/event.md b/docs/docs/api/event.md index 9e2bdf641b..0919b41fd2 100644 --- a/docs/docs/api/event.md +++ b/docs/docs/api/event.md @@ -25,6 +25,19 @@ 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 取消监听事件 diff --git a/packages/editor-core/src/event-bus.ts b/packages/editor-core/src/event-bus.ts index 95f26f77ec..ae9d28905b 100644 --- a/packages/editor-core/src/event-bus.ts +++ b/packages/editor-core/src/event-bus.ts @@ -55,6 +55,14 @@ export class EventBus implements IEventBus { }; } + prependListener(event: string, listener: (...args: any[]) => void): () => void { + this.eventEmitter.prependListener(event, listener); + this.getLogger().debug(`${this.getMsgPrefix('prependListener')} ${event}`); + return () => { + this.off(event, listener); + }; + } + /** * 取消监听事件 * @param event 事件名称 diff --git a/packages/shell/src/api/event.ts b/packages/shell/src/api/event.ts index 0fb41966e7..f2adca98c1 100644 --- a/packages/shell/src/api/event.ts +++ b/packages/shell/src/api/event.ts @@ -36,6 +36,20 @@ export class Event implements IPublicApiEvent { } } + /** + * 监听事件,会在其他回调函数之前执行 + * @param event 事件名称 + * @param listener 事件回调 + */ + prependListener(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable { + if (isPluginEventName(event)) { + return this[eventBusSymbol].prependListener(event, listener); + } else { + logger.warn(`fail to prependListener event ${event}, event should have a prefix like 'somePrefix:eventName'`); + return () => {}; + } + } + /** * 取消监听事件 * @param event 事件名称 diff --git a/packages/types/src/shell/api/event.ts b/packages/types/src/shell/api/event.ts index 02b8bc5b3f..5b8c59e139 100644 --- a/packages/types/src/shell/api/event.ts +++ b/packages/types/src/shell/api/event.ts @@ -10,6 +10,13 @@ export interface IPublicApiEvent { */ on(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable; + /** + * 监听事件,会在其他回调函数之前执行 + * add monitor to a event + * @param event 事件名称 + * @param listener 事件回调 + */ + prependListener(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable; /** * 取消监听事件 From bc0b94007a92b2f32fe6692b709019f87bd14f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Wed, 16 Aug 2023 16:43:15 +0800 Subject: [PATCH 228/469] docs: update faq009.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 完善“物料出现 Component Not Found 相关报错” FAQ --- docs/docs/faq/faq009.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/docs/faq/faq009.md b/docs/docs/faq/faq009.md index f1247bfa41..4115384353 100644 --- a/docs/docs/faq/faq009.md +++ b/docs/docs/faq/faq009.md @@ -28,6 +28,28 @@ 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') From 67a0c9ebdb9c121e08492a780f661e770ee437bc Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Wed, 16 Aug 2023 16:46:01 +0800 Subject: [PATCH 229/469] docs: publish docs 1.1.2 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 02fa91b7c2..45704074da 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.1", + "version": "1.1.2", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From a389ec184ce88cac229a2e9129103ec8a6f0e367 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 17 Aug 2023 15:18:31 +0800 Subject: [PATCH 230/469] feat: mark the loaded remote description descriptions to reduce loading --- packages/editor-core/src/editor.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index de2191f18f..f31a2a2dda 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -35,6 +35,10 @@ const keyBlacklist = [ 'innerPlugins', ]; +const AssetsCache: { + [key: string]: IPublicTypeRemoteComponentDescription; +} = {}; + export declare interface Editor extends StrictEventEmitter<EventEmitter, GlobalEvent.EventConfig> { addListener(event: string | symbol, listener: (...args: any[]) => void): this; once(event: string | symbol, listener: (...args: any[]) => void): this; @@ -143,9 +147,15 @@ export class Editor extends EventEmitter implements IEditor { // 如果有远程组件描述协议,则自动加载并补充到资产包中,同时出发 designer.incrementalAssetsReady 通知组件面板更新数据 if (remoteComponentDescriptions && remoteComponentDescriptions.length) { await Promise.all( - remoteComponentDescriptions.map(async (component: any) => { + remoteComponentDescriptions.map(async (component: IPublicTypeRemoteComponentDescription) => { const { exportName, url, npm } = component; - await (new AssetLoader()).load(url); + if (!url || !exportName) { + return; + } + if (!AssetsCache[exportName] || !npm?.version || AssetsCache[exportName].npm?.version !== npm?.version) { + await (new AssetLoader()).load(url); + } + AssetsCache[exportName] = component; function setAssetsComponent(component: any, extraNpmInfo: any = {}) { const components = component.components; assets.componentList = assets.componentList?.concat(component.componentList || []); @@ -181,14 +191,14 @@ export class Editor extends EventEmitter implements IEditor { }); }); } - if (window[exportName]) { - if (Array.isArray(window[exportName])) { - setArrayAssets(window[exportName] as any); + if ((window as any)[exportName]) { + if (Array.isArray((window as any)[exportName])) { + setArrayAssets((window as any)[exportName] as any); } else { - setAssetsComponent(window[exportName] as any); + setAssetsComponent((window as any)[exportName] as any); } } - return window[exportName]; + return (window as any)[exportName]; }), ); } From 494017a095a3ab0ec4aff4b70c69fd10d043f584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Thu, 17 Aug 2023 16:25:40 +0800 Subject: [PATCH 231/469] docs: update faq013.md --- docs/docs/faq/faq013.md | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/docs/faq/faq013.md b/docs/docs/faq/faq013.md index bf073e7334..a8f86b2948 100644 --- a/docs/docs/faq/faq013.md +++ b/docs/docs/faq/faq013.md @@ -10,9 +10,28 @@ tags: [FAQ] ## 处理方式 ### 【推荐】升级到 Engine Verison 1.0.11 以上 ### 新增 save propsReducer -通过新增 Save 态的 propsReducer,将 hidden props 去掉。 -参考: -[https://github.com/alibaba/lowcode-demo/blob/main/src/sample-plugins/delete-hidden-transducer/index.ts](https://github.com/alibaba/lowcode-demo/blob/main/src/sample-plugins/delete-hidden-transducer/index.ts) + +通过新增 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 From 7b85128ee52c4326bbdbd2a48d88bb91525688de Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 17 Aug 2023 16:37:07 +0800 Subject: [PATCH 232/469] docs: publish docs 1.1.3 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 45704074da..6267047000 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.2", + "version": "1.1.3", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 3b36926c7083572f6f3b96435da73e646ffbcb94 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 17 Aug 2023 17:26:02 +0800 Subject: [PATCH 233/469] feat: after the component title is modified, update the title of the ComponentAction area --- .../designer/src/builtin-simulator/node-selector/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/designer/src/builtin-simulator/node-selector/index.tsx b/packages/designer/src/builtin-simulator/node-selector/index.tsx index 07ae754aae..0723115da2 100644 --- a/packages/designer/src/builtin-simulator/node-selector/index.tsx +++ b/packages/designer/src/builtin-simulator/node-selector/index.tsx @@ -1,6 +1,6 @@ import { Overlay } from '@alifd/next'; import React, { MouseEvent } from 'react'; -import { Title } from '@alilc/lowcode-editor-core'; +import { Title, observer } from '@alilc/lowcode-editor-core'; import { canClickNode } from '@alilc/lowcode-utils'; import './index.less'; @@ -18,6 +18,7 @@ export interface IState { type UnionNode = INode | null; +@observer export default class InstanceNodeSelector extends React.Component<IProps, IState> { state: IState = { parentNodes: [], From e1dd8e0c5a78c0aed62067bf259bd593fad7f5fa Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 17 Aug 2023 18:55:40 +0800 Subject: [PATCH 234/469] docs: add config options doc --- docs/docs/api/configOptions.md | 285 +++++++++++++++++++++++++++++++++ docs/docs/api/init.md | 111 +------------ 2 files changed, 286 insertions(+), 110 deletions(-) create mode 100644 docs/docs/api/configOptions.md diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md new file mode 100644 index 0000000000..3f8e75df29 --- /dev/null +++ b/docs/docs/api/configOptions.md @@ -0,0 +1,285 @@ +--- +title: config options - 配置列表 +sidebar_position: 13 +--- + +> **@types** [IPublicTypeEngineOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/engine-options.ts)<br/> + +## 配置方式 + +#### 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: Node) => Node; +``` + +#### supportVariableGlobally - 全局变量配置 + +`@type {boolean}` `@default {false}` + +设置所有属性支持变量配置 + +开启拖拽组件时,即将被放入的容器是否有视觉反馈 + +#### customizeIgnoreSelectors - 点击忽略 + +定制画布中点击被忽略的 selectors + +类型定义: + +```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}` + +鼠标事件在画布中是否允许冒泡 + +#### enableReactiveContainer + +`@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 + +#### 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 组件 + +### 其他 + +#### enableStrictPluginMode + +`@type {boolean}` + +开启严格插件模式,默认值:STRICT_PLUGIN_MODE_DEFAULT , 严格模式下,插件将无法通过 engineOptions 传递自定义配置项 + +#### requestHandlersMap + +数据源引擎的请求处理器映射 + +#### customPluginTransducer + +插件处理中间件,方便提供插件调试能力 + +类型定义 + +```typescript +customPluginTransducer: async (originPlugin: IPublicTypePlugin, ctx: IPublicModelPluginContext, options): IPublicTypePlugin; +``` + +#### defaultOutlinePaneProps + +`@type {object}` + +大纲树插件面板默认 props + + diff --git a/docs/docs/api/init.md b/docs/docs/api/init.md index 10e7541765..55b116a579 100644 --- a/docs/docs/api/init.md +++ b/docs/docs/api/init.md @@ -17,97 +17,7 @@ sidebar_position: 10 function init(container?: Element, options?: IPublicTypeEngineOptions): void ``` -**初始化引擎的参数** - -```typescript -interface IPublicTypeEngineOptions { - /** - * 指定初始化的 device - */ - device?: 'default' | 'mobile'; - /** - * 指定初始化的 deviceClassName,挂载到画布的顶层节点上 - */ - deviceClassName?: string; - /** - * 是否开启 condition 的能力,默认在设计器中不管 condition 是啥都正常展示 - */ - enableCondition?: boolean; - /** - * 开启拖拽组件时,即将被放入的容器是否有视觉反馈,默认值:false - */ - enableReactiveContainer?: boolean; - /** - * 关闭画布自动渲染,在资产包多重异步加载的场景有效,默认值:false - */ - disableAutoRender?: boolean; - /** - * 打开画布的锁定操作,默认值:false - */ - enableCanvasLock?: boolean; - /** - * 容器锁定后,容器本身是否可以设置属性,仅当画布锁定特性开启时生效,默认值为:false - */ - enableLockedNodeSetting?: boolean; - /** - * 开启画布上的鼠标事件的冒泡,默认值:false - */ - enableMouseEventPropagationInCanvas?: boolean; - /** - * 关闭拖拽组件时的虚线响应,性能考虑,默认值:false - */ - disableDetecting?: boolean; - /** - * 定制画布中点击被忽略的 selectors,默认值:undefined - */ - customizeIgnoreSelectors?: (defaultIgnoreSelectors: string[]) => string[]; - /** - * 禁止默认的设置面板,默认值:false - */ - disableDefaultSettingPanel?: boolean; - /** - * 禁止默认的设置器,默认值:false - */ - disableDefaultSetters?: boolean; - /** - * 当选中节点切换时,是否停留在相同的设置 tab 上,默认值:false - */ - stayOnTheSameSettingTab?: boolean; - /** - * 自定义 loading 组件 - */ - loadingComponent?: ComponentType; - - /** - * @default true - * JSExpression 是否只支持使用 this 来访问上下文变量,假如需要兼容原来的 'state.xxx',则设置为 false - */ - thisRequiredInJSE?: boolean; - - /** - * @default false - * >= 1.0.14 - * 当开启组件未找到严格模式时,渲染模块不会默认给一个容器组件 - */ - enableStrictNotFoundMode?: boolean; - - /** - * 配置指定节点为根组件 - * >= 1.0.15 - */ - focusNodeSelector?: (rootNode: Node) => Node; - - /** - * 工具类扩展 - */ - appHelper?: { - utils?: {}; - } - - [key: string]: any; -} -``` -> 源码详见 [IPublicTypeEngineOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/engine-options.ts) +[**初始化引擎配置参数列表**](./configOptions) ## 使用示例 @@ -126,25 +36,6 @@ import { init } from '@alilc/lowcode-engine'; init({ device: 'mobile', }); -``` -### device 参数详细说明 - -引擎默认支持的 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; -} - ``` ### 使用 utils 第三方工具扩展 From 82ecee98c5e64a6f41467de2fd666bab26cd8d81 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 18 Aug 2023 09:34:43 +0800 Subject: [PATCH 235/469] docs: publish docs 1.1.4 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 6267047000..c454117331 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.3", + "version": "1.1.4", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 4128654347d06406a385a724028f90640cbfb07c Mon Sep 17 00:00:00 2001 From: Rainke <woshihepeng520@163.com> Date: Fri, 18 Aug 2023 15:01:11 +0800 Subject: [PATCH 236/469] fix: default FaultComponent can not get componentName (#2385) --- .../renderer-core/src/renderer/renderer.tsx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/renderer-core/src/renderer/renderer.tsx b/packages/renderer-core/src/renderer/renderer.tsx index 88cc0ce025..09559b6f89 100644 --- a/packages/renderer-core/src/renderer/renderer.tsx +++ b/packages/renderer-core/src/renderer/renderer.tsx @@ -135,17 +135,20 @@ export default function rendererFactory(): IRenderComponent { return engine.createElement(engine.getFaultComponent(), { ...this.props, error: this.state.error, + componentName: this.props._componentName }); } return originRender.call(this); }; - const originShouldComponentUpdate = SetComponent.prototype.shouldComponentUpdate; - SetComponent.prototype.shouldComponentUpdate = function (nextProps: IRendererProps, nextState: any) { - if (nextState && nextState.engineRenderError) { - return true; - } - return originShouldComponentUpdate ? originShouldComponentUpdate.call(this, nextProps, nextState) : true; - }; + if(!(SetComponent.prototype instanceof PureComponent)) { + const originShouldComponentUpdate = SetComponent.prototype.shouldComponentUpdate; + SetComponent.prototype.shouldComponentUpdate = function (nextProps: IRendererProps, nextState: any) { + if (nextState && nextState.engineRenderError) { + return true; + } + return originShouldComponentUpdate ? originShouldComponentUpdate.call(this, nextProps, nextState) : true; + }; + } } createElement(SetComponent: any, props: any, children?: any) { From 15f5675ddd75b453249ec388164767a0412444d9 Mon Sep 17 00:00:00 2001 From: kyoonart <pengtaocc@foxmail.com> Date: Fri, 18 Aug 2023 15:17:00 +0800 Subject: [PATCH 237/469] feat: outline-plugin-pane support overflow-x scroll & delete node (#2376) --- .../src/controllers/tree-node.ts | 4 ++- .../plugin-outline-pane/src/icons/delete.tsx | 11 +++++++ .../plugin-outline-pane/src/icons/index.ts | 1 + .../plugin-outline-pane/src/locale/en-US.json | 3 +- .../plugin-outline-pane/src/locale/zh-CN.json | 3 +- .../plugin-outline-pane/src/views/style.less | 32 +++++++++++++------ .../src/views/tree-title.tsx | 32 ++++++++++++++++--- 7 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 packages/plugin-outline-pane/src/icons/delete.tsx diff --git a/packages/plugin-outline-pane/src/controllers/tree-node.ts b/packages/plugin-outline-pane/src/controllers/tree-node.ts index 92bf374d86..34d06fee0b 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-node.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-node.ts @@ -178,7 +178,9 @@ export default class TreeNode { this.node.lock(flag); this.event.emit(EVENT_NAMES.lockedChanged, flag); } - + deleteNode(node: IPublicModelNode) { + node && node.remove(); + } onFilterResultChanged(fn: () => void): IPublicTypeDisposable { this.event.on(EVENT_NAMES.filterResultChanged, fn); return () => { diff --git a/packages/plugin-outline-pane/src/icons/delete.tsx b/packages/plugin-outline-pane/src/icons/delete.tsx new file mode 100644 index 0000000000..1f93600196 --- /dev/null +++ b/packages/plugin-outline-pane/src/icons/delete.tsx @@ -0,0 +1,11 @@ +import { SVGIcon, IconProps } from '@alilc/lowcode-utils'; + +export function IconDelete(props: IconProps) { + return ( + <SVGIcon viewBox="0 0 1024 1024" {...props}> + <path d="M224 256v639.84A64 64 0 0 0 287.84 960h448.32A64 64 0 0 0 800 895.84V256h64a32 32 0 1 0 0-64H160a32 32 0 1 0 0 64h64zM384 96c0-17.664 14.496-32 31.904-32h192.192C625.696 64 640 78.208 640 96c0 17.664-14.496 32-31.904 32H415.904A31.872 31.872 0 0 1 384 96z m-96 191.744C288 270.208 302.4 256 320.224 256h383.552C721.6 256 736 270.56 736 287.744v576.512C736 881.792 721.6 896 703.776 896H320.224A32.224 32.224 0 0 1 288 864.256V287.744zM352 352c0-17.696 14.208-32.032 32-32.032 17.664 0 32 14.24 32 32v448c0 17.664-14.208 32-32 32-17.664 0-32-14.24-32-32V352z m128 0c0-17.696 14.208-32.032 32-32.032 17.664 0 32 14.24 32 32v448c0 17.664-14.208 32-32 32-17.664 0-32-14.24-32-32V352z m128 0c0-17.696 14.208-32.032 32-32.032 17.664 0 32 14.24 32 32v448c0 17.664-14.208 32-32 32-17.664 0-32-14.24-32-32V352z" /> + </SVGIcon> + ); +} + +IconDelete.displayName = 'IconDelete'; diff --git a/packages/plugin-outline-pane/src/icons/index.ts b/packages/plugin-outline-pane/src/icons/index.ts index ad90250818..d28f61dd28 100644 --- a/packages/plugin-outline-pane/src/icons/index.ts +++ b/packages/plugin-outline-pane/src/icons/index.ts @@ -9,3 +9,4 @@ export * from './loop'; export * from './radio-active'; export * from './radio'; export * from './setting'; +export * from './delete'; diff --git a/packages/plugin-outline-pane/src/locale/en-US.json b/packages/plugin-outline-pane/src/locale/en-US.json index b0f3d3e4a3..9ade9e66f4 100644 --- a/packages/plugin-outline-pane/src/locale/en-US.json +++ b/packages/plugin-outline-pane/src/locale/en-US.json @@ -18,5 +18,6 @@ "Locked": "Locked", "Hidden": "Hidden", "Modal View": "Modal View", - "Rename": "Rename" + "Rename": "Rename", + "Delete": "Delete" } diff --git a/packages/plugin-outline-pane/src/locale/zh-CN.json b/packages/plugin-outline-pane/src/locale/zh-CN.json index 8036688f22..9070d17715 100644 --- a/packages/plugin-outline-pane/src/locale/zh-CN.json +++ b/packages/plugin-outline-pane/src/locale/zh-CN.json @@ -18,5 +18,6 @@ "Locked": "已锁定", "Hidden": "已隐藏", "Modal View": "模态视图层", - "Rename": "重命名" + "Rename": "重命名", + "Delete": "删除" } diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index f343fba170..254b639d62 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -51,6 +51,7 @@ overflow: hidden; margin-bottom: @treeNodeHeight; user-select: none; + overflow-x: scroll; .tree-node-modal { margin: 5px; @@ -80,7 +81,8 @@ } } - .tree-node-modal-radio, .tree-node-modal-radio-active { + .tree-node-modal-radio, + .tree-node-modal-radio-active { margin-right: 4px; opacity: 0.8; position: absolute; @@ -139,7 +141,7 @@ content: ' '; z-index: 2; } - >.condition-group-title { + > .condition-group-title { text-align: center; background-color: #7b605b; height: 14px; @@ -167,7 +169,7 @@ content: ' '; z-index: 2; } - >.tree-node-slots-title { + > .tree-node-slots-title { text-align: center; background-color: rgb(144, 94, 190); height: 14px; @@ -183,7 +185,7 @@ &.insertion-at-slots { padding-bottom: @treeNodeHeight; border-bottom-color: rgb(182, 55, 55); - >.tree-node-slots-title { + > .tree-node-slots-title { background-color: rgb(182, 55, 55); } &::before { @@ -279,7 +281,10 @@ } } - .tree-node-hide-btn, .tree-node-lock-btn, .tree-node-rename-btn { + .tree-node-hide-btn, + .tree-node-lock-btn, + .tree-node-rename-btn, + .tree-node-delete-btn { opacity: 0; color: var(--color-text); line-height: 0; @@ -293,18 +298,26 @@ } } &:hover { - .tree-node-hide-btn, .tree-node-lock-btn, .tree-node-rename-btn { + .tree-node-hide-btn, + .tree-node-lock-btn, + .tree-node-rename-btn, + .tree-node-delete-btn { opacity: 0.5; } } html.lc-cursor-dragging & { // FIXME: only hide hover shows - .tree-node-hide-btn, .tree-node-lock-btn, .tree-node-rename-btn { + .tree-node-hide-btn, + .tree-node-lock-btn, + .tree-node-rename-btn { display: none; } } &.editing { - & > .tree-node-hide-btn, & >.tree-node-lock-btn, & >.tree-node-rename-btn { + & > .tree-node-hide-btn, + & > .tree-node-lock-btn, + & > .tree-node-rename-btn, + & > .tree-node-delete-btn { display: none; } } @@ -381,7 +394,8 @@ opacity: 0.8; } .tree-node-branches { - .tree-node-lock-btn, .tree-node-hide-btn { + .tree-node-lock-btn, + .tree-node-hide-btn { opacity: 0; } } diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 6686ea3cf7..02ac94ae69 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -3,7 +3,7 @@ import classNames from 'classnames'; import { createIcon } from '@alilc/lowcode-utils'; import { IPublicApiEvent } from '@alilc/lowcode-types'; import TreeNode from '../controllers/tree-node'; -import { IconLock, IconUnlock, IconArrowRight, IconEyeClose, IconEye, IconCond, IconLoop, IconRadioActive, IconRadio, IconSetting } from '../icons'; +import { IconLock, IconUnlock, IconArrowRight, IconEyeClose, IconEye, IconCond, IconLoop, IconRadioActive, IconRadio, IconSetting, IconDelete } from '../icons'; function emitOutlineEvent(event: IPublicApiEvent, type: string, treeNode: TreeNode, rest?: Record<string, unknown>) { const node = treeNode?.node; @@ -100,7 +100,11 @@ export default class TreeTitle extends PureComponent<{ }); }); } - + deleteClick = () => { + const { treeNode } = this.props; + const { node } = treeNode; + treeNode.deleteNode(node); + }; render() { const { treeNode, isModal } = this.props; const { pluginContext } = treeNode; @@ -131,6 +135,7 @@ export default class TreeTitle extends PureComponent<{ const shouldShowHideBtn = isCNode && isNodeParent && !isModal && couldHide; const shouldShowLockBtn = config.get('enableCanvasLock', false) && isContainer && isCNode && isNodeParent && ((couldLock && !node.isLocked) || (couldUnlock && node.isLocked)); const shouldEditBtn = isCNode && isNodeParent; + const shouldDeleteBtn = isCNode && isNodeParent && node?.canPerformAction('remove'); return ( <div className={classNames('tree-node-title', { editing })} @@ -214,8 +219,28 @@ export default class TreeTitle extends PureComponent<{ </div> {shouldShowHideBtn && <HideBtn hidden={this.props.hidden} treeNode={treeNode} />} {shouldShowLockBtn && <LockBtn locked={this.props.locked} treeNode={treeNode} />} - {shouldEditBtn && <RenameBtn treeNode={treeNode} onClick={this.enableEdit} /> } + {shouldEditBtn && <RenameBtn treeNode={treeNode} onClick={this.enableEdit} />} + {shouldDeleteBtn && <DeleteBtn treeNode={treeNode} onClick={this.deleteClick} />} + </div> + ); + } +} +class DeleteBtn extends PureComponent<{ + treeNode: TreeNode; + onClick: () => void; +}> { + render() { + const { intl, common } = this.props.treeNode.pluginContext; + const { Tip } = common.editorCabin; + return ( + <div + className="tree-node-delete-btn" + onClick={this.props.onClick} + > + <IconDelete /> + {/* @ts-ignore */} + <Tip>{intl('Delete')}</Tip> </div> ); } @@ -297,7 +322,6 @@ class ExpandBtn extends PureComponent<{ expanded: boolean; expandable: boolean; }> { - render() { const { treeNode, expanded, expandable } = this.props; if (!expandable) { From cf3d7a86429f5bd7d9c8ff59162b208b272c627e Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 2 Aug 2023 10:51:55 +0800 Subject: [PATCH 238/469] feat(workspace): when the sleep window is opened, the active window event is not triggered --- packages/workspace/src/workspace.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 41be09fcf3..b12fbb65ba 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -266,10 +266,12 @@ export class Workspace implements IWorkspace { }); this.windows = [...this.windows, window]; this.editorWindowMap.set(window.id, window); - if (!sleep) { - this.window = window; - await this.window.init(); + if (sleep) { + this.emitChangeWindow(); + return; } + this.window = window; + await this.window.init(); this.emitChangeWindow(); this.emitChangeActiveWindow(); this.window?.updateState(WINDOW_STATE.active); From 8b5e2b47c6668817e365b31277f2b2d6c9313cca Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 18 Aug 2023 16:45:35 +0800 Subject: [PATCH 239/469] fix(material): fix rendering is blocked, when the url in the asset fails to load --- packages/editor-core/src/editor.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index f31a2a2dda..10aa0bea1c 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -153,7 +153,11 @@ export class Editor extends EventEmitter implements IEditor { return; } if (!AssetsCache[exportName] || !npm?.version || AssetsCache[exportName].npm?.version !== npm?.version) { - await (new AssetLoader()).load(url); + try { + await (new AssetLoader()).load(url); + } catch (error) { + console.error(`${url} load error: `, error); + } } AssetsCache[exportName] = component; function setAssetsComponent(component: any, extraNpmInfo: any = {}) { From 9ddda1db9e50f91c3865d841e81da0f52599b498 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 18 Aug 2023 17:00:56 +0800 Subject: [PATCH 240/469] feat(config): add onGot in config.device --- packages/plugin-designer/src/index.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/plugin-designer/src/index.tsx b/packages/plugin-designer/src/index.tsx index 90eefaaba5..51b81ff9d0 100644 --- a/packages/plugin-designer/src/index.tsx +++ b/packages/plugin-designer/src/index.tsx @@ -72,6 +72,11 @@ export default class DesignerPlugin extends PureComponent<PluginProps, DesignerP requestHandlersMap, }); }); + engineConfig.onGot('device', (device) => { + this.setState({ + device, + }); + }); const { components, packages, extraEnvironment, utils } = assets; const state = { componentMetadatas: components || [], From 899ffa15541164c31e2e3688344639046df282ec Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 21 Aug 2023 10:56:03 +0800 Subject: [PATCH 241/469] feat(workspace): update openEditorWindow api --- docs/docs/api/workspace.md | 11 +++- .../designer/src/plugin/plugin-manager.ts | 4 +- packages/shell/src/api/workspace.ts | 14 +++-- packages/shell/src/model/resource.ts | 4 ++ packages/types/src/shell/api/workspace.ts | 13 ++++- packages/types/src/shell/model/resource.ts | 2 + .../types/src/shell/type/resource-list.ts | 7 +-- packages/workspace/src/resource.ts | 4 ++ packages/workspace/src/workspace.ts | 55 +++++++++++++++++-- 9 files changed, 92 insertions(+), 22 deletions(-) diff --git a/docs/docs/api/workspace.md b/docs/docs/api/workspace.md index 9d99609270..5e0f7acd2f 100644 --- a/docs/docs/api/workspace.md +++ b/docs/docs/api/workspace.md @@ -84,7 +84,14 @@ setResourceList(resourceList: IPublicResourceList) {} 打开视图窗口 ```typescript -openEditorWindow(resourceName: string, title: string, options: Object, viewName?: string): void; +/** + * 打开视图窗口 + * @deprecated + */ +openEditorWindow(resourceName: string, id: string, extra: Object, viewName?: string, sleep?: boolean): Promise<void>; + +/** 打开视图窗口 */ +openEditorWindow(resource: Resource, sleep?: boolean): Promise<void>; ``` ### openEditorWindowById @@ -100,7 +107,7 @@ openEditorWindowById(id: string): void; 移除视图窗口 ```typescript -removeEditorWindow(resourceName: string, title: string): void; +removeEditorWindow(resourceName: string, id: string): void; ``` ### removeEditorWindowById diff --git a/packages/designer/src/plugin/plugin-manager.ts b/packages/designer/src/plugin/plugin-manager.ts index f30ccdc8f3..f6b325dc0d 100644 --- a/packages/designer/src/plugin/plugin-manager.ts +++ b/packages/designer/src/plugin/plugin-manager.ts @@ -84,8 +84,8 @@ export class LowCodePluginManager implements ILowCodePluginManager { const ctx = this._getLowCodePluginContext({ pluginName, meta }); const customFilterValidOptions = engineConfig.get('customPluginFilterOptions', filterValidOptions); const pluginTransducer = engineConfig.get('customPluginTransducer', null); - const newOptions = customFilterValidOptions(options, preferenceDeclaration!); - const newPluginModel = pluginTransducer ? await pluginTransducer(pluginModel, ctx, newOptions) : pluginModel; + const newPluginModel = pluginTransducer ? await pluginTransducer(pluginModel, ctx, options) : pluginModel; + const newOptions = customFilterValidOptions(options, newPluginModel.meta?.preferenceDeclaration); const config = newPluginModel(ctx, newOptions); // compat the legacy way to declare pluginName // @ts-ignore diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index 1a16d31ce8..b19638ec76 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -1,6 +1,6 @@ import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; import { IWorkspace } from '@alilc/lowcode-workspace'; -import { workspaceSymbol } from '../symbols'; +import { resourceSymbol, workspaceSymbol } from '../symbols'; import { Resource as ShellResource, Window as ShellWindow } from '../model'; import { Plugins } from './plugins'; @@ -64,16 +64,20 @@ export class Workspace implements IPublicApiWorkspace { this[workspaceSymbol].registerResourceType(resourceTypeModel); } - async openEditorWindow(resourceName: string, title: string, extra: object, viewName?: string, sleep?: boolean): Promise<void> { - await this[workspaceSymbol].openEditorWindow(resourceName, title, extra, viewName, sleep); + async openEditorWindow(): Promise<void> { + if (typeof arguments[0] === 'string') { + await this[workspaceSymbol].openEditorWindow(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]); + } else { + await this[workspaceSymbol].openEditorWindowByResource(arguments[0]?.[resourceSymbol], arguments[1]); + } } openEditorWindowById(id: string) { this[workspaceSymbol].openEditorWindowById(id); } - removeEditorWindow(resourceName: string, title: string) { - this[workspaceSymbol].removeEditorWindow(resourceName, title); + removeEditorWindow(resourceName: string, id: string) { + this[workspaceSymbol].removeEditorWindow(resourceName, id); } removeEditorWindowById(id: string) { diff --git a/packages/shell/src/model/resource.ts b/packages/shell/src/model/resource.ts index 6a1a07e499..29a385b993 100644 --- a/packages/shell/src/model/resource.ts +++ b/packages/shell/src/model/resource.ts @@ -13,6 +13,10 @@ export class Resource implements IPublicModelResource { return this[resourceSymbol].title; } + get id() { + return this[resourceSymbol].id; + } + get icon() { return this[resourceSymbol].icon; } diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index 8ae2434bc5..d4232d9a14 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -3,7 +3,8 @@ import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTy export interface IPublicApiWorkspace< Plugins = IPublicApiPlugins, - ModelWindow = IPublicModelWindow + ModelWindow = IPublicModelWindow, + Resource = IPublicModelResource, > { /** 是否启用 workspace 模式 */ @@ -29,14 +30,20 @@ export interface IPublicApiWorkspace< /** 注册资源 */ registerResourceType(resourceTypeModel: IPublicTypeResourceType): void; + /** + * 打开视图窗口 + * @deprecated + */ + openEditorWindow(resourceName: string, id: string, extra: Object, viewName?: string, sleep?: boolean): Promise<void>; + /** 打开视图窗口 */ - openEditorWindow(resourceName: string, title: string, extra: Object, viewName?: string, sleep?: boolean): Promise<void>; + openEditorWindow(resource: Resource, sleep?: boolean): Promise<void>; /** 通过视图 id 打开窗口 */ openEditorWindowById(id: string): void; /** 移除视图窗口 */ - removeEditorWindow(resourceName: string, title: string): void; + removeEditorWindow(resourceName: string, id: string): void; /** 通过视图 id 移除窗口 */ removeEditorWindowById(id: string): void; diff --git a/packages/types/src/shell/model/resource.ts b/packages/types/src/shell/model/resource.ts index 0d791412b9..b79b6acfcc 100644 --- a/packages/types/src/shell/model/resource.ts +++ b/packages/types/src/shell/model/resource.ts @@ -5,6 +5,8 @@ export interface IBaseModelResource< > { get title(): string | undefined; + get id(): string | undefined; + get icon(): ReactElement | undefined; get options(): Record<string, any>; diff --git a/packages/types/src/shell/type/resource-list.ts b/packages/types/src/shell/type/resource-list.ts index 7abdcc7b13..ec998a95be 100644 --- a/packages/types/src/shell/type/resource-list.ts +++ b/packages/types/src/shell/type/resource-list.ts @@ -8,6 +8,9 @@ export interface IPublicResourceData { /** 资源标题 */ title?: string; + /** 资源 Id */ + id?: string; + /** 分类 */ category?: string; @@ -24,10 +27,6 @@ export interface IPublicResourceData { /** 资源子元素 */ children?: IPublicResourceData[]; - - config?: { - disableBehaviors?: ('copy' | 'remove')[]; - }; } export type IPublicResourceList = IPublicResourceData[]; \ No newline at end of file diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index a7ecc59b2e..6e85183853 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -60,6 +60,10 @@ export class Resource implements IResource { return this.resourceData.title || this.resourceTypeInstance.defaultTitle; } + get id(): string | undefined { + return this.resourceData.id; + } + get options() { return this.resourceData.options; } diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index b12fbb65ba..50255b7dbf 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -50,6 +50,8 @@ export interface IWorkspace extends Omit<IPublicApiWorkspace< onChangeActiveEditorView(fn: () => void): IPublicTypeDisposable; emitChangeActiveEditorView(): void; + + openEditorWindowByResource(resource: IResource, sleep: boolean): Promise<void>; } export class Workspace implements IWorkspace { @@ -91,12 +93,12 @@ export class Workspace implements IWorkspace { @obx.ref window: IEditorWindow; - windowQueue: { + windowQueue: ({ name: string; title: string; options: Object; viewName?: string; - }[] = []; + } | IResource)[] = []; constructor( readonly registryInnerPlugin: (designer: IDesigner, editor: IEditor, plugins: IPublicApiPlugins) => Promise<IPublicTypeDisposable>, @@ -192,7 +194,7 @@ export class Workspace implements IWorkspace { this.remove(index); } - private remove(index: number) { + private async remove(index: number) { if (index < 0) { return; } @@ -202,7 +204,7 @@ export class Workspace implements IWorkspace { if (this.window === window) { this.window = this.windows[index] || this.windows[index + 1] || this.windows[index - 1]; if (this.window?.sleep) { - this.window.init(); + await this.window.init(); } this.emitChangeActiveWindow(); } @@ -210,8 +212,8 @@ export class Workspace implements IWorkspace { this.window?.updateState(WINDOW_STATE.active); } - removeEditorWindow(resourceName: string, title: string) { - const index = this.windows.findIndex(d => (d.resource?.name === resourceName && d.title === title)); + removeEditorWindow(resourceName: string, id: string) { + const index = this.windows.findIndex(d => (d.resource?.name === resourceName && d.title === id)); this.remove(index); } @@ -228,6 +230,47 @@ export class Workspace implements IWorkspace { this.window?.updateState(WINDOW_STATE.active); } + async openEditorWindowByResource(resource: IResource, sleep: boolean = false): Promise<void> { + if (this.window && !this.window?.initReady && !sleep) { + this.windowQueue.push(resource); + return; + } + + this.window?.updateState(WINDOW_STATE.inactive); + + const filterWindows = this.windows.filter(d => (d.resource?.id === resource.id)); + if (filterWindows && filterWindows.length) { + this.window = filterWindows[0]; + if (!sleep && this.window.sleep) { + await this.window.init(); + } else { + this.checkWindowQueue(); + } + this.emitChangeActiveWindow(); + this.window?.updateState(WINDOW_STATE.active); + return; + } + + const window = new EditorWindow(resource, this, { + title: resource.title, + options: resource.options, + viewName: resource.viewName, + sleep, + }); + + this.windows = [...this.windows, window]; + this.editorWindowMap.set(window.id, window); + if (sleep) { + this.emitChangeWindow(); + return; + } + this.window = window; + await this.window.init(); + this.emitChangeWindow(); + this.emitChangeActiveWindow(); + this.window?.updateState(WINDOW_STATE.active); + } + async openEditorWindow(name: string, title: string, options: Object, viewName?: string, sleep?: boolean) { if (this.window && !this.window?.initReady && !sleep) { this.windowQueue.push({ From 5a4e43a7d7c031985c14b75bc7adde077b8def76 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 21 Aug 2023 11:43:07 +0800 Subject: [PATCH 242/469] chore(docs): publish docs 1.1.5 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index c454117331..998d9daf9c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.4", + "version": "1.1.5", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From b4c20b181fb19827a6f5c5492a3a6cc804fe74d4 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 21 Aug 2023 15:00:57 +0800 Subject: [PATCH 243/469] fix: logger is not defined error in transformStringToFunction --- packages/editor-skeleton/src/transducers/parse-func.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-skeleton/src/transducers/parse-func.ts b/packages/editor-skeleton/src/transducers/parse-func.ts index b253103504..bc52deec35 100644 --- a/packages/editor-skeleton/src/transducers/parse-func.ts +++ b/packages/editor-skeleton/src/transducers/parse-func.ts @@ -26,7 +26,7 @@ function transformStringToFunction(str: string) { try { return (${str}).apply(self, arguments); } catch(e) { - logger.warn('call function which parsed by lowcode failed: ', e); + console.warn('call function which parsed by lowcode failed: ', e); return e.message; } }; From 14d294c92c662d00350e87d8cf6ec57beee325f6 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 22 Aug 2023 17:59:35 +0800 Subject: [PATCH 244/469] feat: when field rendering error, output error log --- .../src/components/field/fields.tsx | 22 ++++++++++++++----- packages/types/src/shell/model/resource.ts | 2 +- .../types/src/shell/type/resource-list.ts | 7 +++++- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/editor-skeleton/src/components/field/fields.tsx b/packages/editor-skeleton/src/components/field/fields.tsx index 84ac56f48b..b773995e3a 100644 --- a/packages/editor-skeleton/src/components/field/fields.tsx +++ b/packages/editor-skeleton/src/components/field/fields.tsx @@ -1,5 +1,5 @@ /* eslint-disable react/no-unused-prop-types */ -import { Component, MouseEvent } from 'react'; +import { Component, ErrorInfo, MouseEvent } from 'react'; import { isObject } from 'lodash'; import classNames from 'classnames'; import { Icon } from '@alifd/next'; @@ -9,6 +9,9 @@ import { PopupPipe, PopupContext } from '../popup'; import './index.less'; import InlineTip from './inlinetip'; import { intl } from '../../locale'; +import { Logger } from '@alilc/lowcode-utils'; + +const logger = new Logger({ level: 'warn', bizName: 'skeleton:field' }); export interface FieldProps { className?: string; @@ -31,6 +34,10 @@ export class Field extends Component<FieldProps> { hasError: false, }; + private body: HTMLDivElement | null = null; + + private dispose?: () => void; + constructor(props: any) { super(props); this.handleClear = this.handleClear.bind(this); @@ -47,10 +54,6 @@ export class Field extends Component<FieldProps> { onExpandChange && onExpandChange(!collapsed); }; - private body: HTMLDivElement | null = null; - - private dispose?: () => void; - private deployBlockTesting() { if (this.dispose) { this.dispose(); @@ -101,7 +104,13 @@ export class Field extends Component<FieldProps> { } static getDerivedStateFromError() { - return { hasError: true }; + return { + hasError: true, + }; + } + + componentDidCatch(error: Error, errorInfo: ErrorInfo) { + logger.error(`${this.props.title} has error`, error, errorInfo); } getTipContent(propName: string, tip?: any): any { @@ -194,6 +203,7 @@ export class Field extends Component<FieldProps> { */ function createValueState(/* valueState?: number, onClear?: (e: React.MouseEvent) => void */) { return null; + /* let tip: any = null; let className = 'lc-valuestate'; diff --git a/packages/types/src/shell/model/resource.ts b/packages/types/src/shell/model/resource.ts index b79b6acfcc..acd7d056f5 100644 --- a/packages/types/src/shell/model/resource.ts +++ b/packages/types/src/shell/model/resource.ts @@ -24,7 +24,7 @@ export interface IBaseModelResource< get description(): string | undefined; get config(): { - disableBehaviors?: ('copy' | 'remove')[]; + [key: string]: any; } | undefined; } diff --git a/packages/types/src/shell/type/resource-list.ts b/packages/types/src/shell/type/resource-list.ts index ec998a95be..1d7c34232a 100644 --- a/packages/types/src/shell/type/resource-list.ts +++ b/packages/types/src/shell/type/resource-list.ts @@ -5,6 +5,11 @@ export interface IPublicResourceData { /** 资源名字 */ resourceName: string; + /** 资源扩展配置 */ + config?: { + [key: string]: any; + }; + /** 资源标题 */ title?: string; @@ -20,7 +25,7 @@ export interface IPublicResourceData { /** 资源 icon */ icon?: ReactElement; - /** 资源其他配置 */ + /** 资源其他配置,资源初始化时的第二个参数 */ options: { [key: string]: any; }; From 547bbf4ddc0377c15f3e348d49d86eaa49de17ca Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 23 Aug 2023 14:20:08 +0800 Subject: [PATCH 245/469] feat(workspace): update removeEditorWindow api --- docs/docs/api/workspace.md | 9 +++++++++ packages/shell/src/api/workspace.ts | 8 ++++++-- packages/types/src/shell/api/workspace.ts | 10 +++++++++- packages/workspace/src/workspace.ts | 21 +++++++++++++++++++-- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/docs/docs/api/workspace.md b/docs/docs/api/workspace.md index 5e0f7acd2f..3c13b00aa0 100644 --- a/docs/docs/api/workspace.md +++ b/docs/docs/api/workspace.md @@ -107,7 +107,16 @@ openEditorWindowById(id: string): void; 移除视图窗口 ```typescript +/** + * 移除视图窗口 + * @deprecated + */ removeEditorWindow(resourceName: string, id: string): void; + +/** + * 移除视图窗口 + */ +removeEditorWindow(resource: Resource): void; ``` ### removeEditorWindowById diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index b19638ec76..8737e37bd7 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -76,8 +76,12 @@ export class Workspace implements IPublicApiWorkspace { this[workspaceSymbol].openEditorWindowById(id); } - removeEditorWindow(resourceName: string, id: string) { - this[workspaceSymbol].removeEditorWindow(resourceName, id); + removeEditorWindow() { + if (typeof arguments[0] === 'string') { + this[workspaceSymbol].removeEditorWindow(arguments[0], arguments[1]); + } else { + this[workspaceSymbol].removeEditorWindowByResource(arguments[0]?.[resourceSymbol]); + } } removeEditorWindowById(id: string) { diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index d4232d9a14..9e1080b31e 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -42,9 +42,17 @@ export interface IPublicApiWorkspace< /** 通过视图 id 打开窗口 */ openEditorWindowById(id: string): void; - /** 移除视图窗口 */ + /** + * 移除视图窗口 + * @deprecated + */ removeEditorWindow(resourceName: string, id: string): void; + /** + * 移除视图窗口 + */ + removeEditorWindow(resource: Resource): void; + /** 通过视图 id 移除窗口 */ removeEditorWindowById(id: string): void; diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 50255b7dbf..22eb9ede2b 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -22,7 +22,7 @@ const CHANGE_EVENT = 'resource.list.change'; export interface IWorkspace extends Omit<IPublicApiWorkspace< LowCodePluginManager, IEditorWindow ->, 'resourceList' | 'plugins'> { +>, 'resourceList' | 'plugins' | 'openEditorWindow' | 'removeEditorWindow'> { readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise<IPublicTypeDisposable>; readonly shellModelFactory: IShellModelFactory; @@ -52,6 +52,18 @@ export interface IWorkspace extends Omit<IPublicApiWorkspace< emitChangeActiveEditorView(): void; openEditorWindowByResource(resource: IResource, sleep: boolean): Promise<void>; + + /** + * @deprecated + */ + removeEditorWindow(resourceName: string, id: string): void; + + removeEditorWindowByResource(resource: IResource): void; + + /** + * @deprecated + */ + openEditorWindow(name: string, title: string, options: Object, viewName?: string, sleep?: boolean): Promise<void>; } export class Workspace implements IWorkspace { @@ -213,7 +225,12 @@ export class Workspace implements IWorkspace { } removeEditorWindow(resourceName: string, id: string) { - const index = this.windows.findIndex(d => (d.resource?.name === resourceName && d.title === id)); + const index = this.windows.findIndex(d => (d.resource?.name === resourceName && (d.title === id || d.resource.id === id))); + this.remove(index); + } + + removeEditorWindowByResource(resource: IResource) { + const index = this.windows.findIndex(d => (d.resource?.id === resource.id)); this.remove(index); } From 58628c583bf26bde2fcc4d70dae45cf6067a4a16 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Wed, 23 Aug 2023 15:10:09 +0800 Subject: [PATCH 246/469] chore(docs): publish docs 1.1.6 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 998d9daf9c..e7d3311853 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.5", + "version": "1.1.6", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 379d51d61ffb75eab4889316e82ceb2f7cd353bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Thu, 24 Aug 2023 17:34:07 +0800 Subject: [PATCH 247/469] docs: update configOptions.md --- docs/docs/api/configOptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md index 3f8e75df29..cc606a91ee 100644 --- a/docs/docs/api/configOptions.md +++ b/docs/docs/api/configOptions.md @@ -179,7 +179,7 @@ config.set('enableCondition', false) `@type {boolean}` `@default {false}` -鼠标事件在画布中是否允许冒泡 +鼠标事件(mouseover、mouseleave、mousemove)在画布中是否允许冒泡,默认不允许。 #### enableReactiveContainer From f9898d483c8dd078565f444dbfb92376aa3a8ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Thu, 24 Aug 2023 17:29:29 +0800 Subject: [PATCH 248/469] docs: update configOptions.md --- docs/docs/api/configOptions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md index cc606a91ee..4127576569 100644 --- a/docs/docs/api/configOptions.md +++ b/docs/docs/api/configOptions.md @@ -126,7 +126,7 @@ config.set('enableCondition', false) #### customizeIgnoreSelectors - 点击忽略 -定制画布中点击被忽略的 selectors +配置画布中,需要屏蔽点击事件的元素,即配置的元素默认点击行为均不生效。 类型定义: From 0da46fffb7fc99c2f4703eee9bfbf72be729e6ab Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 24 Aug 2023 17:44:16 +0800 Subject: [PATCH 249/469] chore(docs): publish docs 1.1.7 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index e7d3311853..012ef49d04 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.6", + "version": "1.1.7", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From bf980c98ea62eb969af29cfc810f497c3f772509 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 25 Aug 2023 11:29:01 +0800 Subject: [PATCH 250/469] chore(release): publish 1.1.10 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 9d3eb758a1..0bb34d1aee 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.9", + "version": "1.1.10", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 0b2178c3b8..274d266fc0 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.9", + "version": "1.1.10", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -16,9 +16,9 @@ "license": "MIT", "dependencies": { "@alilc/build-plugin-lce": "^0.0.4-beta.2", - "@alilc/lowcode-editor-core": "1.1.9", - "@alilc/lowcode-types": "1.1.9", - "@alilc/lowcode-utils": "1.1.9", + "@alilc/lowcode-editor-core": "1.1.10", + "@alilc/lowcode-types": "1.1.10", + "@alilc/lowcode-utils": "1.1.10", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 58e8eb4814..e05002469e 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.1.9", + "version": "1.1.10", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.9", - "@alilc/lowcode-utils": "1.1.9", + "@alilc/lowcode-types": "1.1.10", + "@alilc/lowcode-utils": "1.1.10", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index b1802795dd..2c8efccebf 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.1.9", + "version": "1.1.10", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.1.9", - "@alilc/lowcode-editor-core": "1.1.9", - "@alilc/lowcode-types": "1.1.9", - "@alilc/lowcode-utils": "1.1.9", + "@alilc/lowcode-designer": "1.1.10", + "@alilc/lowcode-editor-core": "1.1.10", + "@alilc/lowcode-types": "1.1.10", + "@alilc/lowcode-utils": "1.1.10", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 4d5e4681f6..a9521d486b 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.9", + "version": "1.1.10", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.1.9", - "@alilc/lowcode-editor-core": "1.1.9", - "@alilc/lowcode-editor-skeleton": "1.1.9", + "@alilc/lowcode-designer": "1.1.10", + "@alilc/lowcode-editor-core": "1.1.10", + "@alilc/lowcode-editor-skeleton": "1.1.10", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.9", - "@alilc/lowcode-plugin-outline-pane": "1.1.9", - "@alilc/lowcode-shell": "1.1.9", - "@alilc/lowcode-utils": "1.1.9", - "@alilc/lowcode-workspace": "1.1.9", + "@alilc/lowcode-plugin-designer": "1.1.10", + "@alilc/lowcode-plugin-outline-pane": "1.1.10", + "@alilc/lowcode-shell": "1.1.10", + "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-workspace": "1.1.10", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 4064e585bf..116f98e5d5 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.9", + "version": "1.1.10", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 16905f6159..760d57a133 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.1.9", + "version": "1.1.10", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.9", - "@alilc/lowcode-editor-core": "1.1.9", - "@alilc/lowcode-utils": "1.1.9", + "@alilc/lowcode-designer": "1.1.10", + "@alilc/lowcode-editor-core": "1.1.10", + "@alilc/lowcode-utils": "1.1.10", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index c49e11c2ef..4a71eb26b8 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.1.9", + "version": "1.1.10", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.9", - "@alilc/lowcode-utils": "1.1.9", + "@alilc/lowcode-types": "1.1.10", + "@alilc/lowcode-utils": "1.1.10", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index ddd160f004..90a9b7e08e 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.1.9", + "version": "1.1.10", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.1.9", - "@alilc/lowcode-utils": "1.1.9", + "@alilc/lowcode-renderer-core": "1.1.10", + "@alilc/lowcode-utils": "1.1.10", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index d2c39c0c81..8ff7f1f0a4 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.1.9", + "version": "1.1.10", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.9", - "@alilc/lowcode-rax-renderer": "1.1.9", - "@alilc/lowcode-types": "1.1.9", - "@alilc/lowcode-utils": "1.1.9", + "@alilc/lowcode-designer": "1.1.10", + "@alilc/lowcode-rax-renderer": "1.1.10", + "@alilc/lowcode-types": "1.1.10", + "@alilc/lowcode-utils": "1.1.10", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 410d24a6bf..1535cb2088 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.1.9", + "version": "1.1.10", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.1.9" + "@alilc/lowcode-renderer-core": "1.1.10" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 8fb1e979b3..ffb8228dfd 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.1.9", + "version": "1.1.10", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.9", - "@alilc/lowcode-react-renderer": "1.1.9", - "@alilc/lowcode-types": "1.1.9", - "@alilc/lowcode-utils": "1.1.9", + "@alilc/lowcode-designer": "1.1.10", + "@alilc/lowcode-react-renderer": "1.1.10", + "@alilc/lowcode-types": "1.1.10", + "@alilc/lowcode-utils": "1.1.10", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 49c9d30fe5..52b13b86c6 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.1.9", + "version": "1.1.10", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.1.9", - "@alilc/lowcode-utils": "1.1.9", + "@alilc/lowcode-types": "1.1.10", + "@alilc/lowcode-utils": "1.1.10", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.1.9", + "@alilc/lowcode-designer": "1.1.10", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index c9663e4a77..09768a06a7 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.9", + "version": "1.1.10", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.9", - "@alilc/lowcode-editor-core": "1.1.9", - "@alilc/lowcode-editor-skeleton": "1.1.9", - "@alilc/lowcode-types": "1.1.9", - "@alilc/lowcode-utils": "1.1.9", - "@alilc/lowcode-workspace": "1.1.9", + "@alilc/lowcode-designer": "1.1.10", + "@alilc/lowcode-editor-core": "1.1.10", + "@alilc/lowcode-editor-skeleton": "1.1.10", + "@alilc/lowcode-types": "1.1.10", + "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-workspace": "1.1.10", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 317fbbeb73..fe9cd51235 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.9", + "version": "1.1.10", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index dcc1ccdd21..ecf6bff3c0 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.9", + "version": "1.1.10", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.9", + "@alilc/lowcode-types": "1.1.10", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 36e8dac0f1..8802691d60 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.9", + "version": "1.1.10", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.9", - "@alilc/lowcode-editor-core": "1.1.9", - "@alilc/lowcode-editor-skeleton": "1.1.9", - "@alilc/lowcode-types": "1.1.9", - "@alilc/lowcode-utils": "1.1.9", + "@alilc/lowcode-designer": "1.1.10", + "@alilc/lowcode-editor-core": "1.1.10", + "@alilc/lowcode-editor-skeleton": "1.1.10", + "@alilc/lowcode-types": "1.1.10", + "@alilc/lowcode-utils": "1.1.10", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From e3842b05310010ac0d4899e524b7932b4948d337 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 25 Aug 2023 16:43:16 +0800 Subject: [PATCH 251/469] feat: add editorCabinSymbol and skeletonCabinSymbol --- packages/engine/src/modules/symbols.ts | 4 +++ packages/shell/src/api/common.tsx | 49 +++++++++++++++++++++++++- packages/shell/src/symbols.ts | 2 ++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/packages/engine/src/modules/symbols.ts b/packages/engine/src/modules/symbols.ts index a0371abf98..435e8cbc2c 100644 --- a/packages/engine/src/modules/symbols.ts +++ b/packages/engine/src/modules/symbols.ts @@ -12,6 +12,8 @@ import { propSymbol, simulatorHostSymbol, skeletonItemSymbol, + editorCabinSymbol, + skeletonCabinSymbol, } from '@alilc/lowcode-shell'; export default { @@ -25,6 +27,8 @@ export default { settingPropEntrySymbol: settingFieldSymbol, settingTopEntrySymbol, designerCabinSymbol, + editorCabinSymbol, + skeletonCabinSymbol, propSymbol, simulatorHostSymbol, skeletonItemSymbol, diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx index 9f38cf1091..3c2d2e5cce 100644 --- a/packages/shell/src/api/common.tsx +++ b/packages/shell/src/api/common.tsx @@ -1,4 +1,4 @@ -import { editorSymbol, skeletonSymbol, designerCabinSymbol, designerSymbol, settingFieldSymbol } from '../symbols'; +import { editorSymbol, skeletonSymbol, designerCabinSymbol, designerSymbol, settingFieldSymbol, editorCabinSymbol, skeletonCabinSymbol } from '../symbols'; import { isFormEvent as innerIsFormEvent, compatibleLegaoSchema as innerCompatibleLegaoSchema, @@ -36,6 +36,10 @@ import { getConvertedExtraKey as innerGetConvertedExtraKey, getOriginalExtraKey as innerGetOriginalExtraKey, IDesigner, + DropLocation as InnerDropLocation, + Designer as InnerDesigner, + Node as InnerNode, + LowCodePluginManager as InnerLowCodePluginManager, } from '@alilc/lowcode-designer'; import { Skeleton as InnerSkeleton, @@ -43,6 +47,8 @@ import { PopupContext as InnerPopupContext, PopupPipe as InnerPopupPipe, Workbench as InnerWorkbench, + SettingsPrimaryPane as InnerSettingsPrimaryPane, + registerDefaults as InnerRegisterDefaults, } from '@alilc/lowcode-editor-skeleton'; import { Editor, @@ -61,6 +67,7 @@ import { action as innerAction, runInAction as innerRunInAction, engineConfig as innerEngineConfig, + globalContext, } from '@alilc/lowcode-editor-core'; import { Dragon as ShellDragon } from '../model'; import { ReactNode } from 'react'; @@ -94,6 +101,10 @@ class DesignerCabin implements IPublicApiCommonDesignerCabin { DragObjectType: InnerDragObjectType, isDragNodeDataObject: innerIsDragNodeDataObject, isNode: innerIsNode, + DropLocation: InnerDropLocation, + Designer: InnerDesigner, + Node: InnerNode, + LowCodePluginManager: InnerLowCodePluginManager, }; } @@ -160,8 +171,19 @@ class DesignerCabin implements IPublicApiCommonDesignerCabin { class SkeletonCabin implements IPublicApiCommonSkeletonCabin { private readonly [skeletonSymbol]: InnerSkeleton; + readonly [skeletonCabinSymbol]: any; + constructor(skeleton: InnerSkeleton) { this[skeletonSymbol] = skeleton; + this[skeletonCabinSymbol] = { + Workbench: this.Workbench, + createSettingFieldView: this.createSettingFieldView, + PopupContext: InnerPopupContext, + PopupPipe: InnerPopupPipe, + SettingsPrimaryPane: InnerSettingsPrimaryPane, + registerDefaults: InnerRegisterDefaults, + Skeleton: InnerSkeleton, + }; } get Workbench(): any { @@ -242,8 +264,33 @@ class Utils implements IPublicApiCommonUtils { class EditorCabin implements IPublicApiCommonEditorCabin { private readonly [editorSymbol]: Editor; + /** + * @deprecated + */ + readonly [editorCabinSymbol]: any; + constructor(editor: Editor) { this[editorSymbol] = editor; + this[editorCabinSymbol] = { + Editor, + globalContext, + runInAction: innerRunInAction, + Title: InnerTitle, + Tip: InnerTip, + shallowIntl: innerShallowIntl, + createIntl: innerCreateIntl, + intl: innerIntl, + createSetterContent: this.createSetterContent.bind(this), + globalLocale: innerGlobalLocale, + obx: innerObx, + action: innerAction, + engineConfig: innerEngineConfig, + observable: innerObservable, + makeObservable: innerMakeObservable, + untracked: innerUntracked, + computed: innerComputed, + observer: innerObserver, + }; } /** diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index b4ec01c7ec..cc1be48560 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -24,6 +24,8 @@ export const simulatorHostSymbol = Symbol('simulatorHost'); export const dragObjectSymbol = Symbol('dragObject'); export const locateEventSymbol = Symbol('locateEvent'); export const designerCabinSymbol = Symbol('designerCabin'); +export const editorCabinSymbol = Symbol('editorCabin'); +export const skeletonCabinSymbol = Symbol('skeletonCabin'); export const hotkeySymbol = Symbol('hotkey'); export const pluginsSymbol = Symbol('plugins'); export const workspaceSymbol = Symbol('workspace'); From 857685a3b412c0155a22f1da4c0a95138544df0b Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 28 Aug 2023 16:54:11 +0800 Subject: [PATCH 252/469] feat(node): add getRGL api --- docs/docs/api/model/node.md | 18 ++++++++ packages/designer/src/component-actions.ts | 47 ++++++++++----------- packages/designer/src/document/node/node.ts | 2 +- packages/shell/src/model/node.ts | 20 +++++++++ packages/types/src/shell/model/node.ts | 12 ++++++ 5 files changed, 74 insertions(+), 25 deletions(-) diff --git a/docs/docs/api/model/node.md b/docs/docs/api/model/node.md index c10af34660..697eefd088 100644 --- a/docs/docs/api/model/node.md +++ b/docs/docs/api/model/node.md @@ -657,4 +657,22 @@ setConditionalVisible(): void; */ getDOMNode(): HTMLElement; +``` + +### getRGL + +获取磁贴相关信息 + +```typescript +/** + * 获取磁贴相关信息 + */ +getRGL(): { + isContainerNode: boolean; + isEmptyNode: boolean; + isRGLContainerNode: boolean; + isRGLNode: boolean; + isRGL: boolean; + rglNode: Node | null; +} ``` \ No newline at end of file diff --git a/packages/designer/src/component-actions.ts b/packages/designer/src/component-actions.ts index a7a690a44d..76ead7d9a6 100644 --- a/packages/designer/src/component-actions.ts +++ b/packages/designer/src/component-actions.ts @@ -1,4 +1,4 @@ -import { IPublicTypeComponentAction, IPublicTypeMetadataTransducer } from '@alilc/lowcode-types'; +import { IPublicModelNode, IPublicTypeComponentAction, IPublicTypeMetadataTransducer } from '@alilc/lowcode-types'; import { engineConfig } from '@alilc/lowcode-editor-core'; import { intlNode } from './locale'; import { @@ -8,10 +8,11 @@ import { IconClone, IconHidden, } from './icons'; -import { Node } from './document'; import { componentDefaults, legacyIssues } from './transducers'; export class ComponentActions { + private metadataTransducers: IPublicTypeMetadataTransducer[] = []; + actions: IPublicTypeComponentAction[] = [ { name: 'remove', @@ -19,7 +20,7 @@ export class ComponentActions { icon: IconRemove, title: intlNode('remove'), /* istanbul ignore next */ - action(node: Node) { + action(node: IPublicModelNode) { node.remove(); }, }, @@ -31,13 +32,13 @@ export class ComponentActions { icon: IconHidden, title: intlNode('hide'), /* istanbul ignore next */ - action(node: Node) { - node.setVisible(false); + action(node: IPublicModelNode) { + node.visible = false; }, }, /* istanbul ignore next */ - condition: (node: Node) => { - return node.componentMeta.isModal; + condition: (node: IPublicModelNode) => { + return node.componentMeta?.isModal; }, important: true, }, @@ -47,25 +48,25 @@ export class ComponentActions { icon: IconClone, title: intlNode('copy'), /* istanbul ignore next */ - action(node: Node) { + action(node: IPublicModelNode) { // node.remove(); const { document: doc, parent, index } = node; if (parent) { - const newNode = doc.insertNode(parent, node, index + 1, true); - newNode.select(); - const { isRGL, rglNode } = node.getRGL(); + const newNode = doc?.insertNode(parent, node, (index ?? 0) + 1, true); + newNode?.select(); + const { isRGL, rglNode } = node?.getRGL(); if (isRGL) { // 复制 layout 信息 - const layout = rglNode.getPropValue('layout') || []; - const curLayout = layout.filter((item) => item.i === node.getPropValue('fieldId')); + const layout: any = rglNode?.getPropValue('layout') || []; + const curLayout = layout.filter((item: any) => item.i === node.getPropValue('fieldId')); if (curLayout && curLayout[0]) { layout.push({ ...curLayout[0], - i: newNode.getPropValue('fieldId'), + i: newNode?.getPropValue('fieldId'), }); - rglNode.setPropValue('layout', layout); + rglNode?.setPropValue('layout', layout); // 如果是磁贴块复制,则需要滚动到影响位置 - setTimeout(() => newNode.document.simulator?.scrollToNode(newNode), 10); + setTimeout(() => newNode?.document?.project?.simulatorHost?.scrollToNode(newNode), 10); } } } @@ -79,13 +80,13 @@ export class ComponentActions { icon: IconLock, // 锁定 icon title: intlNode('lock'), /* istanbul ignore next */ - action(node: Node) { + action(node: IPublicModelNode) { node.lock(); }, }, /* istanbul ignore next */ - condition: (node: Node) => { - return engineConfig.get('enableCanvasLock', false) && node.isContainer() && !node.isLocked; + condition: (node: IPublicModelNode) => { + return engineConfig.get('enableCanvasLock', false) && node.isContainerNode && !node.isLocked; }, important: true, }, @@ -95,13 +96,13 @@ export class ComponentActions { icon: IconUnlock, // 解锁 icon title: intlNode('unlock'), /* istanbul ignore next */ - action(node: Node) { + action(node: IPublicModelNode) { node.lock(false); }, }, /* istanbul ignore next */ - condition: (node: Node) => { - return engineConfig.get('enableCanvasLock', false) && node.isContainer() && node.isLocked; + condition: (node: IPublicModelNode) => { + return engineConfig.get('enableCanvasLock', false) && node.isContainerNode && node.isLocked; }, important: true, }, @@ -132,8 +133,6 @@ export class ComponentActions { } } - private metadataTransducers: IPublicTypeMetadataTransducer[] = []; - registerMetadataTransducer( transducer: IPublicTypeMetadataTransducer, level = 100, diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index b0e509bce8..9effc341dd 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -1225,7 +1225,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> const isRGLContainerNode = this.isRGLContainer; const isRGLNode = this.getParent()?.isRGLContainer; const isRGL = isRGLContainerNode || (isRGLNode && (!isContainerNode || !isEmptyNode)); - let rglNode = isRGLContainerNode ? this : isRGL ? this?.getParent() : {}; + let rglNode = isRGLContainerNode ? this : isRGL ? this?.getParent() : null; return { isContainerNode, isEmptyNode, isRGLContainerNode, isRGLNode, isRGL, rglNode }; } diff --git a/packages/shell/src/model/node.ts b/packages/shell/src/model/node.ts index f2cddd1ab8..29d24232eb 100644 --- a/packages/shell/src/model/node.ts +++ b/packages/shell/src/model/node.ts @@ -655,4 +655,24 @@ export class Node implements IPublicModelNode { setConditionalVisible(): void { this[nodeSymbol].setConditionalVisible(); } + + getRGL() { + const { + isContainerNode, + isEmptyNode, + isRGLContainerNode, + isRGLNode, + isRGL, + rglNode, + } = this[nodeSymbol].getRGL(); + + return { + isContainerNode, + isEmptyNode, + isRGLContainerNode, + isRGLNode, + isRGL, + rglNode: Node.create(rglNode), + }; + } } diff --git a/packages/types/src/shell/model/node.ts b/packages/types/src/shell/model/node.ts index 0255376aec..9d8cec3647 100644 --- a/packages/types/src/shell/model/node.ts +++ b/packages/types/src/shell/model/node.ts @@ -490,6 +490,18 @@ export interface IBaseModelNode< * 获取节点实例对应的 dom 节点 */ getDOMNode(): HTMLElement; + + /** + * 获取磁贴相关信息 + */ + getRGL(): { + isContainerNode: boolean; + isEmptyNode: boolean; + isRGLContainerNode: boolean; + isRGLNode: boolean; + isRGL: boolean; + rglNode: Node | null; + }; } export interface IPublicModelNode extends IBaseModelNode<IPublicModelDocumentModel, IPublicModelNode> {} \ No newline at end of file From dc0cf5f62c7671d6743d225fac63691f58027009 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 28 Aug 2023 15:51:50 +0800 Subject: [PATCH 253/469] fix: fix utils under appHelper will not be updated when props.appHelper is updated --- packages/renderer-core/src/renderer/base.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 99a9a40cfa..89dc143d5f 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -131,7 +131,6 @@ export default function baseRendererFactory(): IBaseRenderComponent { static contextType = AppContext; - appHelper?: IRendererAppHelper; i18n: any; getLocale: any; setLocale: any; @@ -174,7 +173,6 @@ export default function baseRendererFactory(): IBaseRenderComponent { __beforeInit(_props: IBaseRendererProps) { } __init(props: IBaseRendererProps) { - this.appHelper = props.__appHelper; this.__compScopes = {}; this.__instanceMap = {}; this.__bindCustomMethods(props); @@ -1019,6 +1017,10 @@ export default function baseRendererFactory(): IBaseRenderComponent { return !isSchema(schema) || !componentNames.includes(schema?.componentName ?? ''); }; + get appHelper(): IRendererAppHelper { + return this.props.__appHelper; + } + get requestHandlersMap() { return this.appHelper?.requestHandlersMap; } From a3b9d6ff48995e5580fe42b2507388a2e3ae03e2 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 29 Aug 2023 14:17:42 +0800 Subject: [PATCH 254/469] fix(outline-pane): when dialog is dragged, the outline pane is not displayed visible state --- packages/plugin-outline-pane/src/views/tree-title.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 02ac94ae69..c8c0e75b09 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -83,6 +83,7 @@ export default class TreeTitle extends PureComponent<{ editing: false, title: treeNode.titleLabel, condition: treeNode.condition, + visible: !treeNode.hidden, }); treeNode.onTitleLabelChanged(() => { this.setState({ From 1d572ccc0b42bd7771b7503058fdfe729f814cf6 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 31 Aug 2023 17:15:40 +0800 Subject: [PATCH 255/469] style: udpate some style for multi theme --- packages/designer/src/project/project.less | 2 +- .../editor-core/src/widgets/tip/style.less | 2 +- .../src/components/settings/style.less | 1 - packages/editor-skeleton/src/index.ts | 1 + packages/editor-skeleton/src/layouts/index.ts | 7 + .../editor-skeleton/src/layouts/left-area.tsx | 7 +- .../src/layouts/sub-top-area.tsx | 0 .../editor-skeleton/src/layouts/theme.less | 2 + .../src/layouts/workbench.less | 136 ++++-- .../plugin-outline-pane/src/views/style.less | 6 +- .../workspace/src/layouts/bottom-area.tsx | 34 -- packages/workspace/src/layouts/left-area.tsx | 50 --- .../workspace/src/layouts/left-fixed-pane.tsx | 42 -- .../workspace/src/layouts/left-float-pane.tsx | 136 ------ packages/workspace/src/layouts/main-area.tsx | 16 - packages/workspace/src/layouts/theme.less | 62 --- packages/workspace/src/layouts/top-area.tsx | 60 --- packages/workspace/src/layouts/workbench.less | 421 ------------------ packages/workspace/src/layouts/workbench.tsx | 22 +- packages/workspace/src/view/resource-view.tsx | 2 +- 20 files changed, 138 insertions(+), 871 deletions(-) create mode 100644 packages/editor-skeleton/src/layouts/index.ts rename packages/{workspace => editor-skeleton}/src/layouts/sub-top-area.tsx (100%) delete mode 100644 packages/workspace/src/layouts/bottom-area.tsx delete mode 100644 packages/workspace/src/layouts/left-area.tsx delete mode 100644 packages/workspace/src/layouts/left-fixed-pane.tsx delete mode 100644 packages/workspace/src/layouts/left-float-pane.tsx delete mode 100644 packages/workspace/src/layouts/main-area.tsx delete mode 100644 packages/workspace/src/layouts/theme.less delete mode 100644 packages/workspace/src/layouts/top-area.tsx delete mode 100644 packages/workspace/src/layouts/workbench.less diff --git a/packages/designer/src/project/project.less b/packages/designer/src/project/project.less index 9d37c73fb4..38f1f74428 100644 --- a/packages/designer/src/project/project.less +++ b/packages/designer/src/project/project.less @@ -14,7 +14,7 @@ } .lc-simulator { - background: rgb(237, 239, 243); + background-color: var(--color-background, rgb(237, 239, 243)); } .lc-simulator-shell { diff --git a/packages/editor-core/src/widgets/tip/style.less b/packages/editor-core/src/widgets/tip/style.less index 3c02e5313e..21b60b9b5d 100644 --- a/packages/editor-core/src/widgets/tip/style.less +++ b/packages/editor-core/src/widgets/tip/style.less @@ -147,7 +147,7 @@ z-index: 2; position: fixed; box-sizing: border-box; - background: rgba(0, 0, 0, 0.7); + background: var(--color-layer-tooltip-background); max-height: 400px; color: var(--color-text-reverse, rgba(255, 255, 255, 0.8)); left: 0; diff --git a/packages/editor-skeleton/src/components/settings/style.less b/packages/editor-skeleton/src/components/settings/style.less index 23b707afd8..57a7c9357f 100644 --- a/packages/editor-skeleton/src/components/settings/style.less +++ b/packages/editor-skeleton/src/components/settings/style.less @@ -143,7 +143,6 @@ .lc-outline-pane { position: absolute; z-index: 100; - background-color: white; top: 0; bottom: 0; display: none; diff --git a/packages/editor-skeleton/src/index.ts b/packages/editor-skeleton/src/index.ts index d4851ff5b0..a39b445d1f 100644 --- a/packages/editor-skeleton/src/index.ts +++ b/packages/editor-skeleton/src/index.ts @@ -8,3 +8,4 @@ export * from './components/popup'; export * from './context'; export * from './register-defaults'; export * from './widget'; +export * from './layouts'; diff --git a/packages/editor-skeleton/src/layouts/index.ts b/packages/editor-skeleton/src/layouts/index.ts new file mode 100644 index 0000000000..b3c7a10580 --- /dev/null +++ b/packages/editor-skeleton/src/layouts/index.ts @@ -0,0 +1,7 @@ +export { default as LeftArea } from './left-area'; +export { default as LeftFloatPane } from './left-float-pane'; +export { default as LeftFixedPane } from './left-fixed-pane'; +export { default as MainArea } from './main-area'; +export { default as BottomArea } from './bottom-area'; +export { default as TopArea } from './top-area'; +export { default as SubTopArea } from './sub-top-area'; \ No newline at end of file diff --git a/packages/editor-skeleton/src/layouts/left-area.tsx b/packages/editor-skeleton/src/layouts/left-area.tsx index cbeba5a5c8..d30dcfa863 100644 --- a/packages/editor-skeleton/src/layouts/left-area.tsx +++ b/packages/editor-skeleton/src/layouts/left-area.tsx @@ -4,14 +4,14 @@ import { observer } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; @observer -export default class LeftArea extends Component<{ area: Area }> { +export default class LeftArea extends Component<{ area: Area; className?: string }> { render() { - const { area } = this.props; + const { area, className = 'lc-left-area' } = this.props; if (area.isEmpty()) { return null; } return ( - <div className={classNames('lc-left-area', { + <div className={classNames(className, { 'lc-area-visible': area.visible, })} > @@ -21,7 +21,6 @@ export default class LeftArea extends Component<{ area: Area }> { } } - @observer class Contents extends Component<{ area: Area }> { render() { diff --git a/packages/workspace/src/layouts/sub-top-area.tsx b/packages/editor-skeleton/src/layouts/sub-top-area.tsx similarity index 100% rename from packages/workspace/src/layouts/sub-top-area.tsx rename to packages/editor-skeleton/src/layouts/sub-top-area.tsx diff --git a/packages/editor-skeleton/src/layouts/theme.less b/packages/editor-skeleton/src/layouts/theme.less index b0da053db1..53afb69328 100644 --- a/packages/editor-skeleton/src/layouts/theme.less +++ b/packages/editor-skeleton/src/layouts/theme.less @@ -16,6 +16,7 @@ --color-icon-hover: @normal-alpha-3; --color-icon-active: @brand-color-1; --color-icon-reverse: @white-alpha-1; + --color-icon-pane: @dark-alpha-3; --color-line-normal: @normal-alpha-7; --color-line-darken: darken(@normal-alpha-7, 10%); @@ -57,6 +58,7 @@ --color-block-background-deep-dark: @normal-5; --color-layer-mask-background: @dark-alpha-7; --color-layer-tooltip-background: rgba(44,47,51,0.8); + --color-background: #edeff3; --pane-title-bg-color: rgba(31,56,88,.04); } diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index fccdad4c2d..0a034822f4 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -38,7 +38,7 @@ body { font-family: var(--font-family); font-size: var(--font-size-text); color: var(--color-text); - background-color: #edeff3; + background-color: var(--color-background); } * { @@ -49,13 +49,10 @@ body { width: 100%; height: 100%; position: relative; - background-color: #fff; - background-color: var(--color-pane-background); &.hidden { display: none; } .lc-panel-title { - // background-color: var(--pane-title-bg-color,rgba(31,56,88,.04)); display: flex; align-items: center; justify-content: flex-start; @@ -71,7 +68,6 @@ body { height: 48px; font-size: 16px; padding: 0 15px; - // border-bottom: 1px solid var(--color-line-normal,rgba(31,56,88,.1)); color: #0f1726; font-weight: bold; } @@ -125,9 +121,6 @@ body { height: 100%; width: 100%; position: relative; - background-color: #fff; - background-color: var(--color-pane-background); - // overflow: auto; &.hidden { display: none; } @@ -137,7 +130,7 @@ body { height: 100%; display: flex; flex-direction: column; - background-color: #edeff3; + background-color: var(--color-background); position: absolute; left: 0; top: 0; @@ -164,47 +157,58 @@ body { &.active { z-index: 999; - background: #edeff3; + background: var(--color-background); } } } -.lc-workbench { +.lc-workbench, .lc-workspace-workbench { height: 100%; display: flex; flex-direction: column; - background-color: #edeff3; + background-color: var(--color-background); &.engine-main { height: 100%; display: flex; flex-direction: column; - background-color: #edeff3; + background-color: var(--color-background); } - .lc-top-area { - height: var(--top-area-height); - background-color: var(--color-pane-background); + .lc-top-area, .lc-sub-top-area { width: 100%; display: none; margin-bottom: 2px; padding: 8px 12px 8px 16px; + &.lc-top-area { + background-color: var(--color-top-area-background, var(--color-pane-background)); + height: var(--top-area-height); + } + + &.lc-sub-top-area { + background-color: var(--color-sub-top-area-background, var(--color-pane-background)); + height: var(--sub-top-area-height, var(--top-area-height)); + margin: var(--sub-top-area-margin, 0px 0px 2px 0px); + padding: var(--sub-top-area-padding, 8px 12px 8px 16px); + } + &.lc-area-visible { display: flex; } - .lc-top-area-left { + .lc-top-area-left, .lc-sub-top-area-left { display: flex; align-items: center; + max-width: 100%; } - .lc-top-area-center { + .lc-top-area-center, .lc-sub-top-area-center { flex: 1; display: flex; justify-content: center; margin: 0 8px; } - .lc-top-area-right { + .lc-top-area-right, .lc-sub-top-area-right { display: flex; align-items: center; > * { @@ -216,7 +220,7 @@ body { } } } - .lc-workbench-body { + .lc-workbench-body, .lc-workspace-workbench-body { flex: 1; display: flex; min-height: 0; @@ -264,7 +268,7 @@ body { z-index: 2; .next-icon { line-height: 1; - color: rgba(0, 0, 0, 0.6); + color: var(--color-icon-pane); } } @@ -277,7 +281,7 @@ body { z-index: 2; svg { vertical-align: middle; - color: rgba(0, 0, 0, 0.6); + color: var(--color-icon-pane); } } @@ -288,7 +292,7 @@ body { width: var(--dock-pane-width); // min-width: var(--dock-fixed-pane-width); left: calc(var(--left-area-width) + 1px); - background-color: var(--color-pane-background); + background-color: var(--color-left-float-pane-background, var(--color-pane-background)); box-shadow: 4px 6px 6px 0 rgba(31, 50, 88, 0.08); z-index: 820; display: none; @@ -297,15 +301,20 @@ body { display: block; } } - .lc-left-area { + .lc-left-area, .lc-workspace-left-area { height: 100%; width: var(--left-area-width); - background-color: var(--color-pane-background); display: none; flex-shrink: 0; flex-direction: column; justify-content: space-between; overflow: hidden; + &.lc-left-area { + background-color: var(--color-left-area-background, var(--color-pane-background)); + } + &.lc-workspace-left-area { + background-color: var(--color-workspace-left-area-background, var(--color-pane-background)); + } &.lc-area-visible { display: flex; } @@ -316,6 +325,8 @@ body { flex-direction: column; justify-content: flex-start; align-items: center; + color: var(--color-text); + .lc-title { flex-direction: column; width: calc(var(--left-area-width) - 2px); @@ -325,6 +336,9 @@ body { justify-content: center; cursor: pointer; + &.has-tip { + cursor: pointer; + } &.actived { color: #0079f2; } @@ -366,6 +380,9 @@ body { .lc-left-area.lc-area-visible ~ .lc-workbench-center { margin-left: 2px; } + .lc-workspace-left-area.lc-area-visible ~ .lc-workspace-workbench-center { + margin-left: 2px; + } .lc-outline-pane { .lc-outline-tree .tree-node .tree-node-title { border-bottom: none; @@ -390,7 +407,7 @@ body { } .lc-main-area { flex: 1; - background-color: #edeff3; + background-color: var(--color-background); } .lc-bottom-area { height: var(--bottom-area-height); @@ -404,13 +421,14 @@ body { .lc-right-area { height: 100%; width: var(--right-area-width); - background-color: var(--color-pane-background); + background-color: var(--color-right-area-background, var(--color-pane-background)); display: none; flex-shrink: 0; margin-left: 2px; position: relative; > .lc-panel { position: absolute; + background-color: var(--color-right-area-background, var(--color-pane-background, #fff)); left: 0; top: 0; } @@ -437,4 +455,68 @@ body { } } } + .engine-actionitem { + max-width: 100%; + color: var(--color-text); + } +} + +.lc-workspace-workbench { + height: 100%; + display: flex; + flex-direction: column; + background-color: var(--color-background); + .lc-workspace-workbench-body { + flex: 1; + display: flex; + min-height: 0; + position: relative; + + .lc-workspace-workbench-center { + flex: 1; + display: flex; + flex-direction: column; + z-index: 10; + position: relative; + .lc-toolbar { + display: flex; + height: var(--toolbar-height); + background-color: var(--color-pane-background); + padding: 8px 16px; + .lc-toolbar-center { + display: flex; + justify-content: center; + align-items: center; + flex: 1; + } + } + .lc-main-area { + flex: 1; + } + .lc-bottom-area { + height: var(--bottom-area-height); + background-color: var(--color-pane-background); + display: none; + &.lc-area-visible { + display: block; + } + } + } + + .lc-workspace-workbench-center-content { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + flex-direction: column; + display: flex; + align-content: stretch; + } + + .lc-workspace-workbench-window { + position: relative; + height: 100%; + } + } } diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index 254b639d62..406a5b5da4 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -3,7 +3,6 @@ width: 100%; position: relative; z-index: 200; - background-color: white; > .lc-outline-tree-container { top: 52px; @@ -29,8 +28,8 @@ } .lc-outline-filter-icon { - background: #ebecf0; - border: 1px solid #c4c6cf; + background: var(--color-block-background-shallow, #ebecf0); + border: 1px solid var(--color-field-border, #c4c6cf); display: flex; align-items: center; border-radius: 0 2px 2px 0; @@ -245,7 +244,6 @@ .tree-node-title { font-size: var(--font-size-text); cursor: pointer; - background: var(--color-pane-background); border-bottom: 1px solid var(--color-line-normal, rgba(31, 56, 88, 0.1)); display: flex; align-items: center; diff --git a/packages/workspace/src/layouts/bottom-area.tsx b/packages/workspace/src/layouts/bottom-area.tsx deleted file mode 100644 index 5fc4d815bc..0000000000 --- a/packages/workspace/src/layouts/bottom-area.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Component, Fragment } from 'react'; -import classNames from 'classnames'; -import { observer } from '@alilc/lowcode-editor-core'; -import { Area, Panel } from '@alilc/lowcode-editor-skeleton'; - -@observer -export default class BottomArea extends Component<{ area: Area<any, Panel> }> { - render() { - const { area } = this.props; - if (area.isEmpty()) { - return null; - } - return ( - <div className={classNames('lc-bottom-area', { - 'lc-area-visible': area.visible, - })} - > - <Contents area={area} /> - </div> - ); - } -} - -@observer -class Contents extends Component<{ area: Area<any, Panel> }> { - render() { - const { area } = this.props; - return ( - <Fragment> - {area.container.items.map((item) => item.content)} - </Fragment> - ); - } -} diff --git a/packages/workspace/src/layouts/left-area.tsx b/packages/workspace/src/layouts/left-area.tsx deleted file mode 100644 index 3057386eda..0000000000 --- a/packages/workspace/src/layouts/left-area.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Component, Fragment } from 'react'; -import classNames from 'classnames'; -import { observer } from '@alilc/lowcode-editor-core'; -import { Area } from '@alilc/lowcode-editor-skeleton'; - -@observer -export default class LeftArea extends Component<{ area: Area }> { - render() { - const { area } = this.props; - if (area.isEmpty()) { - return null; - } - return ( - <div className={classNames('lc-left-area', { - 'lc-area-visible': area.visible, - })} - > - <Contents area={area} /> - </div> - ); - } -} - - -@observer -class Contents extends Component<{ area: Area }> { - render() { - const { area } = this.props; - const top: any[] = []; - const bottom: any[] = []; - area.container.items.slice().sort((a, b) => { - const index1 = a.config?.index || 0; - const index2 = b.config?.index || 0; - return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1); - }).forEach((item) => { - const content = <div key={`left-area-${item.name}`}>{item.content}</div>; - if (item.align === 'bottom') { - bottom.push(content); - } else { - top.push(content); - } - }); - return ( - <Fragment> - <div className="lc-left-area-top">{top}</div> - <div className="lc-left-area-bottom">{bottom}</div> - </Fragment> - ); - } -} diff --git a/packages/workspace/src/layouts/left-fixed-pane.tsx b/packages/workspace/src/layouts/left-fixed-pane.tsx deleted file mode 100644 index e0c01c5109..0000000000 --- a/packages/workspace/src/layouts/left-fixed-pane.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Component, Fragment } from 'react'; -import classNames from 'classnames'; -import { observer } from '@alilc/lowcode-editor-core'; -import { Area, Panel, PanelConfig } from '@alilc/lowcode-editor-skeleton'; - -@observer -export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, Panel> }> { - componentDidUpdate() { - // FIXME: dirty fix, need deep think - this.props.area.skeleton.editor.get('designer')?.touchOffsetObserver(); - } - - - render() { - const { area } = this.props; - const width = area.current?.config.props?.width; - const style = width - ? { - width, - } - : undefined; - - return ( - <div - className={classNames('lc-left-fixed-pane', { - 'lc-area-visible': area.visible, - })} - style={style} - > - <Contents area={area} /> - </div> - ); - } -} - -@observer -class Contents extends Component<{ area: Area<PanelConfig, Panel> }> { - render() { - const { area } = this.props; - return <Fragment>{area.container.items.map((panel) => panel.content)}</Fragment>; - } -} diff --git a/packages/workspace/src/layouts/left-float-pane.tsx b/packages/workspace/src/layouts/left-float-pane.tsx deleted file mode 100644 index 3df3e197c2..0000000000 --- a/packages/workspace/src/layouts/left-float-pane.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { Component, Fragment } from 'react'; -import classNames from 'classnames'; -import { observer, Focusable } from '@alilc/lowcode-editor-core'; -import { Area, Panel } from '@alilc/lowcode-editor-skeleton'; -import { IPublicApiProject } from '@alilc/lowcode-types'; - -@observer -export default class LeftFloatPane extends Component<{ area: Area<any, Panel> }> { - private dispose?: () => void; - - private focusing?: Focusable; - - private shell: HTMLElement | null = null; - - componentDidMount() { - const { area } = this.props; - const triggerClose = (e: any) => { - if (!area.visible) return; - // 当 MouseEvent 的 target 为「插入占位符」时,不关闭当前 panel - if (e.originalEvent?.target?.classList.contains('insertion')) return; - // 假如当前操作 target 祖先节点中有属性 data-keep-visible-while-dragging="true" 代表该 target 所属 panel - // 不希望 target 在 panel 范围内拖拽时关闭 panel - const panelElem = e.originalEvent?.target.closest('div[data-keep-visible-while-dragging="true"]'); - if (panelElem) return; - area.setVisible(false); - }; - area.skeleton.editor.eventBus.on('designer.drag', triggerClose); - - this.dispose = () => { - area.skeleton.editor.removeListener('designer.drag', triggerClose); - }; - - const project: IPublicApiProject | undefined = area.skeleton.editor.get('project'); - - this.focusing = area.skeleton.focusTracker.create({ - range: (e) => { - const target = e.target as HTMLElement; - if (!target) { - return false; - } - if (this.shell?.contains(target)) { - return true; - } - // 点击了 iframe 内容,算失焦 - if ((document.querySelector('.lc-simulator-content-frame') as HTMLIFrameElement)?.contentWindow?.document.documentElement.contains(target)) { - return false; - } - if (project?.simulatorHost?.contentWindow?.document.documentElement.contains(target)) { - return false; - } - // 点击设置区 - if (document.querySelector('.lc-right-area')?.contains(target)) { - return false; - } - // 点击非编辑区域的popup/dialog,插件栏左侧等不触发失焦 - if (!document.querySelector('.lc-workbench')?.contains(target)) { - return true; - } - // 排除设置区,iframe 之后,都不算失焦 - if (document.querySelector('.lc-workbench-body')?.contains(target)) { - return true; - } - const docks = area.current?.getAssocDocks(); - if (docks && docks?.length) { - return docks.some(dock => dock.getDOMNode()?.contains(target)); - } - return false; - }, - onEsc: () => { - this.props.area.setVisible(false); - }, - onBlur: () => { - this.props.area.setVisible(false); - }, - }); - - this.onEffect(); - } - - onEffect() { - const { area } = this.props; - if (area.visible) { - this.focusing?.active(); - // 关闭当前fixed区域的面板 - // TODO: 看看有没有更合适的地方 - const fixedContainer = area?.skeleton?.leftFixedArea?.container; - const currentFixed = fixedContainer?.current; - if (currentFixed) { - fixedContainer.unactive(currentFixed); - } - } else { - this.focusing?.suspense(); - } - } - - componentDidUpdate() { - this.onEffect(); - } - - componentWillUnmount() { - this.focusing?.purge(); - this.dispose?.(); - } - - render() { - const { area } = this.props; - const width = area.current?.config.props?.width; - - const style = width ? { - width, - } : undefined; - return ( - <div - ref={(ref) => { this.shell = ref; }} - className={classNames('lc-left-float-pane', { - 'lc-area-visible': area.visible, - })} - style={style} - > - <Contents area={area} /> - </div> - ); - } -} - -@observer -class Contents extends Component<{ area: Area<any, Panel> }> { - render() { - const { area } = this.props; - return ( - <Fragment> - {area.container.items.map((panel) => panel.content)} - </Fragment> - ); - } -} diff --git a/packages/workspace/src/layouts/main-area.tsx b/packages/workspace/src/layouts/main-area.tsx deleted file mode 100644 index 5313d7007e..0000000000 --- a/packages/workspace/src/layouts/main-area.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Component } from 'react'; -import classNames from 'classnames'; -import { observer } from '@alilc/lowcode-editor-core'; -import { Area, Panel, Widget } from '@alilc/lowcode-editor-skeleton'; - -@observer -export default class MainArea extends Component<{ area: Area<any, Panel | Widget> }> { - render() { - const { area } = this.props; - return ( - <div className={classNames('lc-main-area engine-workspacepane')}> - {area.container.items.map((item) => item.content)} - </div> - ); - } -} diff --git a/packages/workspace/src/layouts/theme.less b/packages/workspace/src/layouts/theme.less deleted file mode 100644 index b0da053db1..0000000000 --- a/packages/workspace/src/layouts/theme.less +++ /dev/null @@ -1,62 +0,0 @@ -@import '../less-variables.less'; - -/* - * Theme Colors - * - * 乐高设计器的主要主题色变量 - */ -:root { - --color-brand: @brand-color-1; - --color-brand-light: @brand-color-2; - --color-brand-dark: @brand-color-3; - - --color-canvas-background: @normal-alpha-8; - - --color-icon-normal: @normal-alpha-4; - --color-icon-hover: @normal-alpha-3; - --color-icon-active: @brand-color-1; - --color-icon-reverse: @white-alpha-1; - - --color-line-normal: @normal-alpha-7; - --color-line-darken: darken(@normal-alpha-7, 10%); - - --color-title: @dark-alpha-2; - --color-text: @dark-alpha-3; - --color-text-dark: darken(@dark-alpha-3, 10%); - --color-text-light: lighten(@dark-alpha-3, 10%); - --color-text-reverse: @white-alpha-2; - --color-text-regular: @normal-alpha-2; - - --color-field-label: @dark-alpha-4; - --color-field-text: @dark-alpha-3; - --color-field-placeholder: @normal-alpha-5; - --color-field-border: @normal-alpha-5; - --color-field-border-hover: @normal-alpha-4; - --color-field-border-active: @normal-alpha-3; - --color-field-background: @white-alpha-1; - - --color-function-success: @brand-success; - --color-function-success-dark: darken(@brand-success, 10%); - --color-function-success-light: lighten(@brand-success, 10%); - --color-function-warning: @brand-warning; - --color-function-warning-dark: darken(@brand-warning, 10%); - --color-function-warning-light: lighten(@brand-warning, 10%); - --color-function-information: @brand-link-hover; - --color-function-information-dark: darken(@brand-link-hover, 10%); - --color-function-information-light: lighten(@brand-link-hover, 10%); - --color-function-error: @brand-danger; - --color-function-error-dark: darken(@brand-danger, 10%); - --color-function-error-light: lighten(@brand-danger, 10%); - - --color-pane-background: @white-alpha-1; - --color-block-background-normal: @white-alpha-1; - --color-block-background-light: @normal-alpha-9; - --color-block-background-shallow: @normal-alpha-8; - --color-block-background-dark: @normal-alpha-7; - --color-block-background-disabled: @normal-alpha-6; - --color-block-background-deep-dark: @normal-5; - --color-layer-mask-background: @dark-alpha-7; - --color-layer-tooltip-background: rgba(44,47,51,0.8); - - --pane-title-bg-color: rgba(31,56,88,.04); -} diff --git a/packages/workspace/src/layouts/top-area.tsx b/packages/workspace/src/layouts/top-area.tsx deleted file mode 100644 index cecaee2a71..0000000000 --- a/packages/workspace/src/layouts/top-area.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { Component, Fragment } from 'react'; -import classNames from 'classnames'; -import { observer } from '@alilc/lowcode-editor-core'; -import { Area } from '@alilc/lowcode-editor-skeleton'; - -@observer -export default class TopArea extends Component<{ area: Area; itemClassName?: string }> { - render() { - const { area, itemClassName } = this.props; - - if (area.isEmpty()) { - return null; - } - - return ( - <div className={classNames('lc-top-area engine-actionpane', { - 'lc-area-visible': area.visible, - })} - > - <Contents area={area} itemClassName={itemClassName} /> - </div> - ); - } -} - -@observer -class Contents extends Component<{ area: Area; itemClassName?: string }> { - render() { - const { area, itemClassName } = this.props; - const left: any[] = []; - const center: any[] = []; - const right: any[] = []; - area.container.items.slice().sort((a, b) => { - const index1 = a.config?.index || 0; - const index2 = b.config?.index || 0; - return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1); - }).forEach(item => { - const content = ( - <div className={itemClassName || ''} key={`top-area-${item.name}`}> - {item.content} - </div> - ); - if (item.align === 'center') { - center.push(content); - } else if (item.align === 'left') { - left.push(content); - } else { - right.push(content); - } - }); - - return ( - <Fragment> - <div className="lc-top-area-left">{left}</div> - <div className="lc-top-area-center">{center}</div> - <div className="lc-top-area-right">{right}</div> - </Fragment> - ); - } -} diff --git a/packages/workspace/src/layouts/workbench.less b/packages/workspace/src/layouts/workbench.less deleted file mode 100644 index 05eb5f513b..0000000000 --- a/packages/workspace/src/layouts/workbench.less +++ /dev/null @@ -1,421 +0,0 @@ -@import './theme.less'; - -:root { - --font-family: @font-family; - --font-size-label: @fontSize-4; - --font-size-text: @fontSize-5; - --font-size-btn-large: @fontSize-3; - --font-size-btn-medium: @fontSize-4; - --font-size-btn-small: @fontSize-5; - - --global-border-radius: @global-border-radius; - --input-border-radius: @input-border-radius; - --popup-border-radius: @popup-border-radius; - - --left-area-width: 48px; - --right-area-width: 300px; - --top-area-height: 48px; - --toolbar-height: 36px; - --dock-pane-width: 300px; - --dock-fixed-pane-width: 300px; -} - -@media (min-width: 1860px) { - :root { - --right-area-width: 400px; - --dock-pane-width: 452px; - --dock-fixed-pane-width: 350px; - } -} - -html, -body { - height: 100%; - overflow: hidden; - padding: 0; - margin: 0; - position: relative; - font-family: var(--font-family); - font-size: var(--font-size-text); - color: var(--color-text); - background-color: #edeff3; -} - -* { - box-sizing: border-box; -} - -.lc-titled-panel { - width: 100%; - height: 100%; - position: relative; - background-color: #fff; - background-color: var(--color-pane-background); - &.hidden { - display: none; - } - .lc-panel-title { - // background-color: var(--pane-title-bg-color,rgba(31,56,88,.04)); - display: flex; - align-items: center; - justify-content: flex-start; - padding: 0 15px; - - .lc-help-tip { - margin-left: 4px; - color: rgba(0, 0, 0, 0.4); - cursor: pointer; - } - } - > .lc-panel-title { - height: 48px; - font-size: 16px; - padding: 0 15px; - // border-bottom: 1px solid var(--color-line-normal,rgba(31,56,88,.1)); - color: #0f1726; - font-weight: bold; - } - - .lc-panel-body { - position: absolute; - top: 48px; - bottom: 0; - left: 0; - right: 0; - overflow: visible; - /* - .my-tabs { - width: 100%; - height: 100%; - position: relative; - .tabs-title { - display: flex; - height: var(--pane-title-height); - > .tab-title { - cursor: pointer; - padding: 0; - flex: 1; - min-width: 0; - justify-content: center; - border-bottom: 2px solid transparent; - &.actived { - cursor: default; - color: var(--color-text-avtived); - border-bottom-color: #3896ee; - } - } - } - .tabs-content { - position: absolute; - top: var(--pane-title-height); - bottom: 0; - left: 0; - right: 0; - height: calc(100% - var(--pane-title-height)); - overflow: hidden; - } - } - */ - } - .lc-outline-tree-container { - border-top: 1px solid var(--color-line-normal, rgba(31, 56, 88, 0.1)); - } -} -.lc-panel { - height: 100%; - width: 100%; - position: relative; - background-color: #fff; - background-color: var(--color-pane-background); - // overflow: auto; - &.hidden { - display: none; - } -} - -.lc-workspace-workbench { - height: 100%; - display: flex; - flex-direction: column; - background-color: #edeff3; - .lc-top-area, .lc-sub-top-area { - height: var(--top-area-height); - background-color: var(--color-pane-background); - width: 100%; - display: none; - margin-bottom: 2px; - padding: 8px 12px 8px 16px; - - &.lc-area-visible { - display: flex; - } - - .lc-top-area-left, .lc-sub-top-area-left { - display: flex; - align-items: center; - max-width: 100%; - } - - .lc-top-area-center, .lc-sub-top-area-center { - flex: 1; - display: flex; - justify-content: center; - margin: 0 8px; - } - .lc-top-area-right, .lc-sub-top-area-right { - display: flex; - align-items: center; - > * { - margin-left: 4px; - margin-right: 4px; - } - .ve-quick-search-trigger { - display: flex; - } - } - } - .lc-workspace-workbench-body { - flex: 1; - display: flex; - min-height: 0; - position: relative; - - .lc-tabs-title { - width: 100%; - height: 32px; - position: relative; - display: center; - display: flex; - justify-content: center; - align-items: center; - // background: rgba(31,56,88,0.04); - border-bottom: 1px solid #edeff3; - .lc-tab-title { - flex: 1; - height: 32px; - display: flex; - align-items: center; - justify-content: center; - border-bottom: 2px solid transparent; - cursor: pointer; - font-size: 12px; - &.actived { - color: #0079f2; - border-bottom-color: #0079f2; - } - } - } - - .lc-tabs-content { - position: absolute; - top: 32px; - bottom: 0; - left: 0; - right: 0; - } - - .lc-pane-icon-close { - position: absolute; - right: 16px; - top: 14px; - height: auto; - z-index: 2; - .next-icon { - line-height: 1; - color: rgba(0, 0, 0, 0.6); - } - } - - .lc-pane-icon-fix, - .lc-pane-icon-float { - position: absolute; - right: 38px; - top: 14px; - height: auto; - z-index: 2; - svg { - vertical-align: middle; - color: rgba(0, 0, 0, 0.6); - } - } - - .lc-left-float-pane { - position: absolute; - top: 0; - bottom: 0; - width: var(--dock-pane-width); - // min-width: var(--dock-fixed-pane-width); - left: calc(var(--left-area-width) + 1px); - background-color: var(--color-pane-background); - box-shadow: 4px 6px 6px 0 rgba(31, 50, 88, 0.08); - z-index: 820; - display: none; - // padding-top: 36px; - &.lc-area-visible { - display: block; - } - } - .lc-left-area { - height: 100%; - width: var(--left-area-width); - background-color: var(--color-pane-background); - display: none; - flex-shrink: 0; - flex-direction: column; - justify-content: space-between; - overflow: hidden; - &.lc-area-visible { - display: flex; - } - .lc-left-area-top, - .lc-left-area-bottom { - width: 100%; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: center; - .lc-title { - flex-direction: column; - width: calc(var(--left-area-width) - 2px); - height: 46px; - display: flex; - align-items: center; - justify-content: center; - - &.has-tip { - cursor: pointer; - } - &.actived { - color: #0079f2; - } - &.disabled { - opacity: 0.4; - } - .lc-title-icon { - height: 20px; - width: 20px; - margin: 0; - .next-icon:before { - line-height: 1 !important; - } - } - } - } - .lc-left-area-top { - padding-top: 12px; - } - .lc-left-area-bottom { - padding-bottom: 12px; - } - } - .lc-left-fixed-pane { - width: var(--dock-fixed-pane-width); - background-color: var(--color-pane-background); - height: 100%; - display: none; - flex-shrink: 0; - position: relative; - z-index: 820; - &.lc-area-visible { - display: block; - } - } - .lc-left-area.lc-area-visible ~ .lc-left-fixed-pane { - margin-left: 1px; - } - .lc-left-area.lc-area-visible ~ .lc-workspace-workbench-center { - margin-left: 2px; - } - .lc-outline-pane { - .lc-outline-tree .tree-node .tree-node-title { - border-bottom: none; - } - } - .lc-workspace-workbench-center { - flex: 1; - display: flex; - flex-direction: column; - z-index: 10; - position: relative; - .lc-toolbar { - display: flex; - height: var(--toolbar-height); - background-color: var(--color-pane-background); - padding: 8px 16px; - .lc-toolbar-center { - display: flex; - justify-content: center; - align-items: center; - flex: 1; - } - } - .lc-main-area { - flex: 1; - } - .lc-bottom-area { - height: var(--bottom-area-height); - background-color: var(--color-pane-background); - display: none; - &.lc-area-visible { - display: block; - } - } - } - - .lc-workspace-workbench-center-content { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - flex-direction: column; - display: flex; - align-content: stretch; - } - - .engine-actionitem { - max-width: 100%; - } - - .lc-workspace-workbench-window { - position: relative; - height: 100%; - } - - .lc-right-area { - height: 100%; - width: var(--right-area-width); - background-color: var(--color-pane-background); - display: none; - flex-shrink: 0; - margin-left: 2px; - position: relative; - > .lc-panel { - position: absolute; - left: 0; - top: 0; - } - &.lc-area-visible { - display: block; - } - .lc-settings-tabs { - > .next-tabs-nav-extra { - top: 36px !important; - } - .lc-settings-tab-item { - .next-tabs-tab-inner { - font-size: 12px; - line-height: 12px; - } - } - .lc-title { - color: inherit; - line-height: inherit !important; - } - } - .lc-settings-tabs-content { - top: 66px; - } - } - } -} diff --git a/packages/workspace/src/layouts/workbench.tsx b/packages/workspace/src/layouts/workbench.tsx index 08d6dc1a93..7d2d96df12 100644 --- a/packages/workspace/src/layouts/workbench.tsx +++ b/packages/workspace/src/layouts/workbench.tsx @@ -2,17 +2,10 @@ import { Component } from 'react'; import { TipContainer, engineConfig, observer } from '@alilc/lowcode-editor-core'; import { WindowView } from '../view/window-view'; import classNames from 'classnames'; -import TopArea from './top-area'; -import LeftArea from './left-area'; -import LeftFixedPane from './left-fixed-pane'; -import LeftFloatPane from './left-float-pane'; -import MainArea from './main-area'; -import BottomArea from './bottom-area'; -import './workbench.less'; import { SkeletonContext } from '../skeleton-context'; import { EditorConfig, PluginClassSet } from '@alilc/lowcode-types'; import { Workspace } from '../workspace'; -import SubTopArea from './sub-top-area'; +import { BottomArea, LeftArea, LeftFixedPane, LeftFloatPane, MainArea, SubTopArea, TopArea } from '@alilc/lowcode-editor-skeleton'; @observer export class Workbench extends Component<{ @@ -23,12 +16,18 @@ export class Workbench extends Component<{ topAreaItemClassName?: string; }, { workspaceEmptyComponent: any; + theme?: string; }> { constructor(props: any) { super(props); const { config, components, workspace } = this.props; const { skeleton } = workspace; skeleton.buildFromConfig(config, components); + engineConfig.onGot('theme', (theme) => { + this.setState({ + theme, + }); + }); engineConfig.onGot('workspaceEmptyComponent', (workspaceEmptyComponent) => { this.setState({ workspaceEmptyComponent, @@ -36,20 +35,21 @@ export class Workbench extends Component<{ }); this.state = { workspaceEmptyComponent: engineConfig.get('workspaceEmptyComponent'), + theme: engineConfig.get('theme'), }; } render() { const { workspace, className, topAreaItemClassName } = this.props; const { skeleton } = workspace; - const WorkspaceEmptyComponent = this.state.workspaceEmptyComponent; + const { workspaceEmptyComponent: WorkspaceEmptyComponent, theme } = this.state; return ( - <div className={classNames('lc-workspace-workbench', className)}> + <div className={classNames('lc-workspace-workbench', className, theme)}> <SkeletonContext.Provider value={skeleton}> <TopArea area={skeleton.topArea} itemClassName={topAreaItemClassName} /> <div className="lc-workspace-workbench-body"> - <LeftArea area={skeleton.leftArea} /> + <LeftArea className="lc-workspace-left-area" area={skeleton.leftArea} /> <LeftFloatPane area={skeleton.leftFloatArea} /> <LeftFixedPane area={skeleton.leftFixedArea} /> <div className="lc-workspace-workbench-center"> diff --git a/packages/workspace/src/view/resource-view.tsx b/packages/workspace/src/view/resource-view.tsx index 9ef30af092..e2204dd505 100644 --- a/packages/workspace/src/view/resource-view.tsx +++ b/packages/workspace/src/view/resource-view.tsx @@ -1,10 +1,10 @@ import { PureComponent } from 'react'; import { EditorView } from './editor-view'; import { observer } from '@alilc/lowcode-editor-core'; -import TopArea from '../layouts/top-area'; import { IResource } from '../resource'; import { IEditorWindow } from '../window'; import './resource-view.less'; +import { TopArea } from '@alilc/lowcode-editor-skeleton'; @observer export class ResourceView extends PureComponent<{ From f48c49c21f72c34cb3b0791baa39ba7e8629c74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=BE=E5=B8=85?= <21106848+sdshaoda@users.noreply.github.com> Date: Thu, 31 Aug 2023 16:26:30 +0800 Subject: [PATCH 256/469] docs: Update summary.md add material spec link --- docs/docs/guide/design/summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/guide/design/summary.md b/docs/docs/guide/design/summary.md index cd5edfd886..38d523cac9 100644 --- a/docs/docs/guide/design/summary.md +++ b/docs/docs/guide/design/summary.md @@ -20,7 +20,7 @@ sidebar_position: 0 低代码引擎分为 4 大模块,入料 - 编排 - 渲染 - 出码: -- 入料模块就是将外部的物料,比如海量的 npm 组件,按照《物料描述协议》进行描述。将描述后的数据通过引擎 API 注册后,在编辑器中使用。 +- 入料模块就是将外部的物料,比如海量的 npm 组件,按照[《低代码引擎物料协议规范》](/site/docs/specs/material-spec)进行描述。将描述后的数据通过引擎 API 注册后,在编辑器中使用。 > **注意,这里仅是增加描述,而非重写一套,这样我们能最大程度复用 ProCode 体系已沉淀的组件。** - 编排,本质上来讲,就是**不断在生成符合[《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec)的页面描述,将编辑器中的所有物料,进行布局设置、组件 CRUD 操作、以及 JS / CSS 编写/ 逻辑编排 **等,最终转换成页面描述,技术细节后文会展开。 - 渲染,顾名思义,就是**将编排生成的页面描述结构渲染成视图的过程**,视图是面向用户的,所以必须处理好内部数据流、生命周期、事件绑定、国际化等。 From 2c2241ef73d5582084202e562dd82f551c8367f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 4 Sep 2023 11:44:36 +0800 Subject: [PATCH 257/469] Revert "fix(material): fix rendering is blocked, when the url in the asset fails to load" This reverts commit 8b5e2b47c6668817e365b31277f2b2d6c9313cca. --- packages/editor-core/src/editor.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index 10aa0bea1c..f31a2a2dda 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -153,11 +153,7 @@ export class Editor extends EventEmitter implements IEditor { return; } if (!AssetsCache[exportName] || !npm?.version || AssetsCache[exportName].npm?.version !== npm?.version) { - try { - await (new AssetLoader()).load(url); - } catch (error) { - console.error(`${url} load error: `, error); - } + await (new AssetLoader()).load(url); } AssetsCache[exportName] = component; function setAssetsComponent(component: any, extraNpmInfo: any = {}) { From bfdc7a277ba4713dbfdd1c9efe01bbd9126a4219 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 4 Sep 2023 11:51:18 +0800 Subject: [PATCH 258/469] feat(workspace): fix onWindowRendererReady api --- packages/workspace/src/layouts/workbench.tsx | 2 +- packages/workspace/src/window.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/workspace/src/layouts/workbench.tsx b/packages/workspace/src/layouts/workbench.tsx index 7d2d96df12..9bdbe3f932 100644 --- a/packages/workspace/src/layouts/workbench.tsx +++ b/packages/workspace/src/layouts/workbench.tsx @@ -49,7 +49,7 @@ export class Workbench extends Component<{ <SkeletonContext.Provider value={skeleton}> <TopArea area={skeleton.topArea} itemClassName={topAreaItemClassName} /> <div className="lc-workspace-workbench-body"> - <LeftArea className="lc-workspace-left-area" area={skeleton.leftArea} /> + <LeftArea className="lc-workspace-left-area lc-left-area" area={skeleton.leftArea} /> <LeftFloatPane area={skeleton.leftFloatArea} /> <LeftFixedPane area={skeleton.leftFixedArea} /> <div className="lc-workspace-workbench-center"> diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index 2c670346fb..ce5aab4142 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -126,9 +126,10 @@ export class EditorWindow implements IEditorWindow { async init() { await this.initViewTypes(); await this.execViewTypesInit(); - Promise.all(Array.from(this.editorViews.values()).map((d) => d.onSimulatorRendererReady)).then(() => { - this.workspace.emitWindowRendererReady(); - }); + Promise.all(Array.from(this.editorViews.values()).map((d) => d.onSimulatorRendererReady())) + .then(() => { + this.workspace.emitWindowRendererReady(); + }); this.url = await this.resource.url(); this.setDefaultViewName(); this.initReady = true; From 4677d99127f25f202805b23f661c7f1cc1fc5a3a Mon Sep 17 00:00:00 2001 From: "chenkeyao.chenkeya" <chenkeyao.chenkeya@alibaba-inc.com> Date: Tue, 5 Sep 2023 14:53:30 +0800 Subject: [PATCH 259/469] feat: Modify the content of the article menu and add a video menu --- docs/config/navbar.js | 6 ++++++ docs/docs/article/index.md | 32 ++------------------------------ docs/docs/video/index.md | 13 +++++++++++++ 3 files changed, 21 insertions(+), 30 deletions(-) create mode 100644 docs/docs/video/index.md diff --git a/docs/config/navbar.js b/docs/config/navbar.js index 20d5e5f90c..24f8a39376 100644 --- a/docs/config/navbar.js +++ b/docs/config/navbar.js @@ -39,6 +39,12 @@ module.exports = { position: 'left', label: '文章', }, + { + type: 'doc', + docId: 'video/index', + position: 'left', + label: '视频', + }, { type: 'doc', docId: 'demoUsage/intro', diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index 8ff76ff476..2f6f2cee3f 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -1,8 +1,4 @@ ---- -title: 低代码引擎相关文章资料 ---- - -## 官方文章 +# 官方文章 - [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) @@ -14,28 +10,4 @@ title: 低代码引擎相关文章资料 - [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) - -## Portal 设计项目实战 -#### 直播回放 -[https://www.bilibili.com/video/BV1AS4y1K7DP/](https://www.bilibili.com/video/BV1AS4y1K7DP/) - -#### 示例项目 -- 前端: [https://github.com/mark-ck/lowcode-portal](https://github.com/mark-ck/lowcode-portal) -- 后端: [https://github.com/mark-ck/document-solution-site](https://github.com/mark-ck/document-solution-site) -- 组件库:[https://github.com/mark-ck/portal-components](https://github.com/mark-ck/portal-components) - -**注意** -1. 前端项目要把代码里请求接口的域名改成本地或者自己的域名; -2. 后端项目要把 config.default.js 里的 yuque 和 oss 配置补全; - -#### 视频链接 -- [阿里低代码引擎项目实战 (1)-引擎 demo 部署到 faas 服务](https://www.bilibili.com/video/BV1B44y1P7GM/) -- [【有翻车】阿里低代码引擎项目实战 (2)-保存页面到远端存储](https://www.bilibili.com/video/BV1AS4y1K7DP/) -- [阿里巴巴低代码引擎项目实战 (3)-自定义组件接入](https://www.bilibili.com/video/BV1dZ4y1m76S/) -- [阿里低代码引擎项目实战 (4)-自定义插件 - 页面管理](https://www.bilibili.com/video/BV17a411i73f/) -- [阿里低代码引擎项目实战 (4)-用户登录](https://www.bilibili.com/video/BV1Wu411e7EQ/) -- [【有翻车】阿里低代码引擎项目实战 (5)-表单回显](https://www.bilibili.com/video/BV1UY4y1v7D7/) -- [阿里低代码引擎项目实战 (6)-自定义插件 - 页面管理 - 后端](https://www.bilibili.com/video/BV1uZ4y1U7Ly/) -- [阿里低代码引擎项目实战 (6)-自定义插件 - 页面管理 - 前端](https://www.bilibili.com/video/BV1Yq4y1a74P/) -- [阿里低代码引擎项目实战 (7)-自定义插件 - 页面管理 (完结)](https://www.bilibili.com/video/BV13Y4y1e7EV/) +- [2021/04/14 2B 领域下的低代码探索之路](https://mp.weixin.qq.com/s/HAxrMHLT43dPH488RiEIdw) \ No newline at end of file diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md new file mode 100644 index 0000000000..9f348e4e65 --- /dev/null +++ b/docs/docs/video/index.md @@ -0,0 +1,13 @@ +# 官方视频 +- [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) + +# 社区视频 +- [阿里低代码引擎项目实战 (1)-引擎 demo 部署到 faas 服务](https://www.bilibili.com/video/BV1B44y1P7GM/) +- [【有翻车】阿里低代码引擎项目实战 (2)-保存页面到远端存储](https://www.bilibili.com/video/BV1AS4y1K7DP/) +- [阿里巴巴低代码引擎项目实战 (3)-自定义组件接入](https://www.bilibili.com/video/BV1dZ4y1m76S/) +- [阿里低代码引擎项目实战 (4)-自定义插件 - 页面管理](https://www.bilibili.com/video/BV17a411i73f/) +- [阿里低代码引擎项目实战 (4)-用户登录](https://www.bilibili.com/video/BV1Wu411e7EQ/) +- [【有翻车】阿里低代码引擎项目实战 (5)-表单回显](https://www.bilibili.com/video/BV1UY4y1v7D7/) +- [阿里低代码引擎项目实战 (6)-自定义插件 - 页面管理 - 后端](https://www.bilibili.com/video/BV1uZ4y1U7Ly/) +- [阿里低代码引擎项目实战 (6)-自定义插件 - 页面管理 - 前端](https://www.bilibili.com/video/BV1Yq4y1a74P/) +- [阿里低代码引擎项目实战 (7)-自定义插件 - 页面管理 (完结)](https://www.bilibili.com/video/BV13Y4y1e7EV/) From 70df59a2ce82f1d9fe59c8177ae1b9782465d83e Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 5 Sep 2023 15:41:14 +0800 Subject: [PATCH 260/469] style(outline-pane): fix outline-pane styles --- packages/editor-skeleton/src/layouts/right-area.tsx | 13 +++++++++++-- packages/editor-skeleton/src/layouts/workbench.less | 1 + packages/plugin-outline-pane/src/index.tsx | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/editor-skeleton/src/layouts/right-area.tsx b/packages/editor-skeleton/src/layouts/right-area.tsx index 4393eef55f..f00ae1461a 100644 --- a/packages/editor-skeleton/src/layouts/right-area.tsx +++ b/packages/editor-skeleton/src/layouts/right-area.tsx @@ -22,14 +22,23 @@ export default class RightArea extends Component<{ area: Area<any, Panel> }> { } } - @observer class Contents extends Component<{ area: Area<any, Panel> }> { render() { const { area } = this.props; + return ( <Fragment> - {area.container.items.map((item) => item.content)} + { + area.container.items + .slice() + .sort((a, b) => { + const index1 = a.config?.index || 0; + const index2 = b.config?.index || 0; + return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1); + }) + .map((item) => item.content) + } </Fragment> ); } diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 0a034822f4..38cbcfae09 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -431,6 +431,7 @@ body { background-color: var(--color-right-area-background, var(--color-pane-background, #fff)); left: 0; top: 0; + z-index: 1; } &.lc-area-visible { display: block; diff --git a/packages/plugin-outline-pane/src/index.tsx b/packages/plugin-outline-pane/src/index.tsx index addebbb402..822c503f27 100644 --- a/packages/plugin-outline-pane/src/index.tsx +++ b/packages/plugin-outline-pane/src/index.tsx @@ -92,6 +92,7 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { paneName: BackupPaneName, treeMaster, }, + index: 1, }); // 处理 master pane 和 backup pane 切换 From 34acd70659880409416add185926e874d179876d Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 5 Sep 2023 15:50:33 +0800 Subject: [PATCH 261/469] chore(docs): publish docs 1.1.8 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 012ef49d04..45c645bc09 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.7", + "version": "1.1.8", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 7ef62308d7a53c62feef8da92c1c0374f89b9412 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 6 Sep 2023 17:17:35 +0800 Subject: [PATCH 262/469] feat(common): update skeletonCabinSymbol exports --- packages/shell/src/api/common.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx index 3c2d2e5cce..605d2fb077 100644 --- a/packages/shell/src/api/common.tsx +++ b/packages/shell/src/api/common.tsx @@ -176,7 +176,7 @@ class SkeletonCabin implements IPublicApiCommonSkeletonCabin { constructor(skeleton: InnerSkeleton) { this[skeletonSymbol] = skeleton; this[skeletonCabinSymbol] = { - Workbench: this.Workbench, + Workbench: InnerWorkbench, createSettingFieldView: this.createSettingFieldView, PopupContext: InnerPopupContext, PopupPipe: InnerPopupPipe, From 4507e83d7da87a9a4e759caa237e4b59e9fdef6d Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 7 Sep 2023 10:06:50 +0800 Subject: [PATCH 263/469] feat(common): update designerCabinSymbol exports --- packages/shell/src/api/common.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx index 605d2fb077..a2e4d8c4fa 100644 --- a/packages/shell/src/api/common.tsx +++ b/packages/shell/src/api/common.tsx @@ -40,6 +40,7 @@ import { Designer as InnerDesigner, Node as InnerNode, LowCodePluginManager as InnerLowCodePluginManager, + DesignerView as InnerDesignerView, } from '@alilc/lowcode-designer'; import { Skeleton as InnerSkeleton, @@ -105,6 +106,7 @@ class DesignerCabin implements IPublicApiCommonDesignerCabin { Designer: InnerDesigner, Node: InnerNode, LowCodePluginManager: InnerLowCodePluginManager, + DesignerView: InnerDesignerView, }; } From 4e0b2fae5d2a59f068b1d5315f3fab6134e4d203 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 7 Sep 2023 10:09:40 +0800 Subject: [PATCH 264/469] feat(hotkey): when text is selected, allow the default copy and paste behavior --- packages/engine/src/inner-plugins/builtin-hotkey.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index 692773a756..1a1f3a9c44 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -277,6 +277,10 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { if (isFormEvent(e) || !doc) { return; } + const anchorValue = document.getSelection()?.anchorNode?.nodeValue; + if (anchorValue && typeof anchorValue === 'string') { + return; + } e.preventDefault(); let selected = doc.selection.getTopNodes(true); From 24cac48a3252c3cfe7e0c382e3a859c6b6f4194f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Fri, 8 Sep 2023 10:56:44 +0800 Subject: [PATCH 265/469] docs: update loop.md --- docs/docs/demoUsage/appendix/loop.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/docs/demoUsage/appendix/loop.md b/docs/docs/demoUsage/appendix/loop.md index 8b364ecf4f..46f39398af 100644 --- a/docs/docs/demoUsage/appendix/loop.md +++ b/docs/docs/demoUsage/appendix/loop.md @@ -15,3 +15,14 @@ sidebar_position: 0 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01XQfnYL1P4wxn01oXv_!!6000000001788-2-tps-3840-1896.png) this.index 是当前循环的索引值。 + +3.在事件绑定函数中使用 + +在事件绑定函数中使用扩展参数设置 +![image](https://github.com/alibaba/lowcode-engine/assets/11935995/7274506e-decd-497a-b07f-c95941a706b4) + +绑定之后在函数中使用 +![image](https://github.com/alibaba/lowcode-engine/assets/11935995/9d52ee5c-9959-4991-91be-9391e639bb7e) + +按钮点击效果 +![image](https://github.com/alibaba/lowcode-engine/assets/11935995/6ca590c9-1f5f-4d48-94a5-439130a22e92) From a560830db652713e29e209fb03a0ea6a6d7e9d40 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 8 Sep 2023 14:16:07 +0800 Subject: [PATCH 266/469] chore(docs): publish docs 1.1.9 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 45c645bc09..773f549cba 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.8", + "version": "1.1.9", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 6b14986e8f6cab6af5bc580c9f1a2a4fa925ef5f Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 11 Sep 2023 11:23:36 +0800 Subject: [PATCH 267/469] feat(config): add defaultSettingPanelProps config --- docs/docs/api/configOptions.md | 11 ++++++++++- .../src/inner-plugins/default-panel-registry.tsx | 4 +++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md index 4127576569..467655f68c 100644 --- a/docs/docs/api/configOptions.md +++ b/docs/docs/api/configOptions.md @@ -254,6 +254,16 @@ JSExpression 是否只支持使用 this 来访问上下文变量,假如需要 自定义 loading 组件 +### 插件 + +#### defaultSettingPanelProps + +内置设置面板插件的 panelProps + +#### defaultOutlinePaneProps + +内置大纲树面板插件的 panelProps + ### 其他 #### enableStrictPluginMode @@ -282,4 +292,3 @@ customPluginTransducer: async (originPlugin: IPublicTypePlugin, ctx: IPublicMode 大纲树插件面板默认 props - diff --git a/packages/engine/src/inner-plugins/default-panel-registry.tsx b/packages/engine/src/inner-plugins/default-panel-registry.tsx index d7549d764b..b5f538d44c 100644 --- a/packages/engine/src/inner-plugins/default-panel-registry.tsx +++ b/packages/engine/src/inner-plugins/default-panel-registry.tsx @@ -28,6 +28,9 @@ export const defaultPanelRegistry = (editor: any) => { props: { ignoreRoot: true, }, + panelProps: { + ...(config.get('defaultSettingPanelProps') || {}), + }, }); } }, @@ -39,5 +42,4 @@ export const defaultPanelRegistry = (editor: any) => { return fun; }; - export default defaultPanelRegistry; From 1072ff36fb6be0743ae199e9a48eeaa38bd8e0d1 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 13 Sep 2023 11:02:15 +0800 Subject: [PATCH 268/469] feat(workspace): add workspace.skeleton api --- docs/docs/api/workspace.md | 10 ++++++++++ packages/editor-skeleton/src/skeleton.ts | 2 +- packages/shell/src/api/workspace.ts | 5 +++++ packages/workspace/src/workspace.ts | 3 +++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/docs/api/workspace.md b/docs/docs/api/workspace.md index 3c13b00aa0..9911dc93ad 100644 --- a/docs/docs/api/workspace.md +++ b/docs/docs/api/workspace.md @@ -37,6 +37,16 @@ get plugins(): IPublicApiPlugins 关联模型 [IPublicApiPlugins](./plugins) +### skeleton + +应用级别的面板管理 + +```typescript +get skeleton(): IPublicApiSkeleton +``` + +关联模型 [IPublicApiSkeleton](./skeleton) + ### windows 当前设计器的编辑窗口 diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 8836434049..89bffc4cfe 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -108,7 +108,7 @@ export interface ISkeleton extends Omit<IPublicApiSkeleton, add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined; } -export class Skeleton { +export class Skeleton implements ISkeleton { private panels = new Map<string, Panel>(); private containers = new Map<string, WidgetContainer<any>>(); diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index 8737e37bd7..fd3e82fa90 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -3,6 +3,7 @@ import { IWorkspace } from '@alilc/lowcode-workspace'; import { resourceSymbol, workspaceSymbol } from '../symbols'; import { Resource as ShellResource, Window as ShellWindow } from '../model'; import { Plugins } from './plugins'; +import { Skeleton } from './skeleton'; export class Workspace implements IPublicApiWorkspace { readonly [workspaceSymbol]: IWorkspace; @@ -92,6 +93,10 @@ export class Workspace implements IPublicApiWorkspace { return new Plugins(this[workspaceSymbol].plugins, true); } + get skeleton() { + return new Skeleton(this[workspaceSymbol].skeleton, 'workspace', true); + } + get windows() { return this[workspaceSymbol].windows.map((d) => new ShellWindow(d)); } diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 22eb9ede2b..59b9e866b2 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -6,6 +6,7 @@ import { EditorWindow, WINDOW_STATE } from './window'; import type { IEditorWindow } from './window'; import { IResource, Resource } from './resource'; import { IResourceType, ResourceType } from './resource-type'; +import { ISkeleton } from '@alilc/lowcode-editor-skeleton'; enum EVENT { CHANGE_WINDOW = 'change_window', @@ -33,6 +34,8 @@ export interface IWorkspace extends Omit<IPublicApiWorkspace< plugins: ILowCodePluginManager; + skeleton: ISkeleton; + resourceTypeMap: Map<string, ResourceType>; getResourceList(): IResource[]; From cf2f5c29bce5917e56e774843266f1b5801fd1c3 Mon Sep 17 00:00:00 2001 From: Rainke <woshihepeng520@163.com> Date: Wed, 13 Sep 2023 21:32:38 -0500 Subject: [PATCH 269/469] fix: do not parse props when condition is false or loop data is empty (#2477) * fix: do not parse children props when condition is falsy * fix: skip parsing children when loop data is empty --- packages/renderer-core/src/renderer/base.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 89dc143d5f..216735edcf 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -545,6 +545,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { if (schema.loop != null) { const loop = this.__parseData(schema.loop, scope); + if (Array.isArray(loop) && loop.length === 0) return null; const useLoop = isUseLoop(loop, this.__designModeIsDesign); if (useLoop) { return this.__createLoopVirtualDom( @@ -649,7 +650,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { props.key = props.__id; } - let child = this.__getSchemaChildrenVirtualDom(schema, scope, Comp); + let child = this.__getSchemaChildrenVirtualDom(schema, scope, Comp, condition); const renderComp = (innerProps: any) => engine.createElement(Comp, innerProps, child); // 设计模式下的特殊处理 if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) { @@ -709,8 +710,8 @@ export default function baseRendererFactory(): IBaseRenderComponent { return []; } - __getSchemaChildrenVirtualDom = (schema: IPublicTypeNodeSchema | undefined, scope: any, Comp: any) => { - let children = getSchemaChildren(schema); + __getSchemaChildrenVirtualDom = (schema: IPublicTypeNodeSchema | undefined, scope: any, Comp: any, condition = true) => { + let children = condition ? getSchemaChildren(schema) : null; // @todo 补完这里的 Element 定义 @承虎 let result: any = []; From cfc22f7ecc666ae8258013634c3aa17958299b90 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 18 Sep 2023 15:48:32 +0800 Subject: [PATCH 270/469] feat: add simulatorRender shell --- docs/docs/api/model/simulatorRender.md | 38 +++++++++++++++++++ docs/docs/api/simulatorHost.md | 4 +- packages/engine/src/modules/symbols.ts | 2 + packages/shell/src/api/simulator-host.ts | 13 +++++-- packages/shell/src/model/simulator-render.ts | 23 +++++++++++ packages/shell/src/symbols.ts | 1 + .../types/src/shell/api/simulator-host.ts | 6 +-- packages/types/src/shell/model/index.ts | 1 + .../types/src/shell/model/simulator-render.ts | 14 +++++++ 9 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 docs/docs/api/model/simulatorRender.md create mode 100644 packages/shell/src/model/simulator-render.ts create mode 100644 packages/types/src/shell/model/simulator-render.ts diff --git a/docs/docs/api/model/simulatorRender.md b/docs/docs/api/model/simulatorRender.md new file mode 100644 index 0000000000..f5bacec493 --- /dev/null +++ b/docs/docs/api/model/simulatorRender.md @@ -0,0 +1,38 @@ +--- +title: SimulatorRender +sidebar_position: 6 +--- +> **@types** [IPublicModelSimulatorRender](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/simulator-render.ts)<br/> +> **@since** v1.0.0 + +## 基本介绍 + +画布节点选中模型 + +## 属性 +### components + +画布组件列表 + +```typescript +/** + * 画布组件列表 + */ +components: { + [key: string]: any; +} +``` + +## 方法 + +### rerender + +触发画布重新渲染 + +```typescript +/** + * 触发画布重新渲染 + */ +rerender: () => void; +``` + diff --git a/docs/docs/api/simulatorHost.md b/docs/docs/api/simulatorHost.md index b30a614992..ee8f038fc3 100644 --- a/docs/docs/api/simulatorHost.md +++ b/docs/docs/api/simulatorHost.md @@ -50,11 +50,11 @@ get(key: string): any; ``` ### rerender -刷新渲染画布 +触发组件构建,并刷新渲染画布 ```typescript /** - * 刷新渲染画布 + * 触发组件构建,并刷新渲染画布 * make simulator render again */ rerender(): void; diff --git a/packages/engine/src/modules/symbols.ts b/packages/engine/src/modules/symbols.ts index 435e8cbc2c..55c70e5dcb 100644 --- a/packages/engine/src/modules/symbols.ts +++ b/packages/engine/src/modules/symbols.ts @@ -14,6 +14,7 @@ import { skeletonItemSymbol, editorCabinSymbol, skeletonCabinSymbol, + simulatorRenderSymbol, } from '@alilc/lowcode-shell'; export default { @@ -32,4 +33,5 @@ export default { propSymbol, simulatorHostSymbol, skeletonItemSymbol, + simulatorRenderSymbol, }; diff --git a/packages/shell/src/api/simulator-host.ts b/packages/shell/src/api/simulator-host.ts index 3ed7448905..663ba0c668 100644 --- a/packages/shell/src/api/simulator-host.ts +++ b/packages/shell/src/api/simulator-host.ts @@ -2,7 +2,8 @@ import { BuiltinSimulatorHost, } from '@alilc/lowcode-designer'; import { simulatorHostSymbol, nodeSymbol } from '../symbols'; -import { IPublicApiSimulatorHost, IPublicModelNode } from '@alilc/lowcode-types'; +import { IPublicApiSimulatorHost, IPublicModelNode, IPublicModelSimulatorRender } from '@alilc/lowcode-types'; +import { SimulatorRender } from '../model/simulator-render'; export class SimulatorHost implements IPublicApiSimulatorHost { private readonly [simulatorHostSymbol]: BuiltinSimulatorHost; @@ -30,8 +31,12 @@ export class SimulatorHost implements IPublicApiSimulatorHost { return this[simulatorHostSymbol].contentDocument; } - get renderer(): any { - return this[simulatorHostSymbol].renderer; + get renderer(): IPublicModelSimulatorRender | undefined { + if (this[simulatorHostSymbol].renderer) { + return SimulatorRender.create(this[simulatorHostSymbol].renderer); + } + + return undefined; } /** @@ -61,7 +66,7 @@ export class SimulatorHost implements IPublicApiSimulatorHost { } /** - * 刷新渲染画布 + * 触发组件构建,并刷新渲染画布 */ rerender(): void { this[simulatorHostSymbol].rerender(); diff --git a/packages/shell/src/model/simulator-render.ts b/packages/shell/src/model/simulator-render.ts new file mode 100644 index 0000000000..f6ae47996c --- /dev/null +++ b/packages/shell/src/model/simulator-render.ts @@ -0,0 +1,23 @@ +import { IPublicModelSimulatorRender } from '@alilc/lowcode-types'; +import { simulatorRenderSymbol } from '../symbols'; +import { BuiltinSimulatorRenderer } from '@alilc/lowcode-designer'; + +export class SimulatorRender implements IPublicModelSimulatorRender { + private readonly [simulatorRenderSymbol]: BuiltinSimulatorRenderer; + + constructor(simulatorRender: BuiltinSimulatorRenderer) { + this[simulatorRenderSymbol] = simulatorRender; + } + + static create(simulatorRender: BuiltinSimulatorRenderer): IPublicModelSimulatorRender { + return new SimulatorRender(simulatorRender); + } + + get components() { + return this[simulatorRenderSymbol].components; + } + + rerender() { + return this[simulatorRenderSymbol].rerender(); + } +} \ No newline at end of file diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index cc1be48560..8e2962a24f 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -21,6 +21,7 @@ export const dragonSymbol = Symbol('dragon'); export const componentMetaSymbol = Symbol('componentMeta'); export const dropLocationSymbol = Symbol('dropLocation'); export const simulatorHostSymbol = Symbol('simulatorHost'); +export const simulatorRenderSymbol = Symbol('simulatorRender'); export const dragObjectSymbol = Symbol('dragObject'); export const locateEventSymbol = Symbol('locateEvent'); export const designerCabinSymbol = Symbol('designerCabin'); diff --git a/packages/types/src/shell/api/simulator-host.ts b/packages/types/src/shell/api/simulator-host.ts index 1c0f5dec35..9137067951 100644 --- a/packages/types/src/shell/api/simulator-host.ts +++ b/packages/types/src/shell/api/simulator-host.ts @@ -1,7 +1,7 @@ -import { IPublicModelNode } from '../model'; - +import { IPublicModelNode, IPublicModelSimulatorRender } from '../model'; export interface IPublicApiSimulatorHost { + /** * 获取 contentWindow * @experimental unstable api, pay extra caution when trying to use it @@ -17,7 +17,7 @@ export interface IPublicApiSimulatorHost { /** * @experimental unstable api, pay extra caution when trying to use it */ - get renderer(): any; + get renderer(): IPublicModelSimulatorRender | undefined; /** * 设置若干用于画布渲染的变量,比如画布大小、locale 等。 diff --git a/packages/types/src/shell/model/index.ts b/packages/types/src/shell/model/index.ts index 1924f11215..ffe6347ac2 100644 --- a/packages/types/src/shell/model/index.ts +++ b/packages/types/src/shell/model/index.ts @@ -32,3 +32,4 @@ export * from './clipboard'; export * from './setting-field'; export * from './editor-view'; export * from './skeleton-item'; +export * from './simulator-render'; diff --git a/packages/types/src/shell/model/simulator-render.ts b/packages/types/src/shell/model/simulator-render.ts new file mode 100644 index 0000000000..8cf3a03c55 --- /dev/null +++ b/packages/types/src/shell/model/simulator-render.ts @@ -0,0 +1,14 @@ +export interface IPublicModelSimulatorRender { + + /** + * 画布组件列表 + */ + components: { + [key: string]: any; + }; + + /** + * 触发画布重新渲染 + */ + rerender: () => void; +} From 3e75af171d75b44c213242f6f9d0bda85c4e4cd0 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 19 Sep 2023 09:33:40 +0800 Subject: [PATCH 271/469] chore(docs): publish docs 1.1.10 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 773f549cba..3950b35c9c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.9", + "version": "1.1.10", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 3658bac27feb8b9f7b0c71a579ad9c4b6fb52214 Mon Sep 17 00:00:00 2001 From: zsynuting <zsynuting@163.com> Date: Mon, 18 Sep 2023 16:27:21 +0800 Subject: [PATCH 272/469] remove unnecessary dep --- packages/designer/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/designer/package.json b/packages/designer/package.json index 274d266fc0..1081aef8ff 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -15,7 +15,6 @@ }, "license": "MIT", "dependencies": { - "@alilc/build-plugin-lce": "^0.0.4-beta.2", "@alilc/lowcode-editor-core": "1.1.10", "@alilc/lowcode-types": "1.1.10", "@alilc/lowcode-utils": "1.1.10", From 7a40aff277bba2969242a2d5780dd6e032714cd7 Mon Sep 17 00:00:00 2001 From: iChengbo <chengbo_x@163.com> Date: Mon, 25 Sep 2023 15:02:37 +0800 Subject: [PATCH 273/469] fix: make the color of the logger more highlighted --- packages/utils/src/logger.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/logger.ts b/packages/utils/src/logger.ts index 032b54bdc4..58c7d23b19 100644 --- a/packages/utils/src/logger.ts +++ b/packages/utils/src/logger.ts @@ -52,11 +52,11 @@ const bizNameColors = [ '#2e8b57', ]; const bodyColors: Record<string, string> = { - debug: '#666666', - log: '#bbbbbb', - info: '#ffffff', - warn: '#bbbbbb', - error: '#bbbbbb', + debug: '#fadb14', + log: '#8c8c8c', + info: '#52c41a', + warn: '#fa8c16', + error: '#ff4d4f', }; const levelMarks: Record<string, string> = { debug: 'debug', From 4728484e7e449b8af4d66b414bdb474608bc95e0 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 25 Sep 2023 18:09:57 +0800 Subject: [PATCH 274/469] feat: suport more locale config --- packages/react-simulator-renderer/src/locale/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-simulator-renderer/src/locale/index.ts b/packages/react-simulator-renderer/src/locale/index.ts index e4b39a347c..5f4ef01505 100644 --- a/packages/react-simulator-renderer/src/locale/index.ts +++ b/packages/react-simulator-renderer/src/locale/index.ts @@ -9,10 +9,10 @@ const instance: Record<string, Record<string, string>> = { export function createIntl(locale: string = 'zh-CN') { const intl = (id: string) => { - return instance[locale][id]; + return instance[locale]?.[id] || id; }; - const intlNode = (id: string) => createElement('span', instance[locale][id]); + const intlNode = (id: string) => createElement('span', instance[locale]?.[id] || id); return { intl, From 5c139181b6b0e1a542e0babc9cb63e7938306079 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 26 Sep 2023 17:21:01 +0800 Subject: [PATCH 275/469] fix: fix workspace openEditorWindow API bugs --- packages/workspace/src/workspace.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 59b9e866b2..9f1abaa0fb 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -130,7 +130,9 @@ export class Workspace implements IWorkspace { } const windowInfo = this.windowQueue.shift(); - if (windowInfo) { + if (windowInfo instanceof Resource) { + this.openEditorWindowByResource(windowInfo); + } else if (windowInfo) { this.openEditorWindow(windowInfo.name, windowInfo.title, windowInfo.options, windowInfo.viewName); } } @@ -251,7 +253,7 @@ export class Workspace implements IWorkspace { } async openEditorWindowByResource(resource: IResource, sleep: boolean = false): Promise<void> { - if (this.window && !this.window?.initReady && !sleep) { + if (this.window && !this.window.sleep && !this.window?.initReady && !sleep) { this.windowQueue.push(resource); return; } @@ -292,7 +294,7 @@ export class Workspace implements IWorkspace { } async openEditorWindow(name: string, title: string, options: Object, viewName?: string, sleep?: boolean) { - if (this.window && !this.window?.initReady && !sleep) { + if (this.window && !this.window.sleep && !this.window?.initReady && !sleep) { this.windowQueue.push({ name, title, options, viewName, }); @@ -304,7 +306,7 @@ export class Workspace implements IWorkspace { return; } this.window?.updateState(WINDOW_STATE.inactive); - const filterWindows = this.windows.filter(d => (d.resource?.name === name && d.resource.title == title)); + const filterWindows = this.windows.filter(d => (d.resource?.name === name && d.resource.title == title) || (d.resource.id == title)); if (filterWindows && filterWindows.length) { this.window = filterWindows[0]; if (!sleep && this.window.sleep) { @@ -320,6 +322,7 @@ export class Workspace implements IWorkspace { resourceName: name, title, options, + id: title?.toString(), }, resourceType, this); const window = new EditorWindow(resource, this, { title, From e3e5123b3173cd0999ace99278e904391baa3aa4 Mon Sep 17 00:00:00 2001 From: Rainke <woshihepeng520@163.com> Date: Mon, 25 Sep 2023 21:27:23 -0500 Subject: [PATCH 276/469] fix: remove `class` prop --- .../src/components/settings/settings-primary-pane.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx index 800719588f..a68647ed0d 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -64,7 +64,6 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, { <div className="lc-settings-navigator"> {createIcon(settings.componentMeta?.icon, { className: 'lc-settings-navigator-icon', - class: 'lc-settings-navigator-icon', })} <Title title={settings.componentMeta!.title} /> <span> x {settings.nodes.length}</span> From f50410ae7a51b6c4d7ad18f4146c462beb2cfb51 Mon Sep 17 00:00:00 2001 From: iChengbo <chengbo_x@163.com> Date: Thu, 5 Oct 2023 12:31:45 +0800 Subject: [PATCH 277/469] fix: some spell error --- .../designer/src/builtin-simulator/host.ts | 10 +++++----- packages/designer/src/designer/designer.ts | 4 ++-- packages/designer/src/designer/scroller.ts | 18 +++++++++--------- packages/utils/src/app-helper.ts | 12 ++++++------ packages/utils/src/asset.ts | 8 ++++---- packages/utils/src/logger.ts | 4 ++-- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 5e6fc06a62..eb855e4498 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -1069,15 +1069,15 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp return null; } - const nodeIntance = this.getClosestNodeInstance(target); - if (!nodeIntance) { + const nodeInstance = this.getClosestNodeInstance(target); + if (!nodeInstance) { return null; } - const { docId } = nodeIntance; + const { docId } = nodeInstance; const doc = this.project.getDocument(docId)!; - const node = doc.getNode(nodeIntance.nodeId); + const node = doc.getNode(nodeInstance.nodeId); return { - ...nodeIntance, + ...nodeInstance, node, }; } diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 784ebf57bc..d7e17e84ca 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -18,7 +18,7 @@ import { IPublicEnumTransformStage, IPublicModelLocateEvent, } from '@alilc/lowcode-types'; -import { megreAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils'; +import { mergeAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils'; import { IProject, Project } from '../project'; import { Node, DocumentModel, insertChildren, INode } from '../document'; import { ComponentMeta, IComponentMeta } from '../component-meta'; @@ -458,7 +458,7 @@ export class Designer implements IDesigner { if (components) { // 合并 assets let assets = this.editor.get('assets') || {}; - let newAssets = megreAssets(assets, incrementalAssets); + let newAssets = mergeAssets(assets, incrementalAssets); // 对于 assets 存在需要二次网络下载的过程,必须 await 等待结束之后,再进行事件触发 await this.editor.set('assets', newAssets); } diff --git a/packages/designer/src/designer/scroller.ts b/packages/designer/src/designer/scroller.ts index 67efe7f444..7391c39fab 100644 --- a/packages/designer/src/designer/scroller.ts +++ b/packages/designer/src/designer/scroller.ts @@ -46,7 +46,7 @@ function easing(n: number) { return Math.sin((n * Math.PI) / 2); } -const SCROLL_ACCURCY = 30; +const SCROLL_ACCURACY = 30; export interface IScroller extends IPublicModelScroller { @@ -142,15 +142,15 @@ export class Scroller implements IScroller { let sy = scrollTarget.top; let ax = 0; let ay = 0; - if (y < bounds.top + SCROLL_ACCURCY) { - ay = -Math.min(Math.max(bounds.top + SCROLL_ACCURCY - y, 10), 50) / scale; - } else if (y > bounds.bottom - SCROLL_ACCURCY) { - ay = Math.min(Math.max(y + SCROLL_ACCURCY - bounds.bottom, 10), 50) / scale; + if (y < bounds.top + SCROLL_ACCURACY) { + ay = -Math.min(Math.max(bounds.top + SCROLL_ACCURACY - y, 10), 50) / scale; + } else if (y > bounds.bottom - SCROLL_ACCURACY) { + ay = Math.min(Math.max(y + SCROLL_ACCURACY - bounds.bottom, 10), 50) / scale; } - if (x < bounds.left + SCROLL_ACCURCY) { - ax = -Math.min(Math.max(bounds.top + SCROLL_ACCURCY - y, 10), 50) / scale; - } else if (x > bounds.right - SCROLL_ACCURCY) { - ax = Math.min(Math.max(x + SCROLL_ACCURCY - bounds.right, 10), 50) / scale; + if (x < bounds.left + SCROLL_ACCURACY) { + ax = -Math.min(Math.max(bounds.top + SCROLL_ACCURACY - y, 10), 50) / scale; + } else if (x > bounds.right - SCROLL_ACCURACY) { + ax = Math.min(Math.max(x + SCROLL_ACCURACY - bounds.right, 10), 50) / scale; } if (!ax && !ay) { diff --git a/packages/utils/src/app-helper.ts b/packages/utils/src/app-helper.ts index d5eb2072b3..86b535c592 100644 --- a/packages/utils/src/app-helper.ts +++ b/packages/utils/src/app-helper.ts @@ -34,18 +34,18 @@ export class AppHelper extends EventEmitter { } } - batchOn(events: Array<string | symbol>, lisenter: (...args: any[]) => void) { + batchOn(events: Array<string | symbol>, listener: (...args: any[]) => void) { if (!Array.isArray(events)) return; - events.forEach((event) => this.on(event, lisenter)); + events.forEach((event) => this.on(event, listener)); } - batchOnce(events: Array<string | symbol>, lisenter: (...args: any[]) => void) { + batchOnce(events: Array<string | symbol>, listener: (...args: any[]) => void) { if (!Array.isArray(events)) return; - events.forEach((event) => this.once(event, lisenter)); + events.forEach((event) => this.once(event, listener)); } - batchOff(events: Array<string | symbol>, lisenter: (...args: any[]) => void) { + batchOff(events: Array<string | symbol>, listener: (...args: any[]) => void) { if (!Array.isArray(events)) return; - events.forEach((event) => this.off(event, lisenter)); + events.forEach((event) => this.off(event, listener)); } } diff --git a/packages/utils/src/asset.ts b/packages/utils/src/asset.ts index 4e5a360b86..ad05221248 100644 --- a/packages/utils/src/asset.ts +++ b/packages/utils/src/asset.ts @@ -50,7 +50,7 @@ export function assetItem(type: AssetType, content?: string | null, level?: Asse }; } -export function megreAssets(assets: IPublicTypeAssetsJson, incrementalAssets: IPublicTypeAssetsJson): IPublicTypeAssetsJson { +export function mergeAssets(assets: IPublicTypeAssetsJson, incrementalAssets: IPublicTypeAssetsJson): IPublicTypeAssetsJson { if (incrementalAssets.packages) { assets.packages = [...(assets.packages || []), ...incrementalAssets.packages]; } @@ -59,13 +59,13 @@ export function megreAssets(assets: IPublicTypeAssetsJson, incrementalAssets: IP assets.components = [...(assets.components || []), ...incrementalAssets.components]; } - megreAssetsComponentList(assets, incrementalAssets, 'componentList'); - megreAssetsComponentList(assets, incrementalAssets, 'bizComponentList'); + mergeAssetsComponentList(assets, incrementalAssets, 'componentList'); + mergeAssetsComponentList(assets, incrementalAssets, 'bizComponentList'); return assets; } -function megreAssetsComponentList(assets: IPublicTypeAssetsJson, incrementalAssets: IPublicTypeAssetsJson, listName: keyof IPublicTypeAssetsJson): void { +function mergeAssetsComponentList(assets: IPublicTypeAssetsJson, incrementalAssets: IPublicTypeAssetsJson, listName: keyof IPublicTypeAssetsJson): void { if (incrementalAssets[listName]) { if (assets[listName]) { // 根据title进行合并 diff --git a/packages/utils/src/logger.ts b/packages/utils/src/logger.ts index 58c7d23b19..4c8f375ecd 100644 --- a/packages/utils/src/logger.ts +++ b/packages/utils/src/logger.ts @@ -65,7 +65,7 @@ const levelMarks: Record<string, string> = { warn: 'warn', error: 'error', }; -const outputFuntion: Record<string, any> = { +const outputFunction: Record<string, any> = { debug: console.log, log: console.log, info: console.log, @@ -88,7 +88,7 @@ const shouldOutput = ( const output = (logLevel: string, bizName: string) => { return (...args: any[]) => { - return outputFuntion[logLevel].apply(console, getLogArgs(args, bizName, logLevel)); + return outputFunction[logLevel].apply(console, getLogArgs(args, bizName, logLevel)); }; }; From fc31145f89d6ca1b1377db044cbed0ebe436d268 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Sat, 7 Oct 2023 17:00:45 +0800 Subject: [PATCH 278/469] style: add style varibles and update some styles --- .../builtin-simulator/bem-tools/borders.less | 57 ++------- .../bem-tools/insertion.less | 2 +- .../designer/src/builtin-simulator/host.less | 6 +- .../node-selector/index.less | 2 +- .../src/designer/drag-ghost/ghost.less | 4 +- packages/designer/src/less-variables.less | 8 +- .../editor-core/src/widgets/tip/style.less | 12 +- .../editor-core/src/widgets/title/title.less | 2 +- .../src/components/field/fields.tsx | 34 ----- .../src/components/field/index.less | 117 +----------------- .../src/components/settings/style.less | 8 -- .../editor-skeleton/src/layouts/theme.less | 8 ++ .../src/layouts/workbench.less | 48 ++----- .../editor-skeleton/src/less-variables.less | 8 +- .../plugin-outline-pane/src/views/style.less | 48 +++---- packages/utils/src/create-icon.tsx | 6 +- packages/workspace/src/less-variables.less | 8 +- 17 files changed, 81 insertions(+), 297 deletions(-) diff --git a/packages/designer/src/builtin-simulator/bem-tools/borders.less b/packages/designer/src/builtin-simulator/bem-tools/borders.less index 2cdc9fb403..43fba6a2b8 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/borders.less +++ b/packages/designer/src/builtin-simulator/bem-tools/borders.less @@ -17,7 +17,7 @@ } & > &-status { margin-left: 5px; - color: #3c3c3c; + color: var(--color-text, #3c3c3c); transform: translateY(-100%); font-weight: lighter; } @@ -46,7 +46,7 @@ opacity: 1; max-height: 100%; overflow: hidden; - color: white; + color: var(--color-icon-reverse, white); &:hover { background: var(--color-brand-light, #006cff); } @@ -56,8 +56,8 @@ display: inline-block; width: 8px; height: 8px; - border: 1px solid #197aff; - background: #fff; + border: 1px solid var(--color-brand, #197aff); + background: var(--color-block-background-normal, #fff); pointer-events: auto; z-index: 2; } @@ -73,11 +73,9 @@ &:after { content: ""; display: block; - border: 1px solid #197aff; - background: #fff; - // background: #738397; + border: 1px solid var(--color-brand, #197aff); + background: var(--color-block-background-normal, #fff); border-radius: 2px; - // animation: flashing 1.5s infinite linear; } &.e, @@ -85,7 +83,6 @@ cursor: ew-resize; &:after { width: 4px; - // height: calc(100% - 20px); min-height: 50%; } } @@ -94,62 +91,24 @@ &.s { cursor: ns-resize; &:after { - // width: calc(100% - 20px); min-width: 50%; height: 4px; } } } - // &&-hovering { &&-detecting { z-index: 1; border-style: dashed; - background: rgba(0,121,242,.04); - - &.x-loop { - border-color: rgba(138, 93, 226, 0.8); - background: rgba(138, 93, 226, 0.04); - - >.@{scope}-title { - color: rgba(138, 93, 226, 1.0); - } - } - - &.x-condition { - border-color: rgba(255, 99, 8, 0.8); - background: rgba(255, 99, 8, 0.04); - >.@{scope}-title { - color: rgb(255, 99, 8); - } - } + background: var(--color-block-background-light, rgba(0,121,242,.04)); } &&-selecting { z-index: 2; border-width: 2px; - &.x-loop { - border-color: rgba(147, 112, 219, 1.0); - background: rgba(147, 112, 219, 0.04); - - >@{scope}-title { - color: rgba(147, 112, 219, 1.0); - } - &.highlight { - background: transparent; - } - } - - &.x-condition { - border-color: rgb(255, 99, 8); - >@{scope}-title { - color: rgb(255, 99, 8); - } - } - &.dragging { - background: rgba(182, 178, 178, 0.8); + background: var(--color-layer-mask-background, rgba(182, 178, 178, 0.8)); border: none; } } diff --git a/packages/designer/src/builtin-simulator/bem-tools/insertion.less b/packages/designer/src/builtin-simulator/bem-tools/insertion.less index 770d3893ca..c51e73106f 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/insertion.less +++ b/packages/designer/src/builtin-simulator/bem-tools/insertion.less @@ -23,6 +23,6 @@ } &.invalid { - background-color: red; + background-color: var(--color-function-error, red); } } diff --git a/packages/designer/src/builtin-simulator/host.less b/packages/designer/src/builtin-simulator/host.less index 5e230c4007..7130c42972 100644 --- a/packages/designer/src/builtin-simulator/host.less +++ b/packages/designer/src/builtin-simulator/host.less @@ -31,7 +31,7 @@ max-height: calc(100% - 32px); max-width: calc(100% - 32px); transform: translateX(-50%); - box-shadow: 0 2px 10px 0 rgba(31,56,88,.15); + box-shadow: 0 2px 10px 0 var(--color-block-background-shallow, rgba(31,56,88,.15)); } &-device-iphonex { // 增加默认的小程序的壳 @@ -44,7 +44,7 @@ background: url(https://img.alicdn.com/tfs/TB1b4DHilFR4u4jSZFPXXanzFXa-750-1574.png) no-repeat top; background-size: 375px 812px; border-radius: 44px; - box-shadow: rgba(0, 0, 0, 0.1) 0 36px 42px; + box-shadow: var(--color-block-background-shallow, rgba(0, 0, 0, 0.1)) 0 36px 42px; .@{scope}-canvas-viewport { width: auto; top: 50px; @@ -78,7 +78,7 @@ bottom: 16px; left: 16px; width: auto; - box-shadow: 0 1px 4px 0 rgba(31, 50, 88, 0.125); + box-shadow: 0 1px 4px 0 var(--color-block-background-shallow, rgba(31, 50, 88, 0.125)); } &-content { diff --git a/packages/designer/src/builtin-simulator/node-selector/index.less b/packages/designer/src/builtin-simulator/node-selector/index.less index c0335734e0..01552a2510 100644 --- a/packages/designer/src/builtin-simulator/node-selector/index.less +++ b/packages/designer/src/builtin-simulator/node-selector/index.less @@ -48,7 +48,7 @@ margin-top: 2px; &-content { padding-left: 6px; - background: #78869a; + background: var(--color-layer-tooltip-background, #78869a); display: inline-flex; border-radius: 3px; align-items: center; diff --git a/packages/designer/src/designer/drag-ghost/ghost.less b/packages/designer/src/designer/drag-ghost/ghost.less index 7ab61b41d6..1d9c03552f 100644 --- a/packages/designer/src/designer/drag-ghost/ghost.less +++ b/packages/designer/src/designer/drag-ghost/ghost.less @@ -7,8 +7,8 @@ flex-direction: column; align-items: center; pointer-events: none; - background-color: rgba(0, 0, 0, 0.4); - box-shadow: 0 0 6px grey; + background-color: var(--color-block-background-deep-dark, rgba(0, 0, 0, 0.4)); + box-shadow: 0 0 6px var(--color-block-background-shallow, grey); transform: translate(-10%, -50%); .lc-ghost { .lc-ghost-title { diff --git a/packages/designer/src/less-variables.less b/packages/designer/src/less-variables.less index c44fc196e2..017e432ce6 100644 --- a/packages/designer/src/less-variables.less +++ b/packages/designer/src/less-variables.less @@ -99,19 +99,19 @@ @brand-link-hover: #2e76a6; // F1-1-7 A10 -@brand-danger-alpha-7: rgba(240, 70, 49, 0.9); +@brand-danger-alpha-7: rgba(240, 70, 49, 0.1); // F1-1-8 A6 @brand-danger-alpha-8: rgba(240, 70, 49, 0.8); // F2-1-2 A80 @brand-warning-alpha-2: rgba(250, 189, 14, 0.8); // F2-1-7 A10 -@brand-warning-alpha-7: rgba(250, 189, 14, 0.9); +@brand-warning-alpha-7: rgba(250, 189, 14, 0.1); // F3-1-2 A80 @brand-success-alpha-2: rgba(102, 188, 92, 0.8); // F3-1-7 A10 -@brand-success-alpha-7: rgba(102, 188, 92, 0.9); +@brand-success-alpha-7: rgba(102, 188, 92, 0.1); // F4-1-7 A10 -@brand-link-alpha-7: rgba(102, 188, 92, 0.9); +@brand-link-alpha-7: rgba(102, 188, 92, 0.1); // 文本色 @text-primary-color: @dark-alpha-3; diff --git a/packages/editor-core/src/widgets/tip/style.less b/packages/editor-core/src/widgets/tip/style.less index 21b60b9b5d..aa5327f3d4 100644 --- a/packages/editor-core/src/widgets/tip/style.less +++ b/packages/editor-core/src/widgets/tip/style.less @@ -156,7 +156,7 @@ opacity: 0; border-radius: 3px; padding: 6px 8px; - text-shadow: 0 -1px rgba(0, 0, 0, 0.3); + text-shadow: 0 -1px var(--color-field-label, rgba(0, 0, 0, 0.3)); font-size: var(--font-size-text); line-height: 14px; max-width: 200px; @@ -178,19 +178,19 @@ height: 8px; &:after { border: 6px solid transparent; - border-top-color: rgba(0, 0, 0, 0.7); + border-top-color: var(--color-layer-tooltip-background, rgba(0, 0, 0, 0.7)); } } &.lc-theme-black { - background: rgba(0, 0, 0, 0.7); + background: var(--color-icon-pane, rgba(0, 0, 0, 0.7)); .lc-arrow:after { - border-top-color: rgba(0, 0, 0, 0.7); + border-top-color: var(--color-layer-tooltip-background, rgba(0, 0, 0, 0.7)); } } &.lc-theme-green { - background: #57a672; + background: var(--color-function-success-dark, #57a672); .lc-arrow:after { - border-top-color: #57a672; + border-top-color: var(--color-function-success-dark, #57a672); } } &.lc-visible { diff --git a/packages/editor-core/src/widgets/title/title.less b/packages/editor-core/src/widgets/title/title.less index e9d0765522..f6747ef474 100644 --- a/packages/editor-core/src/widgets/title/title.less +++ b/packages/editor-core/src/widgets/title/title.less @@ -21,7 +21,7 @@ cursor: help; text-decoration-line: underline; text-decoration-style: dashed; - text-decoration-color: rgba(31, 56, 88, .3); + text-decoration-color: var(--color-text-light, rgba(31, 56, 88, .3)); } line-height: initial !important; word-break: break-all; diff --git a/packages/editor-skeleton/src/components/field/fields.tsx b/packages/editor-skeleton/src/components/field/fields.tsx index b773995e3a..21ae93eb25 100644 --- a/packages/editor-skeleton/src/components/field/fields.tsx +++ b/packages/editor-skeleton/src/components/field/fields.tsx @@ -203,40 +203,6 @@ export class Field extends Component<FieldProps> { */ function createValueState(/* valueState?: number, onClear?: (e: React.MouseEvent) => void */) { return null; - - /* - let tip: any = null; - let className = 'lc-valuestate'; - let icon: any = null; - if (valueState) { - if (valueState < 0) { - // multiple value 橘黄色点: tip:多种值,点击清除 - tip = intlNode('Multiple Value, Click to Clear'); - className += ' valuestate-multiple'; - icon = <IconClear size={6} />; - } else if (valueState === 10) { - // isset orangered tip: 必填项 - tip = intlNode('Required'); - className += ' valuestate-required'; - onClear = undefined; - } else if (valueState > 0) { - // isset 蓝点 tip: 已设置值,点击清除 - tip = intlNode('Setted Value, Click to Clear'); - className += ' valuestate-isset'; - icon = <IconClear size={6} />; - } - } else { - onClear = undefined; - // unset 占位空间 - } - - return ( - <i className={className} onClick={onClear}> - {icon} - {tip && <Tip>{tip}</Tip>} - </i> - ); - */ } export interface PopupFieldProps extends FieldProps { diff --git a/packages/editor-skeleton/src/components/field/index.less b/packages/editor-skeleton/src/components/field/index.less index 249abef570..8c1facfbaf 100644 --- a/packages/editor-skeleton/src/components/field/index.less +++ b/packages/editor-skeleton/src/components/field/index.less @@ -14,54 +14,6 @@ .lc-field-title { display: flex; align-items: center; - .lc-valuestate { - height: 6px; - width: 6px; - min-width: 6px; - border-radius: 100%; - margin-right: 2px; - pointer-events: none; - display: inline-flex; - align-items: center; - justify-content: center; - color: white; - > svg { - display: none; - } - &.valuestate-multiple { - background-color: rgb(232, 145, 83); - pointer-events: auto; - &:hover { - background-color: rgb(223, 139, 30); - cursor: pointer; - transform: scale(2); - transform-origin: center; - > svg { - display: block; - } - } - } - &.valuestate-isset { - background-color: rgba(124, 177, 238, 0.6); - pointer-events: auto; - &:hover { - background-color: rgb(45, 126, 219); - cursor: pointer; - transform: scale(2); - transform-origin: center; - > svg { - display: block; - } - } - } - &.valuestate-required { - background-color: rgb(250, 82, 76); - pointer-events: auto; - &:hover { - background-color: rgb(224, 46, 40); - } - } - } } .lc-field-icon { transform-origin: center; @@ -92,11 +44,7 @@ &.lc-block-field, &.lc-accordion-field, &.lc-entry-field { display: block; - &:first-child { - > .lc-field-head { - // border-top: none; - } - } + > .lc-field-head { height: 32px; display: flex; @@ -110,7 +58,7 @@ user-select: none; > .lc-field-icon { - color: #8f9bb3; + color: var(--color-icon-normal, #8f9bb3); } } @@ -128,10 +76,6 @@ } } } - - // + .lc-inline-field { - // border-top: 1px solid var(--color-line-normal); - // } } &.lc-entry-field { @@ -163,15 +107,11 @@ > .lc-field-head { cursor: pointer; } - + &.lc-field-is-collapsed { margin-bottom: 6px; } - // collapsed - // &:last-child.lc-field-is-collapsed{ - // border-bottom: 1px solid var(--color-line-normal); - // } &.lc-field-is-collapsed { > .lc-field-head .lc-field-icon { transform: rotate(180deg); @@ -180,56 +120,5 @@ display: none; } } - - // 邻近的保持上下距离 - + .lc-field { - // margin-top: @y-gap; - } - } - - // 2rd level reset - .lc-field-body { - // .lc-inline-field { - // &:first-child { - // padding-top: 0; - // } - // + .lc-accordion-field, +.lc-block-field { - // margin-top: @y-gap; - // } - // } - - // .lc-field { - // border-top: none !important; - // } - - // .lc-accordion-field, .lc-block-field { - // > .lc-field-head { - // padding-left: @x-gap; - // background: var(--color-block-background-light); - // border-bottom: none; - // border-top: none; - // > .lc-field-icon { - // // margin-right: @x-gap/2; - // margin-right: 0; - // } - // } - - // > .lc-field-body { - // padding: 8px; - // } - // } - - // 3rd level field title width should short - // .lc-field-body .lc-inline-field { - // > .lc-field-head { - // width: 50px; - // .lc-title-label { - // width: 50px; - // } - // } - // } - // >.lc-block-setter { - // flex: 1; - // } } } diff --git a/packages/editor-skeleton/src/components/settings/style.less b/packages/editor-skeleton/src/components/settings/style.less index 57a7c9357f..4599ed55c2 100644 --- a/packages/editor-skeleton/src/components/settings/style.less +++ b/packages/editor-skeleton/src/components/settings/style.less @@ -33,14 +33,6 @@ position: relative; margin-bottom: 4px; position: absolute; - - .lc-setting-stage-back-icon { - position: absolute; - left: 8px; - top: 8px; - color: #8f9bb3; - cursor: pointer; - } } .lc-settings-notice { diff --git a/packages/editor-skeleton/src/layouts/theme.less b/packages/editor-skeleton/src/layouts/theme.less index 53afb69328..13fc19c847 100644 --- a/packages/editor-skeleton/src/layouts/theme.less +++ b/packages/editor-skeleton/src/layouts/theme.less @@ -16,6 +16,7 @@ --color-icon-hover: @normal-alpha-3; --color-icon-active: @brand-color-1; --color-icon-reverse: @white-alpha-1; + --color-icon-disabled: @normal-alpha-6; --color-icon-pane: @dark-alpha-3; --color-line-normal: @normal-alpha-7; @@ -27,6 +28,7 @@ --color-text-light: lighten(@dark-alpha-3, 10%); --color-text-reverse: @white-alpha-2; --color-text-regular: @normal-alpha-2; + --color-text-disabled: @gray-light; --color-field-label: @dark-alpha-4; --color-field-text: @dark-alpha-3; @@ -48,6 +50,8 @@ --color-function-error: @brand-danger; --color-function-error-dark: darken(@brand-danger, 10%); --color-function-error-light: lighten(@brand-danger, 10%); + --color-function-purple: rgb(144, 94, 190); + --color-function-brown: #7b605b; --color-pane-background: @white-alpha-1; --color-block-background-normal: @white-alpha-1; @@ -55,6 +59,10 @@ --color-block-background-shallow: @normal-alpha-8; --color-block-background-dark: @normal-alpha-7; --color-block-background-disabled: @normal-alpha-6; + --color-block-background-active: @brand-color-1-7; + --color-block-background-warning: @brand-warning-alpha-7; + --color-block-background-error: @brand-danger-alpha-7; + --color-block-background-success: @brand-success-alpha-7; --color-block-background-deep-dark: @normal-5; --color-layer-mask-background: @dark-alpha-7; --color-layer-tooltip-background: rgba(44,47,51,0.8); diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 38cbcfae09..58123ea464 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -60,7 +60,7 @@ body { .lc-help-tip { margin-left: 4px; - color: rgba(0, 0, 0, 0.4); + color: var(--color-icon-normal, rgba(0, 0, 0, 0.4)); cursor: pointer; } } @@ -68,7 +68,7 @@ body { height: 48px; font-size: 16px; padding: 0 15px; - color: #0f1726; + color: var(--color-title, #0f1726); font-weight: bold; } @@ -79,39 +79,6 @@ body { left: 0; right: 0; overflow: visible; - /* - .my-tabs { - width: 100%; - height: 100%; - position: relative; - .tabs-title { - display: flex; - height: var(--pane-title-height); - > .tab-title { - cursor: pointer; - padding: 0; - flex: 1; - min-width: 0; - justify-content: center; - border-bottom: 2px solid transparent; - &.actived { - cursor: default; - color: var(--color-text-avtived); - border-bottom-color: #3896ee; - } - } - } - .tabs-content { - position: absolute; - top: var(--pane-title-height); - bottom: 0; - left: 0; - right: 0; - height: calc(100% - var(--pane-title-height)); - overflow: hidden; - } - } - */ } .lc-outline-tree-container { border-top: 1px solid var(--color-line-normal, rgba(31, 56, 88, 0.1)); @@ -234,8 +201,7 @@ body { display: flex; justify-content: center; align-items: center; - // background: rgba(31,56,88,0.04); - border-bottom: 1px solid #edeff3; + border-bottom: 1px solid var(--color-line-normal, #edeff3); .lc-tab-title { flex: 1; height: 32px; @@ -246,8 +212,8 @@ body { cursor: pointer; font-size: 12px; &.actived { - color: #0079f2; - border-bottom-color: #0079f2; + color: var(--color-brand, #0079f2); + border-bottom-color: var(--color-brand, #0079f2); } } } @@ -293,7 +259,7 @@ body { // min-width: var(--dock-fixed-pane-width); left: calc(var(--left-area-width) + 1px); background-color: var(--color-left-float-pane-background, var(--color-pane-background)); - box-shadow: 4px 6px 6px 0 rgba(31, 50, 88, 0.08); + box-shadow: 4px 6px 6px 0 var(--color-block-background-shallow, rgba(31, 50, 88, 0.08)); z-index: 820; display: none; // padding-top: 36px; @@ -340,7 +306,7 @@ body { cursor: pointer; } &.actived { - color: #0079f2; + color: var(--color-brand, #0079f2); } &.disabled { opacity: 0.4; diff --git a/packages/editor-skeleton/src/less-variables.less b/packages/editor-skeleton/src/less-variables.less index c44fc196e2..017e432ce6 100644 --- a/packages/editor-skeleton/src/less-variables.less +++ b/packages/editor-skeleton/src/less-variables.less @@ -99,19 +99,19 @@ @brand-link-hover: #2e76a6; // F1-1-7 A10 -@brand-danger-alpha-7: rgba(240, 70, 49, 0.9); +@brand-danger-alpha-7: rgba(240, 70, 49, 0.1); // F1-1-8 A6 @brand-danger-alpha-8: rgba(240, 70, 49, 0.8); // F2-1-2 A80 @brand-warning-alpha-2: rgba(250, 189, 14, 0.8); // F2-1-7 A10 -@brand-warning-alpha-7: rgba(250, 189, 14, 0.9); +@brand-warning-alpha-7: rgba(250, 189, 14, 0.1); // F3-1-2 A80 @brand-success-alpha-2: rgba(102, 188, 92, 0.8); // F3-1-7 A10 -@brand-success-alpha-7: rgba(102, 188, 92, 0.9); +@brand-success-alpha-7: rgba(102, 188, 92, 0.1); // F4-1-7 A10 -@brand-link-alpha-7: rgba(102, 188, 92, 0.9); +@brand-link-alpha-7: rgba(102, 188, 92, 0.1); // 文本色 @text-primary-color: @dark-alpha-3; diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index 406a5b5da4..37f51a170d 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -54,17 +54,17 @@ .tree-node-modal { margin: 5px; - border: 1px solid rgba(31, 56, 88, 0.2); + border: 1px solid var(--color-field-border, rgba(31, 56, 88, 0.2)); border-radius: 3px; - box-shadow: 0 1px 4px 0 rgba(31, 56, 88, 0.15); + box-shadow: 0 1px 4px 0 var(--color-block-background-shallow, rgba(31, 56, 88, 0.15)); .tree-node-modal-title { position: relative; - background: rgba(31, 56, 88, 0.04); + background: var(--color-block-background-light, rgba(31, 56, 88, 0.04)); padding: 0 10px; height: 32px; line-height: 32px; - border-bottom: 1px solid rgba(31, 56, 88, 0.2); + border-bottom: 1px solid var(--color-field-border, rgba(31, 56, 88, 0.2)); .tree-node-modal-title-visible-icon { position: absolute; @@ -89,7 +89,7 @@ left: 6px; } .tree-node-modal-radio-active { - color: #006cff; + color: var(--color-brand, #006cff); } } @@ -108,7 +108,7 @@ &:hover { .tree-node-branches::before { - border-left-color: #ddd; + border-left-color: var(--color-line-darken, #ddd); } } @@ -120,20 +120,20 @@ transform: translateZ(0); transition: all 0.2s ease-in-out; &.invalid { - border-color: red; - background-color: rgba(240, 154, 154, 0.719); + border-color: var(--color-function-error, red); + background-color: var(--color-block-background-error, rgba(240, 154, 154, 0.719)); } } .condition-group-container { - border-bottom: 1px solid #7b605b; + border-bottom: 1px solid var(--color-function-brown, #7b605b); position: relative; &:before { position: absolute; display: block; width: 0; - border-left: 0.5px solid #7b605b; + border-left: 0.5px solid var(--color-function-brown, #7b605b); height: 100%; top: 0; left: 0; @@ -142,26 +142,26 @@ } > .condition-group-title { text-align: center; - background-color: #7b605b; + background-color: var(--color-function-brown, #7b605b); height: 14px; > .lc-title { font-size: 12px; transform: scale(0.8); transform-origin: top; - color: white; - text-shadow: 0 0 2px black; + color: var(--color-text-reverse, white); + text-shadow: 0 0 2px var(--color-block-background-shallow, black); display: block; } } } .tree-node-slots { - border-bottom: 1px solid rgb(144, 94, 190); + border-bottom: 1px solid var(--color-function-purple, rgb(144, 94, 190)); position: relative; &::before { position: absolute; display: block; width: 0; - border-left: 0.5px solid rgb(144, 94, 190); + border-left: 0.5px solid var(--color-function-purple, rgb(144, 94, 190)); height: 100%; top: 0; left: 0; @@ -170,25 +170,25 @@ } > .tree-node-slots-title { text-align: center; - background-color: rgb(144, 94, 190); + background-color: var(--color-function-purple, rgb(144, 94, 190)); height: 14px; > .lc-title { font-size: 12px; transform: scale(0.8); transform-origin: top; - color: white; + color: var(--color-text-reverse, white); text-shadow: 0 0 2px black; display: block; } } &.insertion-at-slots { padding-bottom: @treeNodeHeight; - border-bottom-color: rgb(182, 55, 55); + border-bottom-color: var(--color-function-error-dark, rgb(182, 55, 55)); > .tree-node-slots-title { - background-color: rgb(182, 55, 55); + background-color: var(--color-function-error-dark, rgb(182, 55, 55)); } &::before { - border-left-color: rgb(182, 55, 55); + border-left-color: var(--color-function-error-dark, rgb(182, 55, 55)); } } } @@ -326,13 +326,13 @@ align-items: center; line-height: 0; &.cond { - color: rgb(179, 52, 6); + color: var(--color-function-error, rgb(179, 52, 6)); } &.loop { - color: rgb(103, 187, 187); + color: var(--color-function-success, rgb(103, 187, 187)); } &.slot { - color: rgb(211, 90, 211); + color: var(--color-function-purple, rgb(211, 90, 211)); } } } @@ -366,7 +366,7 @@ &.hidden { .tree-node-title-label { - color: #9b9b9b; + color: var(--color-text-disabled, #9b9b9b); } & > .tree-node-title > .tree-node-hide-btn { opacity: 0.8; diff --git a/packages/utils/src/create-icon.tsx b/packages/utils/src/create-icon.tsx index 0f25005298..0a5d6c1ff7 100644 --- a/packages/utils/src/create-icon.tsx +++ b/packages/utils/src/create-icon.tsx @@ -18,7 +18,11 @@ export function createIcon( } if (typeof icon === 'string') { if (URL_RE.test(icon)) { - return <img src={icon} {...props} />; + return createElement('img', { + src: icon, + class: props?.className, + ...props, + }); } return <Icon type={icon} {...props} />; } diff --git a/packages/workspace/src/less-variables.less b/packages/workspace/src/less-variables.less index c44fc196e2..017e432ce6 100644 --- a/packages/workspace/src/less-variables.less +++ b/packages/workspace/src/less-variables.less @@ -99,19 +99,19 @@ @brand-link-hover: #2e76a6; // F1-1-7 A10 -@brand-danger-alpha-7: rgba(240, 70, 49, 0.9); +@brand-danger-alpha-7: rgba(240, 70, 49, 0.1); // F1-1-8 A6 @brand-danger-alpha-8: rgba(240, 70, 49, 0.8); // F2-1-2 A80 @brand-warning-alpha-2: rgba(250, 189, 14, 0.8); // F2-1-7 A10 -@brand-warning-alpha-7: rgba(250, 189, 14, 0.9); +@brand-warning-alpha-7: rgba(250, 189, 14, 0.1); // F3-1-2 A80 @brand-success-alpha-2: rgba(102, 188, 92, 0.8); // F3-1-7 A10 -@brand-success-alpha-7: rgba(102, 188, 92, 0.9); +@brand-success-alpha-7: rgba(102, 188, 92, 0.1); // F4-1-7 A10 -@brand-link-alpha-7: rgba(102, 188, 92, 0.9); +@brand-link-alpha-7: rgba(102, 188, 92, 0.1); // 文本色 @text-primary-color: @dark-alpha-3; From 82d82b9d0596f75080d4bde1bfea5ef86a47ad19 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Sun, 8 Oct 2023 18:04:33 +0800 Subject: [PATCH 279/469] feat: update Outline Tree to Component Tree --- packages/plugin-outline-pane/src/locale/en-US.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-outline-pane/src/locale/en-US.json b/packages/plugin-outline-pane/src/locale/en-US.json index 9ade9e66f4..b86a7859bb 100644 --- a/packages/plugin-outline-pane/src/locale/en-US.json +++ b/packages/plugin-outline-pane/src/locale/en-US.json @@ -10,7 +10,7 @@ "Loop": "Loop", "Slots": "Slots", "Slot for {prop}": "Slot for {prop}", - "Outline Tree": "Outline Tree", + "Outline Tree": "Component Tree", "Filter Node": "Filter Node", "Check All": "Check All", "Conditional rendering": "Conditional rendering", From 4684d3171797765fe4a480a4ce23503747663da7 Mon Sep 17 00:00:00 2001 From: rainke <woshihepeng520@163.com> Date: Mon, 9 Oct 2023 09:59:39 +0800 Subject: [PATCH 280/469] chore: resolve react-error-overlay to 6.0.9 --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 6a650c49b6..aded2a3015 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,8 @@ "lockfile": "enable" }, "resolutions": { - "typescript": "4.6.2" + "typescript": "4.6.2", + "react-error-overlay": "6.0.9" }, "repository": "git@github.com:alibaba/lowcode-engine.git" } From 30f8066332b277335b67b681da9fe263d9a15e38 Mon Sep 17 00:00:00 2001 From: AndyJin <jjj706@163.com> Date: Thu, 12 Oct 2023 08:45:34 +0800 Subject: [PATCH 281/469] fix: fix rendering failure when children is number 0 --- packages/renderer-core/src/renderer/base.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 216735edcf..72821cfd38 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -453,7 +453,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { * @param idx 为循环渲染的循环Index */ __createVirtualDom = (originalSchema: IPublicTypeNodeData | IPublicTypeNodeData[] | undefined, originalScope: any, parentInfo: INodeInfo, idx: string | number = ''): any => { - if (!originalSchema) { + if (originalSchema === null || originalSchema === undefined) { return null; } let scope = originalScope; From 3129445d60935db69bf14b81bee5e302f22053db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=AD=A3?= <lizhengnacl@163.com> Date: Tue, 10 Oct 2023 17:11:07 +0800 Subject: [PATCH 282/469] Update specs.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 去掉重复内容 --- docs/docs/guide/design/specs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/guide/design/specs.md b/docs/docs/guide/design/specs.md index 0d97f5cc08..2e8e4c195c 100644 --- a/docs/docs/guide/design/specs.md +++ b/docs/docs/guide/design/specs.md @@ -58,7 +58,7 @@ sidebar_position: 1 ## 协议的作用 -基于统一的协议,我们完成业务组件、区块、模板等各类物料的标准统一,基于统一的协议,我们完成业务组件、区块、模板等各类物料的标准统一,各类中后台研发系统生产的物料可借助物料中心进行跨系统流通,通过丰富物料生态的共享提升各平台研发系统的效率。同时完成低代码引擎的标准统一以及低代码搭建中台能力的输出,帮助业务方快速孵化本业务域中后台研发系统。 +基于统一的协议,我们完成业务组件、区块、模板等各类物料的标准统一,各类中后台研发系统生产的物料可借助物料中心进行跨系统流通,通过丰富物料生态的共享提升各平台研发系统的效率。同时完成低代码引擎的标准统一以及低代码搭建中台能力的输出,帮助业务方快速孵化本业务域中后台研发系统。 ### 打破物料孤岛 From ca6fe7c335b5035eba18a8681a4bb7a5ccac83b3 Mon Sep 17 00:00:00 2001 From: rainke <woshihepeng520@163.com> Date: Wed, 11 Oct 2023 14:55:05 +0800 Subject: [PATCH 283/469] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20forwardRef?= =?UTF-8?q?=20=E7=BB=84=E4=BB=B6=E7=9A=84=E9=94=99=E8=AF=AF=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E6=8D=95=E8=8E=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../renderer/__snapshots__/demo.test.tsx.snap | 1 + packages/renderer-core/src/hoc/index.tsx | 70 ++++++++++++++++--- packages/renderer-core/src/renderer/base.tsx | 8 +-- .../renderer-core/src/renderer/renderer.tsx | 48 ------------- packages/renderer-core/src/types/index.ts | 1 - packages/utils/src/is-react.ts | 13 +++- 6 files changed, 75 insertions(+), 66 deletions(-) diff --git a/packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap b/packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap index 0ebb606dac..2f2d19f269 100644 --- a/packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap +++ b/packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap @@ -31,6 +31,7 @@ exports[`Base should be render Text 1`] = ` behavior="NORMAL" componentId="node_ockvuu8u916" fieldId="text_kvuu9gl2" + forwardRef={[Function]} maxLine={0} showTitle={false} > diff --git a/packages/renderer-core/src/hoc/index.tsx b/packages/renderer-core/src/hoc/index.tsx index a9314060f3..aae03045ec 100644 --- a/packages/renderer-core/src/hoc/index.tsx +++ b/packages/renderer-core/src/hoc/index.tsx @@ -1,20 +1,72 @@ import { cloneEnumerableProperty } from '@alilc/lowcode-utils'; import adapter from '../adapter'; +import { IBaseRendererInstance, IRendererProps } from '../types'; -export function compWrapper(Comp: any) { +function patchDidCatch(Comp: any, { baseRenderer }: { baseRenderer: IBaseRendererInstance }) { + if (Comp.patchedCatch) { + return; + } + Comp.patchedCatch = true; + const { PureComponent } = adapter.getRuntime(); + // Rax 的 getDerivedStateFromError 有 BUG,这里先用 componentDidCatch 来替代 + // @see https://github.com/alibaba/rax/issues/2211 + const originalDidCatch = Comp.prototype.componentDidCatch; + Comp.prototype.componentDidCatch = function didCatch(this: any, error: Error, errorInfo: any) { + this.setState({ engineRenderError: true, error }); + if (originalDidCatch && typeof originalDidCatch === 'function') { + originalDidCatch.call(this, error, errorInfo); + } + }; + + const { engine } = baseRenderer.context; + const originRender = Comp.prototype.render; + Comp.prototype.render = function () { + if (this.state && this.state.engineRenderError) { + this.state.engineRenderError = false; + return engine.createElement(engine.getFaultComponent(), { + ...this.props, + error: this.state.error, + componentName: this.props._componentName, + }); + } + return originRender.call(this); + }; + if (!(Comp.prototype instanceof PureComponent)) { + const originShouldComponentUpdate = Comp.prototype.shouldComponentUpdate; + Comp.prototype.shouldComponentUpdate = function (nextProps: IRendererProps, nextState: any) { + if (nextState && nextState.engineRenderError) { + return true; + } + return originShouldComponentUpdate + ? originShouldComponentUpdate.call(this, nextProps, nextState) + : true; + }; + } +} + +export function compWrapper(Comp: any, options: { baseRenderer: IBaseRendererInstance }) { const { createElement, Component, forwardRef } = adapter.getRuntime(); + if ( + Comp?.prototype?.isReactComponent || // react + Comp?.prototype?.setState || // rax + Comp?.prototype instanceof Component + ) { + patchDidCatch(Comp, options); + return Comp; + } class Wrapper extends Component { - // constructor(props: any, context: any) { - // super(props, context); - // } - render() { - return createElement(Comp, this.props); + return createElement(Comp, { ...this.props, ref: this.props.forwardRef }); } } (Wrapper as any).displayName = Comp.displayName; - return cloneEnumerableProperty(forwardRef((props: any, ref: any) => { - return createElement(Wrapper, { ...props, forwardRef: ref }); - }), Comp); + patchDidCatch(Wrapper, options); + + return cloneEnumerableProperty( + forwardRef((props: any, ref: any) => { + return createElement(Wrapper, { ...props, forwardRef: ref }); + }), + Comp, + ); } diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 72821cfd38..2ed476b1c4 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -23,7 +23,6 @@ import { transformStringToFunction, checkPropTypes, getI18n, - canAcceptsRef, getFileCssName, capitalizeFirstLetter, DataHelper, @@ -616,11 +615,8 @@ export default function baseRendererFactory(): IBaseRenderComponent { }); }); - // 对于不可以接收到 ref 的组件需要做特殊处理 - if (!canAcceptsRef(Comp)) { - Comp = compWrapper(Comp); - components[schema.componentName] = Comp; - } + Comp = compWrapper(Comp, { baseRenderer: this }); + components[schema.componentName] = Comp; otherProps.ref = (ref: any) => { this.$(props.fieldId || props.ref, ref); // 收集ref diff --git a/packages/renderer-core/src/renderer/renderer.tsx b/packages/renderer-core/src/renderer/renderer.tsx index 09559b6f89..300b1cd164 100644 --- a/packages/renderer-core/src/renderer/renderer.tsx +++ b/packages/renderer-core/src/renderer/renderer.tsx @@ -105,55 +105,7 @@ export default function rendererFactory(): IRenderComponent { return SetComponent; } - patchDidCatch(SetComponent: any) { - if (!this.isValidComponent(SetComponent)) { - return; - } - if (SetComponent.patchedCatch) { - return; - } - if (!SetComponent.prototype) { - return; - } - SetComponent.patchedCatch = true; - - // Rax 的 getDerivedStateFromError 有 BUG,这里先用 componentDidCatch 来替代 - // @see https://github.com/alibaba/rax/issues/2211 - const originalDidCatch = SetComponent.prototype.componentDidCatch; - SetComponent.prototype.componentDidCatch = function didCatch(this: any, error: Error, errorInfo: any) { - this.setState({ engineRenderError: true, error }); - if (originalDidCatch && typeof originalDidCatch === 'function') { - originalDidCatch.call(this, error, errorInfo); - } - }; - - const engine = this; - const originRender = SetComponent.prototype.render; - SetComponent.prototype.render = function () { - if (this.state && this.state.engineRenderError) { - this.state.engineRenderError = false; - return engine.createElement(engine.getFaultComponent(), { - ...this.props, - error: this.state.error, - componentName: this.props._componentName - }); - } - return originRender.call(this); - }; - if(!(SetComponent.prototype instanceof PureComponent)) { - const originShouldComponentUpdate = SetComponent.prototype.shouldComponentUpdate; - SetComponent.prototype.shouldComponentUpdate = function (nextProps: IRendererProps, nextState: any) { - if (nextState && nextState.engineRenderError) { - return true; - } - return originShouldComponentUpdate ? originShouldComponentUpdate.call(this, nextProps, nextState) : true; - }; - } - } - createElement(SetComponent: any, props: any, children?: any) { - // TODO: enable in runtime mode? - this.patchDidCatch(SetComponent); return (this.props.customCreateElement || createElement)(SetComponent, props, children); } diff --git a/packages/renderer-core/src/types/index.ts b/packages/renderer-core/src/types/index.ts index a49fe89920..afbec272ab 100644 --- a/packages/renderer-core/src/types/index.ts +++ b/packages/renderer-core/src/types/index.ts @@ -335,7 +335,6 @@ export interface IRenderComponent { componentDidCatch(e: any): Promise<void> | void; shouldComponentUpdate(nextProps: IRendererProps): boolean; isValidComponent(SetComponent: any): any; - patchDidCatch(SetComponent: any): void; createElement(SetComponent: any, props: any, children?: any): any; getNotFoundComponent(): any; getFaultComponent(): any; diff --git a/packages/utils/src/is-react.ts b/packages/utils/src/is-react.ts index 07568db981..b19f043f14 100644 --- a/packages/utils/src/is-react.ts +++ b/packages/utils/src/is-react.ts @@ -10,10 +10,10 @@ export function isReactClass(obj: any): obj is ComponentClass<any> { } export function acceptsRef(obj: any): boolean { - return obj?.prototype?.isReactComponent || (obj.$$typeof && obj.$$typeof === REACT_FORWARD_REF_TYPE); + return obj?.prototype?.isReactComponent || isForwardOrMemoForward(obj); } -function isForwardRefType(obj: any): boolean { +export function isForwardRefType(obj: any): boolean { return obj?.$$typeof && obj?.$$typeof === REACT_FORWARD_REF_TYPE; } @@ -21,6 +21,15 @@ function isMemoType(obj: any): boolean { return obj?.$$typeof && obj.$$typeof === REACT_MEMO_TYPE; } +export function isForwardOrMemoForward(obj: any): boolean { + return obj?.$$typeof && ( + // React.forwardRef(..) + isForwardRefType(obj) || + // React.memo(React.forwardRef(..)) + (isMemoType(obj) && isForwardRefType(obj.type)) + ); +} + export function isReactComponent(obj: any): obj is ComponentType<any> { if (!obj) { return false; From a96961f588971805ef0cdb5e07af2ab14475ac74 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 16 Oct 2023 14:35:10 +0800 Subject: [PATCH 284/469] docs: publish docs 1.1.11 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 3950b35c9c..6c43fe1d0f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.10", + "version": "1.1.11", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 7677ad0166f479fa78c78dfb6d69fb8a3617cbd9 Mon Sep 17 00:00:00 2001 From: rainke <woshihepeng520@163.com> Date: Tue, 17 Oct 2023 17:33:07 +0800 Subject: [PATCH 285/469] =?UTF-8?q?fix:=20hoc=20=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/renderer-core/src/hoc/index.tsx | 22 +++++++++++++++++--- packages/renderer-core/src/renderer/base.tsx | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/renderer-core/src/hoc/index.tsx b/packages/renderer-core/src/hoc/index.tsx index aae03045ec..3e7f5ec6a1 100644 --- a/packages/renderer-core/src/hoc/index.tsx +++ b/packages/renderer-core/src/hoc/index.tsx @@ -2,7 +2,12 @@ import { cloneEnumerableProperty } from '@alilc/lowcode-utils'; import adapter from '../adapter'; import { IBaseRendererInstance, IRendererProps } from '../types'; -function patchDidCatch(Comp: any, { baseRenderer }: { baseRenderer: IBaseRendererInstance }) { +interface Options { + baseRenderer: IBaseRendererInstance; + schema: any; +} + +function patchDidCatch(Comp: any, { baseRenderer }: Options) { if (Comp.patchedCatch) { return; } @@ -44,7 +49,9 @@ function patchDidCatch(Comp: any, { baseRenderer }: { baseRenderer: IBaseRendere } } -export function compWrapper(Comp: any, options: { baseRenderer: IBaseRendererInstance }) { +const cache = new Map(); + +export function compWrapper(Comp: any, options: Options) { const { createElement, Component, forwardRef } = adapter.getRuntime(); if ( Comp?.prototype?.isReactComponent || // react @@ -54,6 +61,11 @@ export function compWrapper(Comp: any, options: { baseRenderer: IBaseRendererIns patchDidCatch(Comp, options); return Comp; } + + if (cache.has(options.schema.id)) { + return cache.get(options.schema.id); + } + class Wrapper extends Component { render() { return createElement(Comp, { ...this.props, ref: this.props.forwardRef }); @@ -63,10 +75,14 @@ export function compWrapper(Comp: any, options: { baseRenderer: IBaseRendererIns patchDidCatch(Wrapper, options); - return cloneEnumerableProperty( + const WrapperComponent = cloneEnumerableProperty( forwardRef((props: any, ref: any) => { return createElement(Wrapper, { ...props, forwardRef: ref }); }), Comp, ); + + cache.set(options.schema.id, WrapperComponent); + + return WrapperComponent; } diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 2ed476b1c4..7b9562fcc6 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -615,7 +615,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { }); }); - Comp = compWrapper(Comp, { baseRenderer: this }); + Comp = compWrapper(Comp, { baseRenderer: this, schema }); components[schema.componentName] = Comp; otherProps.ref = (ref: any) => { From d56ed6bff172f3833f5321073310fac5d54bd247 Mon Sep 17 00:00:00 2001 From: rainke <woshihepeng520@163.com> Date: Mon, 16 Oct 2023 16:59:03 +0800 Subject: [PATCH 286/469] feat: make asset support es module --- packages/designer/src/builtin-simulator/create-simulator.ts | 5 +++-- packages/types/src/assets.ts | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/designer/src/builtin-simulator/create-simulator.ts b/packages/designer/src/builtin-simulator/create-simulator.ts index 15ab3507b5..57369efd89 100644 --- a/packages/designer/src/builtin-simulator/create-simulator.ts +++ b/packages/designer/src/builtin-simulator/create-simulator.ts @@ -56,12 +56,13 @@ export function createSimulator( } const id = asset.id ? ` data-id="${asset.id}"` : ''; const lv = asset.level || level || AssetLevel.Environment; + const scriptType = asset.scriptType ? ` type="${asset.scriptType}"` : ''; if (asset.type === AssetType.JSUrl) { scripts[lv].push( - `<script src="${asset.content}"${id}></script>`, + `<script src="${asset.content}"${id}${scriptType}></script>`, ); } else if (asset.type === AssetType.JSText) { - scripts[lv].push(`<script${id}>${asset.content}</script>`); + scripts[lv].push(`<script${id}${scriptType}>${asset.content}</script>`); } else if (asset.type === AssetType.CSSUrl) { styles[lv].push( `<link rel="stylesheet" href="${asset.content}"${id} />`, diff --git a/packages/types/src/assets.ts b/packages/types/src/assets.ts index 852ed00380..f0e6d35396 100644 --- a/packages/types/src/assets.ts +++ b/packages/types/src/assets.ts @@ -38,6 +38,7 @@ export interface AssetItem { device?: string; level?: AssetLevel; id?: string; + scriptType?: string; } export type AssetList = Array<Asset | undefined | null>; From 96fe876e331d91f36989e9660b86f72b223dc5a4 Mon Sep 17 00:00:00 2001 From: rainke <woshihepeng520@163.com> Date: Fri, 13 Oct 2023 16:57:26 +0800 Subject: [PATCH 287/469] =?UTF-8?q?fix:=20=E5=A4=8D=E5=88=B6=E6=97=B6?= =?UTF-8?q?=E9=98=B2=E6=AD=A2=20ref=20=E9=87=8D=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/designer/src/component-actions.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/designer/src/component-actions.ts b/packages/designer/src/component-actions.ts index 76ead7d9a6..57ad30bf25 100644 --- a/packages/designer/src/component-actions.ts +++ b/packages/designer/src/component-actions.ts @@ -10,6 +10,14 @@ import { } from './icons'; import { componentDefaults, legacyIssues } from './transducers'; +function deduplicateRef(node: IPublicModelNode | null | undefined) { + const currentRef = node?.getPropValue('ref'); + if (currentRef) { + node?.setPropValue('ref', `${node.componentName.toLowerCase()}-${Math.random().toString(36).slice(2, 9)}`); + } + node?.children?.forEach(deduplicateRef); +} + export class ComponentActions { private metadataTransducers: IPublicTypeMetadataTransducer[] = []; @@ -53,6 +61,7 @@ export class ComponentActions { const { document: doc, parent, index } = node; if (parent) { const newNode = doc?.insertNode(parent, node, (index ?? 0) + 1, true); + deduplicateRef(newNode); newNode?.select(); const { isRGL, rglNode } = node?.getRGL(); if (isRGL) { From 79b9a6efa57d1a30559ea8476bbb380b5957d968 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 19 Oct 2023 11:05:41 +0800 Subject: [PATCH 288/469] feat: add theme color document & optimize some theme colors --- docs/docs/guide/expand/editor/cli.md | 2 +- docs/docs/guide/expand/editor/graph.md | 2 +- docs/docs/guide/expand/editor/setter.md | 2 +- docs/docs/guide/expand/editor/theme.md | 91 +++++++++++++++++++ .../bem-tools/insertion.less | 2 +- .../editor-core/src/widgets/tip/style.less | 4 +- .../src/layouts/sub-top-area.tsx | 8 +- .../editor-skeleton/src/layouts/theme.less | 46 +++++++--- .../editor-skeleton/src/layouts/top-area.tsx | 6 +- .../src/layouts/workbench.less | 27 +++--- .../plugin-outline-pane/src/views/style.less | 26 +++--- packages/workspace/src/layouts/workbench.tsx | 2 +- 12 files changed, 165 insertions(+), 53 deletions(-) create mode 100644 docs/docs/guide/expand/editor/theme.md diff --git a/docs/docs/guide/expand/editor/cli.md b/docs/docs/guide/expand/editor/cli.md index 60f44ce875..0577a181db 100644 --- a/docs/docs/guide/expand/editor/cli.md +++ b/docs/docs/guide/expand/editor/cli.md @@ -1,6 +1,6 @@ --- title: 低代码生态脚手架 & 调试机制 -sidebar_position: 8 +sidebar_position: 10 --- ## 脚手架简述 diff --git a/docs/docs/guide/expand/editor/graph.md b/docs/docs/guide/expand/editor/graph.md index 2d5127054e..a45f34baf0 100644 --- a/docs/docs/guide/expand/editor/graph.md +++ b/docs/docs/guide/expand/editor/graph.md @@ -1,6 +1,6 @@ --- title: 图编排扩展 -sidebar_position: 9 +sidebar_position: 8 --- ## 项目运行 ### 前置准备 diff --git a/docs/docs/guide/expand/editor/setter.md b/docs/docs/guide/expand/editor/setter.md index 01fd949bbd..4f0e0219fc 100644 --- a/docs/docs/guide/expand/editor/setter.md +++ b/docs/docs/guide/expand/editor/setter.md @@ -1,6 +1,6 @@ --- title: 设置器扩展 -sidebar_position: 5 +sidebar_position: 7 --- ## 设置器简述 diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md new file mode 100644 index 0000000000..b62fb4f28c --- /dev/null +++ b/docs/docs/guide/expand/editor/theme.md @@ -0,0 +1,91 @@ +--- +title: 主题色扩展 +sidebar_position: 9 +--- + +## 主题色扩展简述 + +通过主题色扩展,可以定制多种设计器主题。 + +## 主题色扩展说明 + +### 主题色变量 + +- `--color-brand`: 品牌色 +- `--color-brand-light`: 品牌色(light) +- `--color-brand-dark`: 品牌色(dark) +- `--color-icon-normal`: 正常 icon 颜色 +- `--color-icon-hover`: icon hover 态颜色 +- `--color-icon-active`: icon active 态颜色 +- `--color-icon-reverse`: icon 反色 +- `--color-icon-disabled`: icon 禁用态颜色 +- `--color-icon-pane`: icon 面板颜色 +- `--color-line-normal`: 线条颜色 +- `--color-line-darken`: 线条颜色(darken) +- `--color-title`: 标题颜色 +- `--color-text`: 文字颜色 +- `--color-text-dark`: 文字颜色(dark) +- `--color-text-light`: 文字颜色(light) +- `--color-text-reverse`: 反色情况下,文字颜色 +- `--color-text-regular`: 文字颜色(regular) +- `--color-text-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-pane-background`: 面板背景色 +- `--color-block-background-normal`: 区块背景色 +- `--color-block-background-light`: 区块背景色(light), 作用于画布组件 hover 时遮罩背景色。 +- `--color-block-background-shallow`: 区块背景色 shallow +- `--color-block-background-dark`: 区块背景色(dark) +- `--color-block-background-disabled`: 区块背景色(disabled) +- `--color-block-background-active`: 区块背景色(active) +- `--color-block-background-warning`: 区块背景色(warning) +- `--color-block-background-error`: 区块背景色(error) +- `--color-block-background-success`: 区块背景色(success) +- `--color-block-background-deep-dark`: 区块背景色(deep-dark),作用于多个组件同时拖拽的背景色。 +- `--color-layer-mask-background`: 拖拽元素时,元素原来位置的遮罩背景色 +- `--color-layer-tooltip-background`: tooltip 背景色 +- `--color-background`: 设计器主要背景色 +- `--color-top-area-background`: topArea 背景色,优先级大于 `--color-pane-background` +- `--color-left-area-background`: leftArea 背景色,优先级大于 `--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 高度 +- `--workspace-sub-top-area-margin`: 应用级二级 topArea margin +- `--workspace-sub-top-area-padding`: 应用级二级 topArea padding + +### 生态使用主题色变量 + +插件、物料、设置器等生态为了支持主题色需要对样式进行改造,需要对生态中的样式升级为 css 变量。例如: + +```css +/* before */ +background: #006cff; + +/* after */ +background: var(--color-brand, #006cff); + +``` + +### fusion 物料进行主题色扩展 + +如果使用了 fusion 组件,可以通过 https://fusion.alibaba-inc.com/ 平台进行主题色定制。 \ No newline at end of file diff --git a/packages/designer/src/builtin-simulator/bem-tools/insertion.less b/packages/designer/src/builtin-simulator/bem-tools/insertion.less index c51e73106f..fff045631a 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/insertion.less +++ b/packages/designer/src/builtin-simulator/bem-tools/insertion.less @@ -23,6 +23,6 @@ } &.invalid { - background-color: var(--color-function-error, red); + background-color: var(--color-error, var(--color-function-error, red)); } } diff --git a/packages/editor-core/src/widgets/tip/style.less b/packages/editor-core/src/widgets/tip/style.less index aa5327f3d4..602886d060 100644 --- a/packages/editor-core/src/widgets/tip/style.less +++ b/packages/editor-core/src/widgets/tip/style.less @@ -188,9 +188,9 @@ } } &.lc-theme-green { - background: var(--color-function-success-dark, #57a672); + background: var(--color-success-dark, var(--color-function-success-dark, #57a672)); .lc-arrow:after { - border-top-color: var(--color-function-success-dark, #57a672); + border-top-color: var(--color-success-dark, var(--color-function-success-dark, #57a672)); } } &.lc-visible { diff --git a/packages/editor-skeleton/src/layouts/sub-top-area.tsx b/packages/editor-skeleton/src/layouts/sub-top-area.tsx index e6bf61871a..cef6aa5b02 100644 --- a/packages/editor-skeleton/src/layouts/sub-top-area.tsx +++ b/packages/editor-skeleton/src/layouts/sub-top-area.tsx @@ -13,7 +13,7 @@ export default class SubTopArea extends Component<{ area: Area; itemClassName?: } return ( - <div className={classNames('lc-sub-top-area engine-actionpane', { + <div className={classNames('lc-workspace-sub-top-area lc-sub-top-area engine-actionpane', { 'lc-area-visible': area.visible, })} > @@ -50,13 +50,13 @@ class Contents extends Component<{ area: Area; itemClassName?: string }> { }); let children = []; if (left && left.length) { - children.push(<div className="lc-sub-top-area-left">{left}</div>); + children.push(<div className="lc-workspace-sub-top-area-left lc-sub-top-area-left">{left}</div>); } if (center && center.length) { - children.push(<div className="lc-sub-top-area-center">{center}</div>); + children.push(<div className="lc-workspace-sub-top-area-center lc-sub-top-area-center">{center}</div>); } if (right && right.length) { - children.push(<div className="lc-sub-top-area-right">{right}</div>); + children.push(<div className="lc-workspace-sub-top-area-right lc-sub-top-area-right">{right}</div>); } return ( <Fragment> diff --git a/packages/editor-skeleton/src/layouts/theme.less b/packages/editor-skeleton/src/layouts/theme.less index 13fc19c847..716ab3a99e 100644 --- a/packages/editor-skeleton/src/layouts/theme.less +++ b/packages/editor-skeleton/src/layouts/theme.less @@ -38,20 +38,20 @@ --color-field-border-active: @normal-alpha-3; --color-field-background: @white-alpha-1; - --color-function-success: @brand-success; - --color-function-success-dark: darken(@brand-success, 10%); - --color-function-success-light: lighten(@brand-success, 10%); - --color-function-warning: @brand-warning; - --color-function-warning-dark: darken(@brand-warning, 10%); - --color-function-warning-light: lighten(@brand-warning, 10%); - --color-function-information: @brand-link-hover; - --color-function-information-dark: darken(@brand-link-hover, 10%); - --color-function-information-light: lighten(@brand-link-hover, 10%); - --color-function-error: @brand-danger; - --color-function-error-dark: darken(@brand-danger, 10%); - --color-function-error-light: lighten(@brand-danger, 10%); - --color-function-purple: rgb(144, 94, 190); - --color-function-brown: #7b605b; + --color-success: @brand-success; + --colo-success-dark: darken(@brand-success, 10%); + --color-success-light: lighten(@brand-success, 10%); + --color-warning: @brand-warning; + --color-warning-dark: darken(@brand-warning, 10%); + --color-warning-light: lighten(@brand-warning, 10%); + --color-information: @brand-link-hover; + --color-information-dark: darken(@brand-link-hover, 10%); + --color-information-light: lighten(@brand-link-hover, 10%); + --color-error: @brand-danger; + --color-error-dark: darken(@brand-danger, 10%); + --color-error-light: lighten(@brand-danger, 10%); + --color-purple: rgb(144, 94, 190); + --color-brown: #7b605b; --color-pane-background: @white-alpha-1; --color-block-background-normal: @white-alpha-1; @@ -70,3 +70,21 @@ --pane-title-bg-color: rgba(31,56,88,.04); } + +// @deprecated 变量 +:root { + --color-function-success: @brand-success; + --color-function-success-dark: darken(@brand-success, 10%); + --color-function-success-light: lighten(@brand-success, 10%); + --color-function-warning: @brand-warning; + --color-function-warning-dark: darken(@brand-warning, 10%); + --color-function-warning-light: lighten(@brand-warning, 10%); + --color-function-information: @brand-link-hover; + --color-function-information-dark: darken(@brand-link-hover, 10%); + --color-function-information-light: lighten(@brand-link-hover, 10%); + --color-function-error: @brand-danger; + --color-function-error-dark: darken(@brand-danger, 10%); + --color-function-error-light: lighten(@brand-danger, 10%); + --color-function-purple: rgb(144, 94, 190); + --color-function-brown: #7b605b; +} diff --git a/packages/editor-skeleton/src/layouts/top-area.tsx b/packages/editor-skeleton/src/layouts/top-area.tsx index 56949cbb7f..f6b84b3e6f 100644 --- a/packages/editor-skeleton/src/layouts/top-area.tsx +++ b/packages/editor-skeleton/src/layouts/top-area.tsx @@ -4,14 +4,14 @@ import { observer } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; @observer -export default class TopArea extends Component<{ area: Area; itemClassName?: string }> { +export default class TopArea extends Component<{ area: Area; itemClassName?: string; className?: string }> { render() { - const { area, itemClassName } = this.props; + const { area, itemClassName, className } = this.props; if (area.isEmpty()) { return null; } return ( - <div className={classNames('lc-top-area engine-actionpane', { + <div className={classNames(className, 'lc-top-area engine-actionpane', { 'lc-area-visible': area.visible, })} > diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 58123ea464..6d0604a1f1 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -141,7 +141,7 @@ body { flex-direction: column; background-color: var(--color-background); } - .lc-top-area, .lc-sub-top-area { + .lc-top-area, .lc-workspace-sub-top-area { width: 100%; display: none; margin-bottom: 2px; @@ -152,30 +152,34 @@ body { height: var(--top-area-height); } - &.lc-sub-top-area { - background-color: var(--color-sub-top-area-background, var(--color-pane-background)); - height: var(--sub-top-area-height, var(--top-area-height)); - margin: var(--sub-top-area-margin, 0px 0px 2px 0px); - padding: var(--sub-top-area-padding, 8px 12px 8px 16px); + &.lc-workspace-top-area { + background-color: var(--color-workspace-top-area-background, var(--color-pane-background)); + } + + &.lc-workspace-sub-top-area { + background-color: var(--color-workspace-sub-top-area-background, var(--color-pane-background)); + height: var(--workspace-sub-top-area-height, var(--top-area-height)); + margin: var(--workspace-sub-top-area-margin, 0px 0px 2px 0px); + padding: var(--workspace-sub-top-area-padding, 8px 12px 8px 16px); } &.lc-area-visible { display: flex; } - .lc-top-area-left, .lc-sub-top-area-left { + .lc-top-area-left, .lc-workspace-sub-top-area-left { display: flex; align-items: center; max-width: 100%; } - .lc-top-area-center, .lc-sub-top-area-center { + .lc-top-area-center, .lc-workspace-sub-top-area-center { flex: 1; display: flex; justify-content: center; margin: 0 8px; } - .lc-top-area-right, .lc-sub-top-area-right { + .lc-top-area-right, .lc-workspace-sub-top-area-right { display: flex; align-items: center; > * { @@ -275,9 +279,8 @@ body { flex-direction: column; justify-content: space-between; overflow: hidden; - &.lc-left-area { - background-color: var(--color-left-area-background, var(--color-pane-background)); - } + background-color: var(--color-left-area-background, var(--color-pane-background)); + &.lc-workspace-left-area { background-color: var(--color-workspace-left-area-background, var(--color-pane-background)); } diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index 37f51a170d..15f115ea6b 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -120,20 +120,20 @@ transform: translateZ(0); transition: all 0.2s ease-in-out; &.invalid { - border-color: var(--color-function-error, red); + border-color: var(--color-error, var(--color-function-error, red)); background-color: var(--color-block-background-error, rgba(240, 154, 154, 0.719)); } } .condition-group-container { - border-bottom: 1px solid var(--color-function-brown, #7b605b); + border-bottom: 1px solid var(--color-brown, var(--color-function-brown, #7b605b)); position: relative; &:before { position: absolute; display: block; width: 0; - border-left: 0.5px solid var(--color-function-brown, #7b605b); + border-left: 0.5px solid var(--color-brown, var(--color-function-brown, #7b605b)); height: 100%; top: 0; left: 0; @@ -142,7 +142,7 @@ } > .condition-group-title { text-align: center; - background-color: var(--color-function-brown, #7b605b); + background-color: var(--color-brown, var(--color-function-brown, #7b605b)); height: 14px; > .lc-title { font-size: 12px; @@ -155,13 +155,13 @@ } } .tree-node-slots { - border-bottom: 1px solid var(--color-function-purple, rgb(144, 94, 190)); + border-bottom: 1px solid var(--color-purple, var(--color-function-purple, rgb(144, 94, 190))); position: relative; &::before { position: absolute; display: block; width: 0; - border-left: 0.5px solid var(--color-function-purple, rgb(144, 94, 190)); + border-left: 0.5px solid var(--color-purple, var(--color-function-purple, rgb(144, 94, 190))); height: 100%; top: 0; left: 0; @@ -170,7 +170,7 @@ } > .tree-node-slots-title { text-align: center; - background-color: var(--color-function-purple, rgb(144, 94, 190)); + background-color: var(--color-purple, var(--color-function-purple, rgb(144, 94, 190))); height: 14px; > .lc-title { font-size: 12px; @@ -183,12 +183,12 @@ } &.insertion-at-slots { padding-bottom: @treeNodeHeight; - border-bottom-color: var(--color-function-error-dark, rgb(182, 55, 55)); + border-bottom-color: var(--color-error-dark, var(--color-function-error-dark, rgb(182, 55, 55))); > .tree-node-slots-title { - background-color: var(--color-function-error-dark, rgb(182, 55, 55)); + background-color: var(--color-error-dark, var(--color-function-error-dark, rgb(182, 55, 55))); } &::before { - border-left-color: var(--color-function-error-dark, rgb(182, 55, 55)); + border-left-color: var(--color-error-dark, var(--color-function-error-dark, rgb(182, 55, 55))); } } } @@ -326,13 +326,13 @@ align-items: center; line-height: 0; &.cond { - color: var(--color-function-error, rgb(179, 52, 6)); + color: var(--color-error, var(--color-function-error, rgb(179, 52, 6))); } &.loop { - color: var(--color-function-success, rgb(103, 187, 187)); + color: var(--color-success, var(--color-function-success, rgb(103, 187, 187))); } &.slot { - color: var(--color-function-purple, rgb(211, 90, 211)); + color: var(--color-purple, var(--color-function-purple, rgb(211, 90, 211))); } } } diff --git a/packages/workspace/src/layouts/workbench.tsx b/packages/workspace/src/layouts/workbench.tsx index 9bdbe3f932..2913576e1c 100644 --- a/packages/workspace/src/layouts/workbench.tsx +++ b/packages/workspace/src/layouts/workbench.tsx @@ -47,7 +47,7 @@ export class Workbench extends Component<{ return ( <div className={classNames('lc-workspace-workbench', className, theme)}> <SkeletonContext.Provider value={skeleton}> - <TopArea area={skeleton.topArea} itemClassName={topAreaItemClassName} /> + <TopArea className="lc-workspace-top-area" area={skeleton.topArea} itemClassName={topAreaItemClassName} /> <div className="lc-workspace-workbench-body"> <LeftArea className="lc-workspace-left-area lc-left-area" area={skeleton.leftArea} /> <LeftFloatPane area={skeleton.leftFloatArea} /> From e7a3ba9e9aae210cb67c565c37038373731ea256 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 19 Oct 2023 14:19:47 +0800 Subject: [PATCH 289/469] chore(docs): publish docs 1.1.12 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 6c43fe1d0f..177226a287 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.11", + "version": "1.1.12", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 0f02080035923db7b5c39644ad4a41da0f56c892 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 20 Oct 2023 15:52:31 +0800 Subject: [PATCH 290/469] chore(release): publish 1.2.0 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 0bb34d1aee..b76ff2ae85 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.10", + "version": "1.2.0", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 1081aef8ff..c32b54a778 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.10", + "version": "1.2.0", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.1.10", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-editor-core": "1.2.0", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index e05002469e..bd4899c9a5 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.1.10", + "version": "1.2.0", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 2c8efccebf..0b23435f91 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.1.10", + "version": "1.2.0", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-editor-core": "1.1.10", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-editor-core": "1.2.0", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index a9521d486b..59ecb02610 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.10", + "version": "1.2.0", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-editor-core": "1.1.10", - "@alilc/lowcode-editor-skeleton": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-editor-core": "1.2.0", + "@alilc/lowcode-editor-skeleton": "1.2.0", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.10", - "@alilc/lowcode-plugin-outline-pane": "1.1.10", - "@alilc/lowcode-shell": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", - "@alilc/lowcode-workspace": "1.1.10", + "@alilc/lowcode-plugin-designer": "1.2.0", + "@alilc/lowcode-plugin-outline-pane": "1.2.0", + "@alilc/lowcode-shell": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-workspace": "1.2.0", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 116f98e5d5..f524eba845 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.10", + "version": "1.2.0", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 760d57a133..65c931ef37 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.1.10", + "version": "1.2.0", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-editor-core": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-editor-core": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 4a71eb26b8..e933128018 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.1.10", + "version": "1.2.0", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 90a9b7e08e..7d55b5ae6c 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.1.10", + "version": "1.2.0", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-renderer-core": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 8ff7f1f0a4..69a029578c 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.1.10", + "version": "1.2.0", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-rax-renderer": "1.1.10", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-rax-renderer": "1.2.0", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 1535cb2088..f1d8b5ea54 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.1.10", + "version": "1.2.0", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.1.10" + "@alilc/lowcode-renderer-core": "1.2.0" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index ffb8228dfd..a265c3e88f 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.1.10", + "version": "1.2.0", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-react-renderer": "1.1.10", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-react-renderer": "1.2.0", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 52b13b86c6..ecfd233809 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.1.10", + "version": "1.2.0", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 09768a06a7..884915877c 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.10", + "version": "1.2.0", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-editor-core": "1.1.10", - "@alilc/lowcode-editor-skeleton": "1.1.10", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", - "@alilc/lowcode-workspace": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-editor-core": "1.2.0", + "@alilc/lowcode-editor-skeleton": "1.2.0", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-workspace": "1.2.0", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index fe9cd51235..155242712a 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.10", + "version": "1.2.0", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index ecf6bff3c0..f9c0005b4d 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.10", + "version": "1.2.0", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.10", + "@alilc/lowcode-types": "1.2.0", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 8802691d60..7e662af378 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.10", + "version": "1.2.0", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-editor-core": "1.1.10", - "@alilc/lowcode-editor-skeleton": "1.1.10", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-editor-core": "1.2.0", + "@alilc/lowcode-editor-skeleton": "1.2.0", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 11ee97c6dafe1ecb60402488ad72b722005cda55 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 26 Oct 2023 11:24:17 +0800 Subject: [PATCH 291/469] fix: fixed the problem caused by component list being overwritten by Hoc --- packages/renderer-core/src/renderer/base.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 7b9562fcc6..1980734e43 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -615,9 +615,6 @@ export default function baseRendererFactory(): IBaseRenderComponent { }); }); - Comp = compWrapper(Comp, { baseRenderer: this, schema }); - components[schema.componentName] = Comp; - otherProps.ref = (ref: any) => { this.$(props.fieldId || props.ref, ref); // 收集ref const refProps = props.ref; @@ -701,9 +698,9 @@ export default function baseRendererFactory(): IBaseRenderComponent { */ get __componentHOCs(): IComponentConstruct[] { if (this.__designModeIsDesign) { - return [leafWrapper]; + return [leafWrapper, compWrapper]; } - return []; + return [compWrapper]; } __getSchemaChildrenVirtualDom = (schema: IPublicTypeNodeSchema | undefined, scope: any, Comp: any, condition = true) => { From 055ab68a4b110385d737c0aafd4362d9c86c96e4 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 26 Oct 2023 11:37:30 +0800 Subject: [PATCH 292/469] fix: fix document.onMountNode parameters --- packages/designer/src/document/document-model.ts | 9 ++++++++- packages/shell/src/model/document-model.ts | 9 +++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 9521fef383..edca8fd818 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -74,7 +74,6 @@ export interface IDocumentModel extends Omit<IPublicModelDocumentModel< 'onRemoveNode' | 'onChangeDetecting' | 'onChangeSelection' | - 'onMountNode' | 'onChangeNodeProp' | 'onImportSchema' | 'isDetectingNode' | @@ -414,6 +413,14 @@ export class DocumentModel implements IDocumentModel { return node ? !node.isPurged : false; } + onMountNode(fn: (payload: { node: INode }) => void) { + this.designer.editor.eventBus.on('node.add', fn as any); + + return () => { + this.designer.editor.eventBus.off('node.add', fn as any); + }; + } + /** * 根据 schema 创建一个节点 */ diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts index 2c5c7b632e..bd0ccaf75e 100644 --- a/packages/shell/src/model/document-model.ts +++ b/packages/shell/src/model/document-model.ts @@ -252,10 +252,11 @@ export class DocumentModel implements IPublicModelDocumentModel { * 当前 document 新增节点事件,此时节点已经挂载到 document 上 */ onMountNode(fn: (payload: { node: IPublicModelNode }) => void): IPublicTypeDisposable { - this[editorSymbol].eventBus.on('node.add', fn as any); - return () => { - this[editorSymbol].eventBus.off('node.add', fn as any); - }; + return this[documentSymbol].onMountNode(({ + node, + }) => { + fn({ node: ShellNode.create(node)! }); + }); } /** From b3b2a03642da21f4747108d1da77488f9655dcfc Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 27 Oct 2023 13:14:57 +0800 Subject: [PATCH 293/469] chore(release): publish 1.2.1 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index b76ff2ae85..8201f484d6 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.0", + "version": "1.2.1", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index c32b54a778..2f57c80c38 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.0", + "version": "1.2.1", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-editor-core": "1.2.1", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index bd4899c9a5..060f986ed3 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.0", + "version": "1.2.1", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 0b23435f91..0f55e637db 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.0", + "version": "1.2.1", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-editor-core": "1.2.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-editor-core": "1.2.1", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 59ecb02610..29ba8c36f6 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.0", + "version": "1.2.1", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-editor-core": "1.2.0", - "@alilc/lowcode-editor-skeleton": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-editor-core": "1.2.1", + "@alilc/lowcode-editor-skeleton": "1.2.1", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.0", - "@alilc/lowcode-plugin-outline-pane": "1.2.0", - "@alilc/lowcode-shell": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", - "@alilc/lowcode-workspace": "1.2.0", + "@alilc/lowcode-plugin-designer": "1.2.1", + "@alilc/lowcode-plugin-outline-pane": "1.2.1", + "@alilc/lowcode-shell": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-workspace": "1.2.1", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index f524eba845..cdf2928b56 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.0", + "version": "1.2.1", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 65c931ef37..9b64b0709f 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.0", + "version": "1.2.1", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-editor-core": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-editor-core": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index e933128018..8295094fe0 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.0", + "version": "1.2.1", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 7d55b5ae6c..ed7434b942 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.0", + "version": "1.2.1", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-renderer-core": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 69a029578c..383cc29895 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.0", + "version": "1.2.1", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-rax-renderer": "1.2.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-rax-renderer": "1.2.1", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index f1d8b5ea54..142e90ebb6 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.0", + "version": "1.2.1", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.0" + "@alilc/lowcode-renderer-core": "1.2.1" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index a265c3e88f..18b57e28fe 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.0", + "version": "1.2.1", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-react-renderer": "1.2.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-react-renderer": "1.2.1", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index ecfd233809..3d4e3c7e09 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.0", + "version": "1.2.1", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 884915877c..36ea05d7b1 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.0", + "version": "1.2.1", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-editor-core": "1.2.0", - "@alilc/lowcode-editor-skeleton": "1.2.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", - "@alilc/lowcode-workspace": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-editor-core": "1.2.1", + "@alilc/lowcode-editor-skeleton": "1.2.1", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-workspace": "1.2.1", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 155242712a..2d66d2f621 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.0", + "version": "1.2.1", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index f9c0005b4d..c2433f1521 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.0", + "version": "1.2.1", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-types": "1.2.1", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 7e662af378..a5d7d4ceae 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.0", + "version": "1.2.1", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-editor-core": "1.2.0", - "@alilc/lowcode-editor-skeleton": "1.2.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-editor-core": "1.2.1", + "@alilc/lowcode-editor-skeleton": "1.2.1", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 95a48e057f856201cb3cbf7c5046128da7e64df6 Mon Sep 17 00:00:00 2001 From: Rainke <woshihepeng520@163.com> Date: Wed, 1 Nov 2023 10:37:14 +0800 Subject: [PATCH 294/469] =?UTF-8?q?fix:=20import=20schema=20=E4=B9=8B?= =?UTF-8?q?=E5=90=8E=20cache=20=E5=88=A4=E6=96=AD=E9=94=99=E8=AF=AF(#2596)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/renderer-core/src/hoc/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/renderer-core/src/hoc/index.tsx b/packages/renderer-core/src/hoc/index.tsx index 3e7f5ec6a1..4851ea486f 100644 --- a/packages/renderer-core/src/hoc/index.tsx +++ b/packages/renderer-core/src/hoc/index.tsx @@ -49,7 +49,7 @@ function patchDidCatch(Comp: any, { baseRenderer }: Options) { } } -const cache = new Map(); +const cache = new Map<string, { Comp: any; WrapperComponent: any }>(); export function compWrapper(Comp: any, options: Options) { const { createElement, Component, forwardRef } = adapter.getRuntime(); @@ -62,8 +62,8 @@ export function compWrapper(Comp: any, options: Options) { return Comp; } - if (cache.has(options.schema.id)) { - return cache.get(options.schema.id); + if (cache.has(options.schema.id) && cache.get(options.schema.id)?.Comp === Comp) { + return cache.get(options.schema.id)?.WrapperComponent; } class Wrapper extends Component { @@ -82,7 +82,7 @@ export function compWrapper(Comp: any, options: Options) { Comp, ); - cache.set(options.schema.id, WrapperComponent); + cache.set(options.schema.id, { WrapperComponent, Comp }); return WrapperComponent; } From c5ba2f3ef1ce52f7a2fae9743a2cd11022563f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Fri, 3 Nov 2023 14:01:58 +0800 Subject: [PATCH 295/469] docs: update useEditor.md --- docs/docs/guide/create/useEditor.md | 56 ----------------------------- 1 file changed, 56 deletions(-) diff --git a/docs/docs/guide/create/useEditor.md b/docs/docs/guide/create/useEditor.md index cbb38f77de..8df4158a6c 100644 --- a/docs/docs/guide/create/useEditor.md +++ b/docs/docs/guide/create/useEditor.md @@ -105,8 +105,6 @@ sidebar_position: 0 ### 初始化低代码编辑器 -#### 方法 2.1 使用 init 进行初始化 - 正确引入后,我们可以直接通过 window 上的变量进行引用,如 `window.AliLowCodeEngine.init`。您可以直接通过此方式初始化低代码引擎: ```javascript @@ -144,59 +142,5 @@ init 的功能包括但不限于: > 本节中的低代码编辑器例子可以在 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) - -#### 方法 2.2 使用 skeletonCabin.Workbench 方式初始化 - -`init()` 内部会调用 `ReactDOM.render()` 函数,因此这样初始化的内容没有办法与外部的 React 组件进行通信,也就没有办法在一些自定义的 plugin 中获取 redux 上的全局数据等内容。 - -因此,这种场景下您可以通过 `skeletonCabin.Workbench` 进行初始化。 - -> 注:**不需要**同时使用 2.1 和 2.2 的方法。根据使用场景,当且只当有需要插件和外界进行一定通信时,才需要使用 2.2 提供的方法。 - - -```javascript -import React, { useState, useEffect } from 'react'; -import { project, plugins, common, skeleton } from '@alilc/lowcode-engine'; - -// 此处略去若干依赖引用 - -async function registerPlugins() { - // 此处略去若干插件注册 -} -function EditorView() { - /** 插件是否已初始化成功,因为必须要等插件初始化后才能渲染 Workbench */ - const [hasPluginInited, setHasPluginInited] = useState(false); - - useEffect(() => { - plugins.init().then(() => { - setHasPluginInited(true); - }).catch(err => console.error(err)); - }, []); - - if (!hasPluginInited) { - return null; - } - const Workbench = common.skeletonCabin.Workbench; - return <Workbench />; -} - -(async function main() { - await registerPlugins(); - config.setConfig({ - enableCondition: true, - enableCanvasLock: true, - supportVariableGlobally: true, - requestHandlersMap: { - fetch: createFetchHandler() - } - }); - - ReactDOM.render(<EditorView />, document.getElementById('lce-container')!); -})(); -``` - -> 本节中的低代码编辑器类似的例子可以在 demo 中找到:[https://github.com/alibaba/lowcode-demo/blob/main/demo-custom-initialization/src/index.tsx](https://github.com/alibaba/lowcode-demo/blob/main/demo-custom-initialization/src/index.tsx) - - ## 配置低代码编辑器 详见[低代码扩展简述](/site/docs/guide/expand/editor/summary)章节。 From c65c17f779fc38648e76dc033c19bffc85365a5c Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 3 Nov 2023 14:05:04 +0800 Subject: [PATCH 296/469] docs: publish docs 1.1.13 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 177226a287..bdc734c71e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.12", + "version": "1.1.13", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 97eb477746c95eab15dccc6ec728159e9edb19a3 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 7 Nov 2023 16:05:50 +0800 Subject: [PATCH 297/469] feat: update engine classes exports --- packages/engine/src/modules/classes.ts | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/packages/engine/src/modules/classes.ts b/packages/engine/src/modules/classes.ts index d68ea43de2..3b7627deb0 100644 --- a/packages/engine/src/modules/classes.ts +++ b/packages/engine/src/modules/classes.ts @@ -1,4 +1,4 @@ -import { +export { Project, Skeleton, DocumentModel, @@ -12,20 +12,5 @@ import { SimulatorHost, SkeletonItem, } from '@alilc/lowcode-shell'; -import { Node as InnerNode } from '@alilc/lowcode-designer'; +export { Node as InnerNode } from '@alilc/lowcode-designer'; -export default { - Project, - Skeleton, - DocumentModel, - Node, - NodeChildren, - History, - SettingPropEntry, - SettingTopEntry, - InnerNode, - Selection, - Prop, - SimulatorHost, - SkeletonItem, -}; From e3611dcf06a0a24b691fab00734ce4cecb501f25 Mon Sep 17 00:00:00 2001 From: keuby <knightchen@knx.com.cn> Date: Tue, 7 Nov 2023 17:20:13 +0800 Subject: [PATCH 298/469] feat(utils|types): add esmodule support for component meta resources (#2603) * feat(utils): support script type param for assest loader * feat(types): update AssestsJson type --- .../src/shell/type/remote-component-description.ts | 6 +++++- packages/utils/src/asset.ts | 10 +++++----- packages/utils/src/script.ts | 9 ++++++--- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/types/src/shell/type/remote-component-description.ts b/packages/types/src/shell/type/remote-component-description.ts index 7ba5324391..2337203657 100644 --- a/packages/types/src/shell/type/remote-component-description.ts +++ b/packages/types/src/shell/type/remote-component-description.ts @@ -1,17 +1,21 @@ +import { Asset } from '../../assets'; import { IPublicTypeComponentMetadata, IPublicTypeReference } from './'; /** * 远程物料描述 */ export interface IPublicTypeRemoteComponentDescription extends IPublicTypeComponentMetadata { + /** * 组件描述导出名字,可以通过 window[exportName] 获取到组件描述的 Object 内容; */ exportName?: string; + /** * 组件描述的资源链接; */ - url?: string; + url?: Asset; + /** * 组件 (库) 的 npm 信息; */ diff --git a/packages/utils/src/asset.ts b/packages/utils/src/asset.ts index ad05221248..3400f965b4 100644 --- a/packages/utils/src/asset.ts +++ b/packages/utils/src/asset.ts @@ -214,6 +214,8 @@ function parseAsset(scripts: any, styles: any, asset: Asset | undefined | null, } export class AssetLoader { + private stylePoints = new Map<string, StylePoint>(); + async load(asset: Asset) { const styles: any = {}; const scripts: any = {}; @@ -237,11 +239,9 @@ export class AssetLoader { await Promise.all( styleQueue.map(({ content, level, type, id }) => this.loadStyle(content, level!, type === AssetType.CSSUrl, id)), ); - await Promise.all(scriptQueue.map(({ content, type }) => this.loadScript(content, type === AssetType.JSUrl))); + await Promise.all(scriptQueue.map(({ content, type, scriptType }) => this.loadScript(content, type === AssetType.JSUrl, scriptType))); } - private stylePoints = new Map<string, StylePoint>(); - private loadStyle(content: string | undefined | null, level: AssetLevel, isUrl?: boolean, id?: string) { if (!content) { return; @@ -259,11 +259,11 @@ export class AssetLoader { return isUrl ? point.applyUrl(content) : point.applyText(content); } - private loadScript(content: string | undefined | null, isUrl?: boolean) { + private loadScript(content: string | undefined | null, isUrl?: boolean, scriptType?: string) { if (!content) { return; } - return isUrl ? load(content) : evaluate(content); + return isUrl ? load(content, scriptType) : evaluate(content, scriptType); } // todo 补充类型 diff --git a/packages/utils/src/script.ts b/packages/utils/src/script.ts index 7c772f03f9..25159b198c 100644 --- a/packages/utils/src/script.ts +++ b/packages/utils/src/script.ts @@ -1,14 +1,15 @@ import { createDefer } from './create-defer'; -export function evaluate(script: string) { +export function evaluate(script: string, scriptType?: string) { const scriptEl = document.createElement('script'); + scriptType && (scriptEl.type = scriptType); scriptEl.text = script; document.head.appendChild(scriptEl); document.head.removeChild(scriptEl); } -export function load(url: string) { - const node: any = document.createElement('script'); +export function load(url: string, scriptType?: string) { + const node = document.createElement('script'); // node.setAttribute('crossorigin', 'anonymous'); @@ -34,6 +35,8 @@ export function load(url: string) { // `async=false` is required to make sure all js resources execute sequentially. node.async = false; + scriptType && (node.type = scriptType); + document.head.appendChild(node); return i.promise(); From de8dab5cb38b6c1c248e35f9c445d24bdbf1babb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Thu, 9 Nov 2023 18:15:39 +0800 Subject: [PATCH 299/469] docs: update index.md --- docs/docs/article/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index 2f6f2cee3f..e62f8f9d87 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -1,4 +1,5 @@ # 官方文章 +- [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) @@ -10,4 +11,4 @@ - [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) \ No newline at end of file +- [2021/04/14 2B 领域下的低代码探索之路](https://mp.weixin.qq.com/s/HAxrMHLT43dPH488RiEIdw) From 9f78f8c54a697a2d7b4102474fd2c0eb9c956e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Thu, 9 Nov 2023 16:22:24 +0800 Subject: [PATCH 300/469] Update material.md --- docs/docs/api/material.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index 2bf99577cb..8b1214476b 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -340,6 +340,31 @@ function addonCombine(metadata: TransformedComponentMetadata) { 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 获取所有物料元数据管道函数 From f5c874b4bfb3c8859750911609f0b6bb3670d8bf Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 9 Nov 2023 11:30:02 +0800 Subject: [PATCH 301/469] chore(ignitor): change build config --- packages/ignitor/build.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ignitor/build.json b/packages/ignitor/build.json index a29eaf0266..218373247c 100644 --- a/packages/ignitor/build.json +++ b/packages/ignitor/build.json @@ -1,15 +1,15 @@ { "entry": { - "engine-core": "../engine/src/index.ts", - "react-simulator-renderer": "../react-simulator-renderer/src/index.ts", - "rax-simulator-renderer": "../rax-simulator-renderer/src/index.ts" + "AliLowCodeEngine": "../engine/src/index.ts", + "ReactSimulatorRenderer": "../react-simulator-renderer/src/index.ts", + "RaxSimulatorRenderer": "../rax-simulator-renderer/src/index.ts" }, "vendor": false, "devServer": { "liveReload": false, "hot": false }, - "library": "AliLowCodeEngine", + "library": "[name]", "publicPath": "/", "externals": { "react": "var window.React", From 3b14a79d1b474e538e8fae33ca38c9920ebebc31 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 10 Nov 2023 10:03:01 +0800 Subject: [PATCH 302/469] docs: publish docs 1.1.14 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index bdc734c71e..7479c7c84e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.13", + "version": "1.1.14", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 6320867cada5e0b851a2836aeadbb3b54f8f7f6d Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 10 Nov 2023 14:20:24 +0800 Subject: [PATCH 303/469] docs: update Node to IPublicModelNode --- docs/docs/api/configOptions.md | 2 +- docs/docs/api/model/dragon.md | 2 +- docs/docs/api/model/modal-nodes-manager.md | 4 ++-- docs/docs/api/model/node.md | 2 +- docs/docs/guide/expand/editor/pluginContextMenu.md | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md index 467655f68c..aaea28261d 100644 --- a/docs/docs/api/configOptions.md +++ b/docs/docs/api/configOptions.md @@ -113,7 +113,7 @@ config.set('enableCondition', false) 类型定义 ```typescript - focusNodeSelector?: (rootNode: Node) => Node; + focusNodeSelector?: (rootNode: IPublicModelNode) => Node; ``` #### supportVariableGlobally - 全局变量配置 diff --git a/docs/docs/api/model/dragon.md b/docs/docs/api/model/dragon.md index 995fd1b1f4..c6feca4329 100644 --- a/docs/docs/api/model/dragon.md +++ b/docs/docs/api/model/dragon.md @@ -101,7 +101,7 @@ from(shell: Element, boost: (e: MouseEvent) => IPublicTypeDragNodeDataObject | n * @param dragObject 拖拽对象 * @param boostEvent 拖拽初始时事件 */ -boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode): void; +boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: IPublicModelNode): void; ``` ### addSensor diff --git a/docs/docs/api/model/modal-nodes-manager.md b/docs/docs/api/model/modal-nodes-manager.md index fbab6a83a5..fead53f0a1 100644 --- a/docs/docs/api/model/modal-nodes-manager.md +++ b/docs/docs/api/model/modal-nodes-manager.md @@ -71,7 +71,7 @@ hideModalNodes(): void; /** * 设置指定节点为可见态 * set specific model node as visible - * @param node Node + * @param node IPublicModelNode */ setVisible(node: IPublicModelNode): void; ``` @@ -86,7 +86,7 @@ setVisible(node: IPublicModelNode): void; /** * 设置指定节点为不可见态 * set specific model node as invisible - * @param node Node + * @param node IPublicModelNode */ setInvisible(node: IPublicModelNode): void; ``` diff --git a/docs/docs/api/model/node.md b/docs/docs/api/model/node.md index 697eefd088..43de96a33d 100644 --- a/docs/docs/api/model/node.md +++ b/docs/docs/api/model/node.md @@ -673,6 +673,6 @@ getRGL(): { isRGLContainerNode: boolean; isRGLNode: boolean; isRGL: boolean; - rglNode: Node | null; + rglNode: IPublicModelNode | null; } ``` \ No newline at end of file diff --git a/docs/docs/guide/expand/editor/pluginContextMenu.md b/docs/docs/guide/expand/editor/pluginContextMenu.md index cd293b73e7..962c913e7e 100644 --- a/docs/docs/guide/expand/editor/pluginContextMenu.md +++ b/docs/docs/guide/expand/editor/pluginContextMenu.md @@ -12,7 +12,7 @@ sidebar_position: 6 ```typescript import { plugins } from '@alilc/lowcode-engine'; -import { IPublicModelPluginContext } from '@alilc/lowcode-types'; +import { IPublicModelPluginContext, IPublicModelNode } from '@alilc/lowcode-types'; import { Icon, Message } from '@alifd/next'; const addHelloAction = (ctx: IPublicModelPluginContext) => { @@ -23,11 +23,11 @@ const addHelloAction = (ctx: IPublicModelPluginContext) => { content: { icon: <Icon type="atm" />, title: 'hello', - action(node: Node) { + action(node: IPublicModelNode) { Message.show('Welcome to Low-Code engine'); }, }, - condition: (node: Node) => { + condition: (node: IPublicModelNode) => { return node.componentMeta.componentName === 'NextTable'; }, important: true, From d64c7d56dfc5ac67be56039a124ae897555569de Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 13 Nov 2023 12:41:45 +0800 Subject: [PATCH 304/469] chore(release): publish 1.2.2 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 8201f484d6..34be89faa8 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.1", + "version": "1.2.2", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 2f57c80c38..69a402ed22 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.1", + "version": "1.2.2", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.1", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-editor-core": "1.2.2", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 060f986ed3..de9d30bc8b 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.1", + "version": "1.2.2", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 0f55e637db..fe2d0d43ff 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.1", + "version": "1.2.2", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-editor-core": "1.2.1", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.2", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 29ba8c36f6..3ea47f79da 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.1", + "version": "1.2.2", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-editor-core": "1.2.1", - "@alilc/lowcode-editor-skeleton": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.2", + "@alilc/lowcode-editor-skeleton": "1.2.2", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.1", - "@alilc/lowcode-plugin-outline-pane": "1.2.1", - "@alilc/lowcode-shell": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", - "@alilc/lowcode-workspace": "1.2.1", + "@alilc/lowcode-plugin-designer": "1.2.2", + "@alilc/lowcode-plugin-outline-pane": "1.2.2", + "@alilc/lowcode-shell": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-workspace": "1.2.2", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index cdf2928b56..d737a7c868 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.1", + "version": "1.2.2", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 9b64b0709f..fe653568bb 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.1", + "version": "1.2.2", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-editor-core": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 8295094fe0..2540ca5ad4 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.1", + "version": "1.2.2", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index ed7434b942..60ea0c6981 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.1", + "version": "1.2.2", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-renderer-core": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 383cc29895..520ff32c89 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.1", + "version": "1.2.2", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-rax-renderer": "1.2.1", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-rax-renderer": "1.2.2", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 142e90ebb6..a35039fc3c 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.1", + "version": "1.2.2", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.1" + "@alilc/lowcode-renderer-core": "1.2.2" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 18b57e28fe..413b1825f8 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.1", + "version": "1.2.2", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-react-renderer": "1.2.1", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-react-renderer": "1.2.2", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 3d4e3c7e09..3b96ef40b3 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.1", + "version": "1.2.2", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 36ea05d7b1..7e20192352 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.1", + "version": "1.2.2", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-editor-core": "1.2.1", - "@alilc/lowcode-editor-skeleton": "1.2.1", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", - "@alilc/lowcode-workspace": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.2", + "@alilc/lowcode-editor-skeleton": "1.2.2", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-workspace": "1.2.2", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 2d66d2f621..c4fa290036 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.1", + "version": "1.2.2", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index c2433f1521..fab7828f13 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.1", + "version": "1.2.2", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-types": "1.2.2", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index a5d7d4ceae..4724323797 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.1", + "version": "1.2.2", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-editor-core": "1.2.1", - "@alilc/lowcode-editor-skeleton": "1.2.1", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.2", + "@alilc/lowcode-editor-skeleton": "1.2.2", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 04adda02fb415e2f56e6ee3e7f20652c2de20668 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 13 Nov 2023 12:30:47 +0800 Subject: [PATCH 305/469] =?UTF-8?q?docs:=20add=20faq-Slot=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E6=B8=B2=E6=9F=93=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/faq/faq023.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 docs/docs/faq/faq023.md diff --git a/docs/docs/faq/faq023.md b/docs/docs/faq/faq023.md new file mode 100644 index 0000000000..e03f7118e0 --- /dev/null +++ b/docs/docs/faq/faq023.md @@ -0,0 +1,31 @@ +--- +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) + +--- From 938c71fb462b37fb154e1b8fdfaa0319d4f0f075 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 13 Nov 2023 12:57:02 +0800 Subject: [PATCH 306/469] chore(docs): publish docs 1.1.15 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 7479c7c84e..27d1a17d04 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.14", + "version": "1.1.15", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 621245393f5ca405d86c90501e51288f2f324d5c Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 13 Nov 2023 12:25:50 +0800 Subject: [PATCH 307/469] test(utils): add ut to package/utils --- packages/utils/jest.config.js | 1 + packages/utils/jest.setup.js | 1 + packages/utils/package.json | 7 +- .../check-types/is-action-content-object.ts | 3 +- .../utils/src/check-types/is-custom-view.ts | 6 +- .../src/check-types/is-drag-any-object.ts | 6 +- .../check-types/is-drag-node-data-object.ts | 6 +- .../src/check-types/is-drag-node-object.ts | 6 +- .../src/check-types/is-dynamic-setter.ts | 7 +- packages/utils/src/check-types/is-function.ts | 3 + .../utils/src/check-types/is-i18n-data.ts | 11 +- .../utils/src/check-types/is-isfunction.ts | 24 +- packages/utils/src/check-types/is-jsblock.ts | 9 +- .../utils/src/check-types/is-jsexpression.ts | 6 +- packages/utils/src/check-types/is-jsslot.ts | 6 +- .../is-location-children-detail.ts | 6 +- .../utils/src/check-types/is-location-data.ts | 6 +- .../check-types/is-lowcode-project-schema.ts | 15 +- .../utils/src/check-types/is-node-schema.ts | 6 +- packages/utils/src/check-types/is-node.ts | 6 +- packages/utils/src/check-types/is-object.ts | 3 + .../check-types/is-procode-component-type.ts | 6 +- .../src/check-types/is-project-schema.ts | 8 +- .../utils/src/check-types/is-setter-config.ts | 7 +- .../utils/src/check-types/is-setting-field.ts | 9 +- .../utils/src/clone-enumerable-property.ts | 4 +- packages/utils/src/is-object.ts | 2 +- packages/utils/src/is-react.ts | 38 +- packages/utils/src/logger.ts | 4 +- packages/utils/src/misc.ts | 15 +- packages/utils/src/navtive-selection.ts | 3 +- packages/utils/src/script.ts | 5 +- packages/utils/src/svg-icon.tsx | 2 +- .../src/__snapshots__/is-react.test.tsx.snap | 10 + .../build-components/buildComponents.test.ts | 342 ---------- .../build-components/buildComponents.test.tsx | 616 ++++++++++++++++++ .../is-action-content-object.test.ts | 20 + .../src/check-types/is-custom-view.test.tsx | 26 + .../test/src/check-types/is-dom-text.test.ts | 13 + .../check-types/is-drag-any-object.test.ts | 32 + .../is-drag-node-data-object.test.ts | 29 + .../check-types/is-drag-node-object.test.ts | 36 + .../src/check-types/is-dynamic-setter.test.ts | 28 + .../test/src/check-types/is-i18n-data.test.ts | 27 + .../src/check-types/is-isfunction.test.ts | 61 ++ .../test/src/check-types/is-jsblock.test.ts | 22 + .../src/check-types/is-jsexpression.test.ts | 39 ++ .../test/src/check-types/is-jsslot.test.ts | 37 ++ .../is-location-children-detail.test.ts | 27 + .../src/check-types/is-location-data.test.ts | 44 ++ .../is-lowcode-component-type.test.ts | 21 + .../is-lowcode-project-schema.test.ts | 42 ++ .../src/check-types/is-node-schema.test.ts | 43 ++ .../test/src/check-types/is-node.test.ts | 19 + .../is-procode-component-type.test.ts | 13 + .../src/check-types/is-project-schema.test.ts | 28 + .../src/check-types/is-setter-config.test.ts | 26 + .../src/check-types/is-setting-field.test.ts | 18 + .../src/check-types/is-title-config.test.ts | 18 + packages/utils/test/src/clone-deep.test.ts | 30 + .../src/clone-enumerable-property.test.ts | 30 + .../utils/test/src/create-content.test.tsx | 38 ++ packages/utils/test/src/create-defer.test.ts | 16 + packages/utils/test/src/is-object.test.ts | 45 ++ packages/utils/test/src/is-react.test.ts | 38 -- packages/utils/test/src/is-react.test.tsx | 316 +++++++++ packages/utils/test/src/is-shaken.test.ts | 45 ++ packages/utils/test/src/misc.test.ts | 319 ++++++++- .../utils/test/src/navtive-selection.test.ts | 18 + packages/utils/test/src/schema.test.ts | 130 +++- packages/utils/test/src/script.test.ts | 47 ++ packages/utils/test/src/svg-icon.test.tsx | 35 + .../test/src/transaction-manager.test.ts | 58 ++ packages/utils/test/src/unique-id.test.ts | 11 + 74 files changed, 2621 insertions(+), 439 deletions(-) create mode 100644 packages/utils/jest.setup.js create mode 100644 packages/utils/src/check-types/is-function.ts create mode 100644 packages/utils/src/check-types/is-object.ts create mode 100644 packages/utils/test/src/__snapshots__/is-react.test.tsx.snap delete mode 100644 packages/utils/test/src/build-components/buildComponents.test.ts create mode 100644 packages/utils/test/src/build-components/buildComponents.test.tsx create mode 100644 packages/utils/test/src/check-types/is-action-content-object.test.ts create mode 100644 packages/utils/test/src/check-types/is-custom-view.test.tsx create mode 100644 packages/utils/test/src/check-types/is-dom-text.test.ts create mode 100644 packages/utils/test/src/check-types/is-drag-any-object.test.ts create mode 100644 packages/utils/test/src/check-types/is-drag-node-data-object.test.ts create mode 100644 packages/utils/test/src/check-types/is-drag-node-object.test.ts create mode 100644 packages/utils/test/src/check-types/is-dynamic-setter.test.ts create mode 100644 packages/utils/test/src/check-types/is-i18n-data.test.ts create mode 100644 packages/utils/test/src/check-types/is-isfunction.test.ts create mode 100644 packages/utils/test/src/check-types/is-jsblock.test.ts create mode 100644 packages/utils/test/src/check-types/is-jsexpression.test.ts create mode 100644 packages/utils/test/src/check-types/is-jsslot.test.ts create mode 100644 packages/utils/test/src/check-types/is-location-children-detail.test.ts create mode 100644 packages/utils/test/src/check-types/is-location-data.test.ts create mode 100644 packages/utils/test/src/check-types/is-lowcode-component-type.test.ts create mode 100644 packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts create mode 100644 packages/utils/test/src/check-types/is-node-schema.test.ts create mode 100644 packages/utils/test/src/check-types/is-node.test.ts create mode 100644 packages/utils/test/src/check-types/is-procode-component-type.test.ts create mode 100644 packages/utils/test/src/check-types/is-project-schema.test.ts create mode 100644 packages/utils/test/src/check-types/is-setter-config.test.ts create mode 100644 packages/utils/test/src/check-types/is-setting-field.test.ts create mode 100644 packages/utils/test/src/check-types/is-title-config.test.ts create mode 100644 packages/utils/test/src/clone-deep.test.ts create mode 100644 packages/utils/test/src/clone-enumerable-property.test.ts create mode 100644 packages/utils/test/src/create-content.test.tsx create mode 100644 packages/utils/test/src/create-defer.test.ts create mode 100644 packages/utils/test/src/is-object.test.ts delete mode 100644 packages/utils/test/src/is-react.test.ts create mode 100644 packages/utils/test/src/is-react.test.tsx create mode 100644 packages/utils/test/src/is-shaken.test.ts create mode 100644 packages/utils/test/src/navtive-selection.test.ts create mode 100644 packages/utils/test/src/script.test.ts create mode 100644 packages/utils/test/src/svg-icon.test.tsx create mode 100644 packages/utils/test/src/transaction-manager.test.ts create mode 100644 packages/utils/test/src/unique-id.test.ts diff --git a/packages/utils/jest.config.js b/packages/utils/jest.config.js index 328ea622eb..0631fa00c9 100644 --- a/packages/utils/jest.config.js +++ b/packages/utils/jest.config.js @@ -11,6 +11,7 @@ const jestConfig = { '!**/node_modules/**', '!**/vendor/**', ], + setupFilesAfterEnv: ['./jest.setup.js'], }; // 只对本仓库内的 pkg 做 mapping diff --git a/packages/utils/jest.setup.js b/packages/utils/jest.setup.js new file mode 100644 index 0000000000..7b0828bfa8 --- /dev/null +++ b/packages/utils/jest.setup.js @@ -0,0 +1 @@ +import '@testing-library/jest-dom'; diff --git a/packages/utils/package.json b/packages/utils/package.json index fab7828f13..af76e9e2f6 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -9,7 +9,7 @@ "main": "lib/index.js", "module": "es/index.js", "scripts": { - "test": "build-scripts test --config build.test.json", + "test": "build-scripts test --config build.test.json --jest-coverage", "build": "build-scripts build" }, "dependencies": { @@ -21,8 +21,11 @@ }, "devDependencies": { "@alib/build-scripts": "^0.1.18", + "@testing-library/jest-dom": "^6.1.4", + "@testing-library/react": "^11.2.7", "@types/node": "^13.7.1", - "@types/react": "^16" + "@types/react": "^16", + "react-dom": "^16.14.0" }, "publishConfig": { "access": "public", diff --git a/packages/utils/src/check-types/is-action-content-object.ts b/packages/utils/src/check-types/is-action-content-object.ts index 4e9a6545a4..8fe31b5bd7 100644 --- a/packages/utils/src/check-types/is-action-content-object.ts +++ b/packages/utils/src/check-types/is-action-content-object.ts @@ -1,5 +1,6 @@ import { IPublicTypeActionContentObject } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isActionContentObject(obj: any): obj is IPublicTypeActionContentObject { - return obj && typeof obj === 'object'; + return isObject(obj); } diff --git a/packages/utils/src/check-types/is-custom-view.ts b/packages/utils/src/check-types/is-custom-view.ts index 89ea9f10e4..4cf921d9c5 100644 --- a/packages/utils/src/check-types/is-custom-view.ts +++ b/packages/utils/src/check-types/is-custom-view.ts @@ -2,7 +2,9 @@ import { isValidElement } from 'react'; import { isReactComponent } from '../is-react'; import { IPublicTypeCustomView } from '@alilc/lowcode-types'; - export function isCustomView(obj: any): obj is IPublicTypeCustomView { - return obj && (isValidElement(obj) || isReactComponent(obj)); + if (!obj) { + return false; + } + return isValidElement(obj) || isReactComponent(obj); } diff --git a/packages/utils/src/check-types/is-drag-any-object.ts b/packages/utils/src/check-types/is-drag-any-object.ts index 34f140f4a5..8711b4e333 100644 --- a/packages/utils/src/check-types/is-drag-any-object.ts +++ b/packages/utils/src/check-types/is-drag-any-object.ts @@ -1,5 +1,9 @@ import { IPublicEnumDragObjectType } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isDragAnyObject(obj: any): boolean { - return obj && obj.type !== IPublicEnumDragObjectType.NodeData && obj.type !== IPublicEnumDragObjectType.Node; + if (!isObject(obj)) { + return false; + } + return obj.type !== IPublicEnumDragObjectType.NodeData && obj.type !== IPublicEnumDragObjectType.Node; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-drag-node-data-object.ts b/packages/utils/src/check-types/is-drag-node-data-object.ts index 4b08f67fa6..aa62f5b1c9 100644 --- a/packages/utils/src/check-types/is-drag-node-data-object.ts +++ b/packages/utils/src/check-types/is-drag-node-data-object.ts @@ -1,5 +1,9 @@ import { IPublicEnumDragObjectType, IPublicTypeDragNodeDataObject } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isDragNodeDataObject(obj: any): obj is IPublicTypeDragNodeDataObject { - return obj && obj.type === IPublicEnumDragObjectType.NodeData; + if (!isObject(obj)) { + return false; + } + return obj.type === IPublicEnumDragObjectType.NodeData; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-drag-node-object.ts b/packages/utils/src/check-types/is-drag-node-object.ts index 1b6c131e93..3a29ec967f 100644 --- a/packages/utils/src/check-types/is-drag-node-object.ts +++ b/packages/utils/src/check-types/is-drag-node-object.ts @@ -1,5 +1,9 @@ import { IPublicEnumDragObjectType, IPublicModelNode, IPublicTypeDragNodeObject } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isDragNodeObject<Node = IPublicModelNode>(obj: any): obj is IPublicTypeDragNodeObject<Node> { - return obj && obj.type === IPublicEnumDragObjectType.Node; + if (!isObject(obj)) { + return false; + } + return obj.type === IPublicEnumDragObjectType.Node; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-dynamic-setter.ts b/packages/utils/src/check-types/is-dynamic-setter.ts index 43a8cb8beb..35f8ff3892 100644 --- a/packages/utils/src/check-types/is-dynamic-setter.ts +++ b/packages/utils/src/check-types/is-dynamic-setter.ts @@ -1,7 +1,10 @@ +import { isFunction } from '../is-function'; import { isReactClass } from '../is-react'; import { IPublicTypeDynamicSetter } from '@alilc/lowcode-types'; - export function isDynamicSetter(obj: any): obj is IPublicTypeDynamicSetter { - return obj && typeof obj === 'function' && !isReactClass(obj); + if (!isFunction(obj)) { + return false; + } + return !isReactClass(obj); } diff --git a/packages/utils/src/check-types/is-function.ts b/packages/utils/src/check-types/is-function.ts new file mode 100644 index 0000000000..d7d3b4c27d --- /dev/null +++ b/packages/utils/src/check-types/is-function.ts @@ -0,0 +1,3 @@ +export function isFunction(obj: any): obj is Function { + return obj && typeof obj === 'function'; +} \ No newline at end of file diff --git a/packages/utils/src/check-types/is-i18n-data.ts b/packages/utils/src/check-types/is-i18n-data.ts index f4a7b6f7aa..793295d240 100644 --- a/packages/utils/src/check-types/is-i18n-data.ts +++ b/packages/utils/src/check-types/is-i18n-data.ts @@ -1,8 +1,9 @@ - -// type checks - -import { IPublicTypeI18nData } from "@alilc/lowcode-types"; +import { IPublicTypeI18nData } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isI18nData(obj: any): obj is IPublicTypeI18nData { - return obj && obj.type === 'i18n'; + if (!isObject(obj)) { + return false; + } + return obj.type === 'i18n'; } diff --git a/packages/utils/src/check-types/is-isfunction.ts b/packages/utils/src/check-types/is-isfunction.ts index a6d5da9008..64b8676637 100644 --- a/packages/utils/src/check-types/is-isfunction.ts +++ b/packages/utils/src/check-types/is-isfunction.ts @@ -1,10 +1,26 @@ +import { IPublicTypeJSFunction } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; + +interface InnerJsFunction { + type: 'JSExpression'; + source: string; + value: string; + extType: 'function'; +} + /** * 内部版本 的 { type: 'JSExpression', source: '', value: '', extType: 'function' } 能力上等同于 JSFunction */ -export function isInnerJsFunction(data: any) { - return data && data.type === 'JSExpression' && data.extType === 'function'; +export function isInnerJsFunction(data: any): data is InnerJsFunction { + if (!isObject(data)) { + return false; + } + return data.type === 'JSExpression' && data.extType === 'function'; } -export function isJSFunction(data: any): boolean { - return typeof data === 'object' && data && data.type === 'JSFunction' || isInnerJsFunction(data); +export function isJSFunction(data: any): data is IPublicTypeJSFunction { + if (!isObject(data)) { + return false; + } + return data.type === 'JSFunction' || isInnerJsFunction(data); } diff --git a/packages/utils/src/check-types/is-jsblock.ts b/packages/utils/src/check-types/is-jsblock.ts index 4c3b28f525..858f5c09cd 100644 --- a/packages/utils/src/check-types/is-jsblock.ts +++ b/packages/utils/src/check-types/is-jsblock.ts @@ -1,4 +1,9 @@ +import { IPublicTypeJSBlock } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; -export function isJSBlock(data: any): boolean { - return data && data.type === 'JSBlock'; +export function isJSBlock(data: any): data is IPublicTypeJSBlock { + if (!isObject(data)) { + return false; + } + return data.type === 'JSBlock'; } diff --git a/packages/utils/src/check-types/is-jsexpression.ts b/packages/utils/src/check-types/is-jsexpression.ts index 949d0f00da..16b8f4ac2a 100644 --- a/packages/utils/src/check-types/is-jsexpression.ts +++ b/packages/utils/src/check-types/is-jsexpression.ts @@ -1,4 +1,5 @@ import { IPublicTypeJSExpression } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; /** * 为了避免把 { type: 'JSExpression', extType: 'function' } 误判为表达式,故增加如下逻辑。 @@ -11,5 +12,8 @@ import { IPublicTypeJSExpression } from '@alilc/lowcode-types'; * @returns */ export function isJSExpression(data: any): data is IPublicTypeJSExpression { - return data && data.type === 'JSExpression' && data.extType !== 'function'; + if (!isObject(data)) { + return false; + } + return data.type === 'JSExpression' && data.extType !== 'function'; } diff --git a/packages/utils/src/check-types/is-jsslot.ts b/packages/utils/src/check-types/is-jsslot.ts index 1a8f09def5..1fb1d819d7 100644 --- a/packages/utils/src/check-types/is-jsslot.ts +++ b/packages/utils/src/check-types/is-jsslot.ts @@ -1,5 +1,9 @@ import { IPublicTypeJSSlot } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isJSSlot(data: any): data is IPublicTypeJSSlot { - return data && data.type === 'JSSlot'; + if (!isObject(data)) { + return false; + } + return data.type === 'JSSlot'; } diff --git a/packages/utils/src/check-types/is-location-children-detail.ts b/packages/utils/src/check-types/is-location-children-detail.ts index c6d2819d30..cc093c4e4a 100644 --- a/packages/utils/src/check-types/is-location-children-detail.ts +++ b/packages/utils/src/check-types/is-location-children-detail.ts @@ -1,5 +1,9 @@ import { IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isLocationChildrenDetail(obj: any): obj is IPublicTypeLocationChildrenDetail { - return obj && obj.type === IPublicTypeLocationDetailType.Children; + if (!isObject(obj)) { + return false; + } + return obj.type === IPublicTypeLocationDetailType.Children; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-location-data.ts b/packages/utils/src/check-types/is-location-data.ts index 8bb3103461..dabd493fa8 100644 --- a/packages/utils/src/check-types/is-location-data.ts +++ b/packages/utils/src/check-types/is-location-data.ts @@ -1,5 +1,9 @@ import { IPublicTypeLocationData } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isLocationData(obj: any): obj is IPublicTypeLocationData { - return obj && obj.target && obj.detail; + if (!isObject(obj)) { + return false; + } + return 'target' in obj && 'detail' in obj; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-lowcode-project-schema.ts b/packages/utils/src/check-types/is-lowcode-project-schema.ts index 0fffaea2fc..230911f0f3 100644 --- a/packages/utils/src/check-types/is-lowcode-project-schema.ts +++ b/packages/utils/src/check-types/is-lowcode-project-schema.ts @@ -1,6 +1,15 @@ -import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from "@alilc/lowcode-types"; -import { isComponentSchema } from "./is-component-schema"; +import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from '@alilc/lowcode-types'; +import { isComponentSchema } from './is-component-schema'; +import { isObject } from '../is-object'; export function isLowcodeProjectSchema(data: any): data is IPublicTypeProjectSchema<IPublicTypeComponentSchema> { - return data && data.componentsTree && data.componentsTree.length && isComponentSchema(data.componentsTree[0]); + if (!isObject(data)) { + return false; + } + + if (!('componentsTree' in data) || data.componentsTree.length === 0) { + return false; + } + + return isComponentSchema(data.componentsTree[0]); } diff --git a/packages/utils/src/check-types/is-node-schema.ts b/packages/utils/src/check-types/is-node-schema.ts index bfc3ff3f2b..253c05a080 100644 --- a/packages/utils/src/check-types/is-node-schema.ts +++ b/packages/utils/src/check-types/is-node-schema.ts @@ -1,5 +1,9 @@ import { IPublicTypeNodeSchema } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isNodeSchema(data: any): data is IPublicTypeNodeSchema { - return data && data.componentName && !data.isNode; + if (!isObject(data)) { + return false; + } + return 'componentName' in data && !data.isNode; } diff --git a/packages/utils/src/check-types/is-node.ts b/packages/utils/src/check-types/is-node.ts index 14c2e2f74e..b4690ddff9 100644 --- a/packages/utils/src/check-types/is-node.ts +++ b/packages/utils/src/check-types/is-node.ts @@ -1,5 +1,9 @@ import { IPublicModelNode } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isNode<Node = IPublicModelNode>(node: any): node is Node { - return node && node.isNode; + if (!isObject(node)) { + return false; + } + return node.isNode; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-object.ts b/packages/utils/src/check-types/is-object.ts new file mode 100644 index 0000000000..56ceb7d979 --- /dev/null +++ b/packages/utils/src/check-types/is-object.ts @@ -0,0 +1,3 @@ +export function isObject(obj: any): boolean { + return obj && typeof obj === 'object'; +} \ No newline at end of file diff --git a/packages/utils/src/check-types/is-procode-component-type.ts b/packages/utils/src/check-types/is-procode-component-type.ts index 5c768dd943..46618dcd5a 100644 --- a/packages/utils/src/check-types/is-procode-component-type.ts +++ b/packages/utils/src/check-types/is-procode-component-type.ts @@ -1,6 +1,10 @@ import { IPublicTypeComponentMap, IPublicTypeProCodeComponent } from '@alilc/lowcode-types'; - +import { isObject } from '../is-object'; export function isProCodeComponentType(desc: IPublicTypeComponentMap): desc is IPublicTypeProCodeComponent { + if (!isObject(desc)) { + return false; + } + return 'package' in desc; } diff --git a/packages/utils/src/check-types/is-project-schema.ts b/packages/utils/src/check-types/is-project-schema.ts index b228d481e0..d217acd9ee 100644 --- a/packages/utils/src/check-types/is-project-schema.ts +++ b/packages/utils/src/check-types/is-project-schema.ts @@ -1,5 +1,9 @@ -import { IPublicTypeProjectSchema } from "@alilc/lowcode-types"; +import { IPublicTypeProjectSchema } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isProjectSchema(data: any): data is IPublicTypeProjectSchema { - return data && data.componentsTree; + if (!isObject(data)) { + return false; + } + return 'componentsTree' in data; } diff --git a/packages/utils/src/check-types/is-setter-config.ts b/packages/utils/src/check-types/is-setter-config.ts index d631d237f1..98d835f32c 100644 --- a/packages/utils/src/check-types/is-setter-config.ts +++ b/packages/utils/src/check-types/is-setter-config.ts @@ -1,7 +1,10 @@ import { IPublicTypeSetterConfig } from '@alilc/lowcode-types'; import { isCustomView } from './is-custom-view'; - +import { isObject } from '../is-object'; export function isSetterConfig(obj: any): obj is IPublicTypeSetterConfig { - return obj && typeof obj === 'object' && 'componentName' in obj && !isCustomView(obj); + if (!isObject(obj)) { + return false; + } + return 'componentName' in obj && !isCustomView(obj); } diff --git a/packages/utils/src/check-types/is-setting-field.ts b/packages/utils/src/check-types/is-setting-field.ts index 67a183a959..0d6e21d848 100644 --- a/packages/utils/src/check-types/is-setting-field.ts +++ b/packages/utils/src/check-types/is-setting-field.ts @@ -1,5 +1,10 @@ -import { IPublicModelSettingField } from "@alilc/lowcode-types"; +import { IPublicModelSettingField } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isSettingField(obj: any): obj is IPublicModelSettingField { - return obj && obj.isSettingField; + if (!isObject(obj)) { + return false; + } + + return 'isSettingField' in obj && obj.isSettingField; } diff --git a/packages/utils/src/clone-enumerable-property.ts b/packages/utils/src/clone-enumerable-property.ts index 414f8dccdd..eb09e177fc 100644 --- a/packages/utils/src/clone-enumerable-property.ts +++ b/packages/utils/src/clone-enumerable-property.ts @@ -11,8 +11,8 @@ const excludePropertyNames = [ 'arguments', ]; -export function cloneEnumerableProperty(target: any, origin: any) { - const compExtraPropertyNames = Object.keys(origin).filter(d => !excludePropertyNames.includes(d)); +export function cloneEnumerableProperty(target: any, origin: any, excludes = excludePropertyNames) { + const compExtraPropertyNames = Object.keys(origin).filter(d => !excludes.includes(d)); compExtraPropertyNames.forEach((d: string) => { (target as any)[d] = origin[d]; diff --git a/packages/utils/src/is-object.ts b/packages/utils/src/is-object.ts index 50b580e5a1..c8d764458b 100644 --- a/packages/utils/src/is-object.ts +++ b/packages/utils/src/is-object.ts @@ -1,4 +1,4 @@ -export function isObject(value: any): value is Record<string, unknown> { +export function isObject(value: any): value is Record<string, any> { return value !== null && typeof value === 'object'; } diff --git a/packages/utils/src/is-react.ts b/packages/utils/src/is-react.ts index b19f043f14..1d6c939ea1 100644 --- a/packages/utils/src/is-react.ts +++ b/packages/utils/src/is-react.ts @@ -2,27 +2,49 @@ import { ComponentClass, Component, FunctionComponent, ComponentType, createElem import { cloneEnumerableProperty } from './clone-enumerable-property'; const hasSymbol = typeof Symbol === 'function' && Symbol.for; -const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; -const REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; +export const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; +export const REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; export function isReactClass(obj: any): obj is ComponentClass<any> { - return obj && obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component); + if (!obj) { + return false; + } + if (obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component)) { + return true; + } + return false; } export function acceptsRef(obj: any): boolean { - return obj?.prototype?.isReactComponent || isForwardOrMemoForward(obj); + if (!obj) { + return false; + } + if (obj?.prototype?.isReactComponent || isForwardOrMemoForward(obj)) { + return true; + } + + return false; } export function isForwardRefType(obj: any): boolean { - return obj?.$$typeof && obj?.$$typeof === REACT_FORWARD_REF_TYPE; + if (!obj || !obj?.$$typeof) { + return false; + } + return obj?.$$typeof === REACT_FORWARD_REF_TYPE; } -function isMemoType(obj: any): boolean { - return obj?.$$typeof && obj.$$typeof === REACT_MEMO_TYPE; +export function isMemoType(obj: any): boolean { + if (!obj || !obj?.$$typeof) { + return false; + } + return obj.$$typeof === REACT_MEMO_TYPE; } export function isForwardOrMemoForward(obj: any): boolean { - return obj?.$$typeof && ( + if (!obj || !obj?.$$typeof) { + return false; + } + return ( // React.forwardRef(..) isForwardRefType(obj) || // React.memo(React.forwardRef(..)) diff --git a/packages/utils/src/logger.ts b/packages/utils/src/logger.ts index 4c8f375ecd..3eb43eedbe 100644 --- a/packages/utils/src/logger.ts +++ b/packages/utils/src/logger.ts @@ -88,7 +88,7 @@ const shouldOutput = ( const output = (logLevel: string, bizName: string) => { return (...args: any[]) => { - return outputFunction[logLevel].apply(console, getLogArgs(args, bizName, logLevel)); + return outputFunction[logLevel]?.apply(console, getLogArgs(args, bizName, logLevel)); }; }; @@ -142,7 +142,6 @@ const defaultOptions: Options = { bizName: '*', }; - class Logger { bizName: string; targetBizName: string; @@ -192,7 +191,6 @@ class Logger { } } - export { Logger }; export function getLogger(config: { level: Level; bizName: string }): Logger { diff --git a/packages/utils/src/misc.ts b/packages/utils/src/misc.ts index 89f121065b..28833ef321 100644 --- a/packages/utils/src/misc.ts +++ b/packages/utils/src/misc.ts @@ -2,6 +2,9 @@ import { isI18NObject } from './is-object'; import { get } from 'lodash'; import { IPublicEnumTransformStage, IPublicModelComponentMeta } from '@alilc/lowcode-types'; +import { Logger } from './logger'; + +const logger = new Logger({ level: 'warn', bizName: 'utils' }); interface Variable { type: 'variable'; @@ -10,7 +13,10 @@ interface Variable { } export function isVariable(obj: any): obj is Variable { - return obj && obj.type === 'variable'; + if (!obj || typeof obj !== 'object') { + return false; + } + return obj.type === 'variable'; } export function isUseI18NSetter(prototype: any, propName: string) { @@ -103,12 +109,15 @@ export function invariant(check: any, message: string, thing?: any) { export function deprecate(fail: any, message: string, alterative?: string) { if (fail) { - console.warn(`Deprecation: ${message}` + (alterative ? `, use ${alterative} instead.` : '')); + logger.warn(`Deprecation: ${message}` + (alterative ? `, use ${alterative} instead.` : '')); } } export function isRegExp(obj: any): obj is RegExp { - return obj && obj.test && obj.exec && obj.compile; + if (!obj || typeof obj !== 'object') { + return false; + } + return 'test' in obj && 'exec' in obj && 'compile' in obj; } /** diff --git a/packages/utils/src/navtive-selection.ts b/packages/utils/src/navtive-selection.ts index 76f51f48aa..b8e5257734 100644 --- a/packages/utils/src/navtive-selection.ts +++ b/packages/utils/src/navtive-selection.ts @@ -1,4 +1,5 @@ -let nativeSelectionEnabled = true; +export let nativeSelectionEnabled = true; + const preventSelection = (e: Event) => { if (nativeSelectionEnabled) { return null; diff --git a/packages/utils/src/script.ts b/packages/utils/src/script.ts index 25159b198c..c4c476fac4 100644 --- a/packages/utils/src/script.ts +++ b/packages/utils/src/script.ts @@ -1,4 +1,7 @@ import { createDefer } from './create-defer'; +import { Logger } from './logger'; + +const logger = new Logger({ level: 'warn', bizName: 'utils' }); export function evaluate(script: string, scriptType?: string) { const scriptEl = document.createElement('script'); @@ -53,7 +56,7 @@ export function newFunction(args: string, code: string) { // eslint-disable-next-line no-new-func return new Function(args, code); } catch (e) { - console.warn('Caught error, Cant init func'); + logger.warn('Caught error, Cant init func'); return null; } } diff --git a/packages/utils/src/svg-icon.tsx b/packages/utils/src/svg-icon.tsx index f75724b064..2513f7bcab 100644 --- a/packages/utils/src/svg-icon.tsx +++ b/packages/utils/src/svg-icon.tsx @@ -1,4 +1,4 @@ -import { ReactNode } from 'react'; +import React, { ReactNode } from 'react'; const SizePresets: any = { xsmall: 8, diff --git a/packages/utils/test/src/__snapshots__/is-react.test.tsx.snap b/packages/utils/test/src/__snapshots__/is-react.test.tsx.snap new file mode 100644 index 0000000000..14ef394533 --- /dev/null +++ b/packages/utils/test/src/__snapshots__/is-react.test.tsx.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`wrapReactClass should render the FunctionComponent with props 1`] = ` +<FunctionComponent + prop1="value1" + prop2="value2" +> + Child Text +</FunctionComponent> +`; diff --git a/packages/utils/test/src/build-components/buildComponents.test.ts b/packages/utils/test/src/build-components/buildComponents.test.ts deleted file mode 100644 index e854890da4..0000000000 --- a/packages/utils/test/src/build-components/buildComponents.test.ts +++ /dev/null @@ -1,342 +0,0 @@ - -import { buildComponents } from "../../../src/build-components"; - -function Button() {}; - -function WrapButton() {}; - -function ButtonGroup() {}; - -function WrapButtonGroup() {}; - -ButtonGroup.Button = Button; - -Button.displayName = "Button"; -ButtonGroup.displayName = "ButtonGroup"; -ButtonGroup.prototype.isReactComponent = true; -Button.prototype.isReactComponent = true; - -jest.mock('../../../src/is-react', () => { - const original = jest.requireActual('../../../src/is-react'); - return { - ...original, - wrapReactClass(view) { - return view; - } - } -}) - -describe('build-component', () => { - it('basic button', () => { - expect( - buildComponents( - { - '@alilc/button': { - Button, - } - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: true, - exportName: 'Button', - subName: 'Button', - } - }, - () => {}, - )) - .toEqual({ - Button, - }); - }); - - it('component is a __esModule', () => { - expect( - buildComponents( - { - '@alilc/button': { - __esModule: true, - default: Button, - } - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - } - }, - () => {}, - )) - .toEqual({ - Button, - }); - }) - - it('basic warp button', () => { - expect( - buildComponents( - { - '@alilc/button': { - WrapButton, - } - }, - { - WrapButton: { - componentName: 'WrapButton', - package: '@alilc/button', - destructuring: true, - exportName: 'WrapButton', - subName: 'WrapButton', - } - }, - () => {}, - )) - .toEqual({ - WrapButton, - }); - }); - - it('destructuring is false button', () => { - expect( - buildComponents( - { - '@alilc/button': Button - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: false, - } - }, - () => {}, - )) - .toEqual({ - Button, - }); - }); - - it('Button and ButtonGroup', () => { - expect( - buildComponents( - { - '@alilc/button': { - Button, - ButtonGroup, - } - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: true, - exportName: 'Button', - subName: 'Button', - }, - ButtonGroup: { - componentName: 'ButtonGroup', - package: '@alilc/button', - destructuring: true, - exportName: 'ButtonGroup', - subName: 'ButtonGroup', - } - }, - () => {}, - )) - .toEqual({ - Button, - ButtonGroup, - }); - }); - - it('ButtonGroup and ButtonGroup.Button', () => { - expect( - buildComponents( - { - '@alilc/button': { - ButtonGroup, - } - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: true, - exportName: 'ButtonGroup', - subName: 'ButtonGroup.Button', - }, - ButtonGroup: { - componentName: 'ButtonGroup', - package: '@alilc/button', - destructuring: true, - exportName: 'ButtonGroup', - subName: 'ButtonGroup', - } - }, - () => {}, - )) - .toEqual({ - Button, - ButtonGroup, - }); - }); - - it('ButtonGroup.default and ButtonGroup.Button', () => { - expect( - buildComponents( - { - '@alilc/button': ButtonGroup, - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: true, - exportName: 'Button', - subName: 'Button', - }, - ButtonGroup: { - componentName: 'ButtonGroup', - package: '@alilc/button', - destructuring: true, - exportName: 'default', - subName: 'default', - } - }, - () => {}, - )) - .toEqual({ - Button, - ButtonGroup, - }); - }); - - it('no npm component', () => { - expect( - buildComponents( - { - '@alilc/button': Button, - }, - { - Button: null, - }, - () => {}, - )) - .toEqual({}); - }); - - it('no npm component and global button', () => { - window.Button = Button; - expect( - buildComponents( - {}, - { - Button: null, - }, - () => {}, - )) - .toEqual({ - Button, - }); - window.Button = null; - }); - - it('componentsMap value is component funtion', () => { - expect( - buildComponents( - {}, - { - Button, - }, - () => {}, - )) - .toEqual({ - Button, - }); - }); - - - it('componentsMap value is component', () => { - expect( - buildComponents( - {}, - { - Button: WrapButton, - }, - () => {}, - )) - .toEqual({ - Button: WrapButton, - }); - }); - - it('componentsMap value is mix component', () => { - expect( - buildComponents( - {}, - { - Button: { - WrapButton, - Button, - ButtonGroup, - }, - }, - () => {}, - )) - .toEqual({ - Button: { - WrapButton, - Button, - ButtonGroup, - }, - }); - }); - - it('componentsMap value is Lowcode Component', () => { - expect( - buildComponents( - {}, - { - Button: { - componentName: 'Component', - schema: {}, - }, - }, - (component) => { - return component as any; - }, - )) - .toEqual({ - Button: { - componentsMap: [], - componentsTree: [ - { - componentName: 'Component', - schema: {}, - } - ], - version: "", - }, - }); - }) -}); - -describe('build div component', () => { - it('build div component', () => { - const components = buildComponents( - { - '@alilc/div': 'div' - }, - { - div: { - componentName: 'div', - package: '@alilc/div' - } - }, - () => {}, - ); - - expect(components['div']).not.toBeNull(); - }) -}) \ No newline at end of file diff --git a/packages/utils/test/src/build-components/buildComponents.test.tsx b/packages/utils/test/src/build-components/buildComponents.test.tsx new file mode 100644 index 0000000000..a50a68b396 --- /dev/null +++ b/packages/utils/test/src/build-components/buildComponents.test.tsx @@ -0,0 +1,616 @@ +import React from 'react'; +import { + accessLibrary, + generateHtmlComp, + getSubComponent, + buildComponents, + getProjectUtils, +} from "../../../src/build-components"; + +function Button() {}; + +function WrapButton() {}; + +function ButtonGroup() {}; + +function WrapButtonGroup() {}; + +ButtonGroup.Button = Button; + +Button.displayName = "Button"; +ButtonGroup.displayName = "ButtonGroup"; +ButtonGroup.prototype.isReactComponent = true; +Button.prototype.isReactComponent = true; + +jest.mock('../../../src/is-react', () => { + const original = jest.requireActual('../../../src/is-react'); + return { + ...original, + wrapReactClass(view) { + return view; + } + } +}); + +describe('accessLibrary', () => { + it('should return a library object when given a library object', () => { + const libraryObject = { key: 'value' }; + const result = accessLibrary(libraryObject); + expect(result).toEqual(libraryObject); + }); + + it('should generate an HTML component when given a string library name', () => { + const libraryName = 'div'; + const result = accessLibrary(libraryName); + + // You can write more specific assertions to validate the generated component + expect(result).toBeDefined(); + }); + + // Add more test cases to cover other scenarios +}); + +describe('generateHtmlComp', () => { + it('should generate an HTML component for valid HTML tags', () => { + const htmlTags = ['a', 'img', 'div', 'span', 'svg']; + htmlTags.forEach((tag) => { + const result = generateHtmlComp(tag); + + // You can write more specific assertions to validate the generated component + expect(result).toBeDefined(); + }); + }); + + it('should return undefined for an invalid HTML tag', () => { + const invalidTag = 'invalidtag'; + const result = generateHtmlComp(invalidTag); + expect(result).toBeUndefined(); + }); + + // Add more test cases to cover other scenarios +}); + +describe('getSubComponent', () => { + it('should return the root library if paths are empty', () => { + const library = { component: 'RootComponent' }; + const paths = []; + const result = getSubComponent(library, paths); + expect(result).toEqual(library); + }); + + it('should return the specified sub-component', () => { + const library = { + components: { + Button: 'ButtonComponent', + Text: 'TextComponent', + }, + }; + const paths = ['components', 'Button']; + const result = getSubComponent(library, paths); + expect(result).toEqual('ButtonComponent'); + }); + + it('should handle missing keys in the path', () => { + const library = { + components: { + Button: 'ButtonComponent', + }, + }; + const paths = ['components', 'Text']; + const result = getSubComponent(library, paths); + expect(result).toEqual({ + Button: 'ButtonComponent', + }); + }); + + it('should handle exceptions and return null', () => { + const library = 'ButtonComponent'; + const paths = ['components', 'Button']; + // Simulate an exception by providing a non-object in place of 'ButtonComponent' + const result = getSubComponent(library, paths); + expect(result).toBeNull(); + }); + + it('should handle the "default" key as the first path element', () => { + const library = { + default: 'DefaultComponent', + }; + const paths = ['default']; + const result = getSubComponent(library, paths); + expect(result).toEqual('DefaultComponent'); + }); +}); + +describe('getProjectUtils', () => { + it('should return an empty object when given empty metadata and library map', () => { + const libraryMap = {}; + const utilsMetadata = []; + const result = getProjectUtils(libraryMap, utilsMetadata); + expect(result).toEqual({}); + }); + + it('should return project utilities based on metadata and library map', () => { + const libraryMap = { + 'package1': 'library1', + 'package2': 'library2', + }; + + const utilsMetadata = [ + { + name: 'util1', + npm: { + package: 'package1', + }, + }, + { + name: 'util2', + npm: { + package: 'package2', + }, + }, + ]; + + global['library1'] = { name: 'library1' }; + global['library2'] = { name: 'library2' }; + + const result = getProjectUtils(libraryMap, utilsMetadata); + + // Define the expected output based on the mocked accessLibrary + const expectedOutput = { + 'util1': { name: 'library1' }, + 'util2': { name: 'library2' }, + }; + + expect(result).toEqual(expectedOutput); + + global['library1'] = null; + global['library1'] = null; + }); + + it('should handle metadata with destructuring', () => { + const libraryMap = { + 'package1': { destructuring: true, util1: 'library1', util2: 'library2' }, + }; + + const utilsMetadata = [ + { + name: 'util1', + npm: { + package: 'package1', + destructuring: true, + }, + }, + ]; + + const result = getProjectUtils(libraryMap, utilsMetadata); + + // Define the expected output based on the mocked accessLibrary + const expectedOutput = { + 'util1': 'library1', + 'util2': 'library2', + }; + + expect(result).toEqual(expectedOutput); + }); +}); + +describe('buildComponents', () => { + it('should create components from component map with React components', () => { + const libraryMap = {}; + const componentsMap = { + Button: () => <button>Button</button>, + Text: () => <p>Text</p>, + }; + + const createComponent = (schema) => { + // Mock createComponent function + return schema.componentsTree.map((component) => component.component); + }; + + const result = buildComponents(libraryMap, componentsMap, createComponent); + + expect(result.Button).toBeDefined(); + expect(result.Text).toBeDefined(); + }); + + it('should create components from component map with component schemas', () => { + const libraryMap = {}; + const componentsMap = { + Button: { + componentsTree: [ + { + componentName: 'Component' + } + ] + }, + Text: { + componentsTree: [ + { + componentName: 'Component' + } + ] + }, + }; + + const createComponent = (schema) => { + // Mock createComponent function + return schema.componentsTree.map((component) => component.component); + }; + + const result = buildComponents(libraryMap, componentsMap, createComponent); + + expect(result.Button).toBeDefined(); + expect(result.Text).toBeDefined(); + }); + + it('should create components from component map with React components and schemas', () => { + const libraryMap = {}; + const componentsMap = { + Button: () => <button>Button</button>, + Text: { + type: 'ComponentSchema', + // Add component schema properties here + }, + }; + + const createComponent = (schema) => { + // Mock createComponent function + return schema.componentsTree.map((component) => component.component); + }; + + const result = buildComponents(libraryMap, componentsMap, createComponent); + + expect(result.Button).toBeDefined(); + expect(result.Text).toBeDefined(); + }); + + it('should create components from component map with library mappings', () => { + const libraryMap = { + 'libraryName1': 'library1', + 'libraryName2': 'library2', + }; + const componentsMap = { + Button: { + package: 'libraryName1', + version: '1.0', + exportName: 'ButtonComponent', + }, + Text: { + package: 'libraryName2', + version: '2.0', + exportName: 'TextComponent', + }, + }; + + const createComponent = (schema) => { + // Mock createComponent function + return schema.componentsTree.map((component) => component.component); + }; + + global['library1'] = () => <button>ButtonComponent</button>; + global['library2'] = () => () => <p>TextComponent</p>; + + const result = buildComponents(libraryMap, componentsMap, createComponent); + + expect(result.Button).toBeDefined(); + expect(result.Text).toBeDefined(); + + global['library1'] = null; + global['library2'] = null; + }); +}); + +describe('build-component', () => { + it('basic button', () => { + expect( + buildComponents( + { + '@alilc/button': { + Button, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'Button', + subName: 'Button', + } + }, + () => {}, + )) + .toEqual({ + Button, + }); + }); + + it('component is a __esModule', () => { + expect( + buildComponents( + { + '@alilc/button': { + __esModule: true, + default: Button, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + } + }, + () => {}, + )) + .toEqual({ + Button, + }); + }) + + it('basic warp button', () => { + expect( + buildComponents( + { + '@alilc/button': { + WrapButton, + } + }, + { + WrapButton: { + componentName: 'WrapButton', + package: '@alilc/button', + destructuring: true, + exportName: 'WrapButton', + subName: 'WrapButton', + } + }, + () => {}, + )) + .toEqual({ + WrapButton, + }); + }); + + it('destructuring is false button', () => { + expect( + buildComponents( + { + '@alilc/button': Button + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: false, + } + }, + () => {}, + )) + .toEqual({ + Button, + }); + }); + + it('Button and ButtonGroup', () => { + expect( + buildComponents( + { + '@alilc/button': { + Button, + ButtonGroup, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'Button', + subName: 'Button', + }, + ButtonGroup: { + componentName: 'ButtonGroup', + package: '@alilc/button', + destructuring: true, + exportName: 'ButtonGroup', + subName: 'ButtonGroup', + } + }, + () => {}, + )) + .toEqual({ + Button, + ButtonGroup, + }); + }); + + it('ButtonGroup and ButtonGroup.Button', () => { + expect( + buildComponents( + { + '@alilc/button': { + ButtonGroup, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'ButtonGroup', + subName: 'ButtonGroup.Button', + }, + ButtonGroup: { + componentName: 'ButtonGroup', + package: '@alilc/button', + destructuring: true, + exportName: 'ButtonGroup', + subName: 'ButtonGroup', + } + }, + () => {}, + )) + .toEqual({ + Button, + ButtonGroup, + }); + }); + + it('ButtonGroup.default and ButtonGroup.Button', () => { + expect( + buildComponents( + { + '@alilc/button': ButtonGroup, + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'Button', + subName: 'Button', + }, + ButtonGroup: { + componentName: 'ButtonGroup', + package: '@alilc/button', + destructuring: true, + exportName: 'default', + subName: 'default', + } + }, + () => {}, + )) + .toEqual({ + Button, + ButtonGroup, + }); + }); + + it('no npm component', () => { + expect( + buildComponents( + { + '@alilc/button': Button, + }, + { + Button: null, + }, + () => {}, + )) + .toEqual({}); + }); + + it('no npm component and global button', () => { + window.Button = Button; + expect( + buildComponents( + {}, + { + Button: null, + }, + () => {}, + )) + .toEqual({ + Button, + }); + window.Button = null; + }); + + it('componentsMap value is component funtion', () => { + expect( + buildComponents( + {}, + { + Button, + }, + () => {}, + )) + .toEqual({ + Button, + }); + }); + + + it('componentsMap value is component', () => { + expect( + buildComponents( + {}, + { + Button: WrapButton, + }, + () => {}, + )) + .toEqual({ + Button: WrapButton, + }); + }); + + it('componentsMap value is mix component', () => { + expect( + buildComponents( + {}, + { + Button: { + WrapButton, + Button, + ButtonGroup, + }, + }, + () => {}, + )) + .toEqual({ + Button: { + WrapButton, + Button, + ButtonGroup, + }, + }); + }); + + it('componentsMap value is Lowcode Component', () => { + expect( + buildComponents( + {}, + { + Button: { + componentName: 'Component', + schema: {}, + }, + }, + (component) => { + return component as any; + }, + )) + .toEqual({ + Button: { + componentsMap: [], + componentsTree: [ + { + componentName: 'Component', + schema: {}, + } + ], + version: "", + }, + }); + }) +}); + +describe('build div component', () => { + it('build div component', () => { + const components = buildComponents( + { + '@alilc/div': 'div' + }, + { + div: { + componentName: 'div', + package: '@alilc/div' + } + }, + () => {}, + ); + + expect(components['div']).not.toBeNull(); + }) +}) \ No newline at end of file diff --git a/packages/utils/test/src/check-types/is-action-content-object.test.ts b/packages/utils/test/src/check-types/is-action-content-object.test.ts new file mode 100644 index 0000000000..08b95788d1 --- /dev/null +++ b/packages/utils/test/src/check-types/is-action-content-object.test.ts @@ -0,0 +1,20 @@ +import { isActionContentObject } from '../../../src/check-types/is-action-content-object'; + +describe('isActionContentObject', () => { + test('should return true for an object', () => { + const obj = { prop: 'value' }; + expect(isActionContentObject(obj)).toBe(true); + }); + + test('should return false for a non-object', () => { + expect(isActionContentObject('not an object')).toBe(false); + expect(isActionContentObject(123)).toBe(false); + expect(isActionContentObject(null)).toBe(false); + expect(isActionContentObject(undefined)).toBe(false); + }); + + test('should return false for an empty object', () => { + const obj = {}; + expect(isActionContentObject(obj)).toBe(true); + }); +}); diff --git a/packages/utils/test/src/check-types/is-custom-view.test.tsx b/packages/utils/test/src/check-types/is-custom-view.test.tsx new file mode 100644 index 0000000000..62c08780e6 --- /dev/null +++ b/packages/utils/test/src/check-types/is-custom-view.test.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { isCustomView } from '../../../src/check-types/is-custom-view'; +import { IPublicTypeCustomView } from '@alilc/lowcode-types'; + +describe('isCustomView', () => { + test('should return true when obj is a valid React element', () => { + const obj: IPublicTypeCustomView = <div>Hello, World!</div>; + expect(isCustomView(obj)).toBe(true); + }); + + test('should return true when obj is a valid React component', () => { + const MyComponent: React.FC = () => <div>Hello, World!</div>; + const obj: IPublicTypeCustomView = MyComponent; + expect(isCustomView(obj)).toBe(true); + }); + + test('should return false when obj is null or undefined', () => { + expect(isCustomView(null)).toBe(false); + expect(isCustomView(undefined)).toBe(false); + }); + + test('should return false when obj is not a valid React element or component', () => { + const obj: IPublicTypeCustomView = 'not a valid object'; + expect(isCustomView(obj)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-dom-text.test.ts b/packages/utils/test/src/check-types/is-dom-text.test.ts new file mode 100644 index 0000000000..50dce0fb7a --- /dev/null +++ b/packages/utils/test/src/check-types/is-dom-text.test.ts @@ -0,0 +1,13 @@ +import { isDOMText } from '../../../src/check-types/is-dom-text'; + +describe('isDOMText', () => { + it('should return true when the input is a string', () => { + const result = isDOMText('Hello World'); + expect(result).toBe(true); + }); + + it('should return false when the input is not a string', () => { + const result = isDOMText(123); + expect(result).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-drag-any-object.test.ts b/packages/utils/test/src/check-types/is-drag-any-object.test.ts new file mode 100644 index 0000000000..6a835f2be3 --- /dev/null +++ b/packages/utils/test/src/check-types/is-drag-any-object.test.ts @@ -0,0 +1,32 @@ +import { isDragAnyObject } from '../../../src/check-types/is-drag-any-object'; +import { IPublicEnumDragObjectType } from '@alilc/lowcode-types'; + +describe('isDragAnyObject', () => { + it('should return false if obj is null', () => { + const result = isDragAnyObject(null); + expect(result).toBe(false); + }); + + it('should return false if obj is number', () => { + const result = isDragAnyObject(2); + expect(result).toBe(false); + }); + + it('should return false if obj.type is NodeData', () => { + const obj = { type: IPublicEnumDragObjectType.NodeData }; + const result = isDragAnyObject(obj); + expect(result).toBe(false); + }); + + it('should return false if obj.type is Node', () => { + const obj = { type: IPublicEnumDragObjectType.Node }; + const result = isDragAnyObject(obj); + expect(result).toBe(false); + }); + + it('should return true if obj.type is anything else', () => { + const obj = { type: 'SomeOtherType' }; + const result = isDragAnyObject(obj); + expect(result).toBe(true); + }); +}); diff --git a/packages/utils/test/src/check-types/is-drag-node-data-object.test.ts b/packages/utils/test/src/check-types/is-drag-node-data-object.test.ts new file mode 100644 index 0000000000..92867843a2 --- /dev/null +++ b/packages/utils/test/src/check-types/is-drag-node-data-object.test.ts @@ -0,0 +1,29 @@ +import { IPublicEnumDragObjectType, IPublicTypeDragNodeDataObject } from '@alilc/lowcode-types'; +import { isDragNodeDataObject } from '../../../src/check-types/is-drag-node-data-object'; + +describe('isDragNodeDataObject', () => { + test('should return true for valid IPublicTypeDragNodeDataObject', () => { + const obj: IPublicTypeDragNodeDataObject = { + type: IPublicEnumDragObjectType.NodeData, + // 其他属性... + }; + + expect(isDragNodeDataObject(obj)).toBe(true); + }); + + test('should return false for invalid IPublicTypeDragNodeDataObject', () => { + const obj: any = { + type: 'InvalidType', + // 其他属性... + }; + + expect(isDragNodeDataObject(obj)).toBe(false); + }); + + test('should return false for null or undefined', () => { + expect(isDragNodeDataObject(null)).toBe(false); + expect(isDragNodeDataObject(undefined)).toBe(false); + }); + + // 可以添加更多测试用例... +}); diff --git a/packages/utils/test/src/check-types/is-drag-node-object.test.ts b/packages/utils/test/src/check-types/is-drag-node-object.test.ts new file mode 100644 index 0000000000..3561c87885 --- /dev/null +++ b/packages/utils/test/src/check-types/is-drag-node-object.test.ts @@ -0,0 +1,36 @@ +import { IPublicEnumDragObjectType } from '@alilc/lowcode-types'; +import { isDragNodeObject } from '../../../src/check-types/is-drag-node-object'; + +describe('isDragNodeObject', () => { + it('should return true if the object is of IPublicTypeDragNodeObject type and has type IPublicEnumDragObjectType.Node', () => { + const obj = { + type: IPublicEnumDragObjectType.Node, + //... other properties + }; + + expect(isDragNodeObject(obj)).toBe(true); + }); + + it('should return false if the object is not of IPublicTypeDragNodeObject type', () => { + const obj = { + type: IPublicEnumDragObjectType.OtherType, + //... other properties + }; + + expect(isDragNodeObject(obj)).toBe(false); + }); + + it('should return false if the object is of IPublicTypeDragNodeObject type but type is not IPublicEnumDragObjectType.Node', () => { + const obj = { + type: IPublicEnumDragObjectType.OtherType, + //... other properties + }; + + expect(isDragNodeObject(obj)).toBe(false); + }); + + it('should return false if the object is null or undefined', () => { + expect(isDragNodeObject(null)).toBe(false); + expect(isDragNodeObject(undefined)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-dynamic-setter.test.ts b/packages/utils/test/src/check-types/is-dynamic-setter.test.ts new file mode 100644 index 0000000000..72f55367d0 --- /dev/null +++ b/packages/utils/test/src/check-types/is-dynamic-setter.test.ts @@ -0,0 +1,28 @@ +import { Component } from 'react'; +import { isDynamicSetter } from '../../../src/check-types/is-dynamic-setter'; + +describe('isDynamicSetter', () => { + it('returns true if input is a dynamic setter function', () => { + const dynamicSetter = (value: any) => { + // some implementation + }; + + expect(isDynamicSetter(dynamicSetter)).toBeTruthy(); + }); + + it('returns false if input is not a dynamic setter function', () => { + expect(isDynamicSetter('not a function')).toBeFalsy(); + expect(isDynamicSetter(null)).toBeFalsy(); + expect(isDynamicSetter(undefined)).toBeFalsy(); + expect(isDynamicSetter(2)).toBeFalsy(); + expect(isDynamicSetter(0)).toBeFalsy(); + }); + + it('returns false if input is a React class', () => { + class ReactClass extends Component { + // some implementation + } + + expect(isDynamicSetter(ReactClass)).toBeFalsy(); + }); +}); diff --git a/packages/utils/test/src/check-types/is-i18n-data.test.ts b/packages/utils/test/src/check-types/is-i18n-data.test.ts new file mode 100644 index 0000000000..2e903a2ed2 --- /dev/null +++ b/packages/utils/test/src/check-types/is-i18n-data.test.ts @@ -0,0 +1,27 @@ +import { isI18nData } from '../../../src/check-types/is-i18n-data'; +import { IPublicTypeI18nData } from "@alilc/lowcode-types"; + +describe('isI18nData', () => { + it('should return true for valid i18n data', () => { + const i18nData: IPublicTypeI18nData = { + type: 'i18n', + // add any other required properties here + }; + + expect(isI18nData(i18nData)).toBe(true); + }); + + it('should return false for invalid i18n data', () => { + const invalidData = { + type: 'some-other-type', + // add any other properties here + }; + + expect(isI18nData(invalidData)).toBe(false); + }); + + it('should return false for undefined or null', () => { + expect(isI18nData(undefined)).toBe(false); + expect(isI18nData(null)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-isfunction.test.ts b/packages/utils/test/src/check-types/is-isfunction.test.ts new file mode 100644 index 0000000000..5154282285 --- /dev/null +++ b/packages/utils/test/src/check-types/is-isfunction.test.ts @@ -0,0 +1,61 @@ +import { isInnerJsFunction, isJSFunction } from '../../../src/check-types/is-isfunction'; + +describe('isInnerJsFunction', () => { + test('should return true for valid input', () => { + const data = { + type: 'JSExpression', + source: '', + value: '', + extType: 'function' + }; + + expect(isInnerJsFunction(data)).toBe(true); + }); + + test('should return false for invalid input', () => { + const data = { + type: 'JSExpression', + source: '', + value: '', + extType: 'object' + }; + + expect(isInnerJsFunction(data)).toBe(false); + expect(isInnerJsFunction(null)).toBe(false); + expect(isInnerJsFunction(undefined)).toBe(false); + expect(isInnerJsFunction(1)).toBe(false); + expect(isInnerJsFunction(0)).toBe(false); + expect(isInnerJsFunction('string')).toBe(false); + expect(isInnerJsFunction('')).toBe(false); + }); +}); + +describe('isJSFunction', () => { + test('should return true for valid input', () => { + const data = { + type: 'JSFunction', + }; + + expect(isJSFunction(data)).toBe(true); + }); + + test('should return true for inner js function', () => { + const data = { + type: 'JSExpression', + source: '', + value: '', + extType: 'function' + }; + + expect(isJSFunction(data)).toBe(true); + }); + + test('should return false for invalid input', () => { + expect(isJSFunction(null)).toBe(false); + expect(isJSFunction(undefined)).toBe(false); + expect(isJSFunction('string')).toBe(false); + expect(isJSFunction('')).toBe(false); + expect(isJSFunction(0)).toBe(false); + expect(isJSFunction(2)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-jsblock.test.ts b/packages/utils/test/src/check-types/is-jsblock.test.ts new file mode 100644 index 0000000000..e44e9eb705 --- /dev/null +++ b/packages/utils/test/src/check-types/is-jsblock.test.ts @@ -0,0 +1,22 @@ +import { isJSBlock } from '../../../src/check-types/is-jsblock'; + +describe('isJSBlock', () => { + it('should return false if data is null or undefined', () => { + expect(isJSBlock(null)).toBe(false); + expect(isJSBlock(undefined)).toBe(false); + }); + + it('should return false if data is not an object', () => { + expect(isJSBlock('JSBlock')).toBe(false); + expect(isJSBlock(123)).toBe(false); + expect(isJSBlock(true)).toBe(false); + }); + + it('should return false if data.type is not "JSBlock"', () => { + expect(isJSBlock({ type: 'InvalidType' })).toBe(false); + }); + + it('should return true if data is an object and data.type is "JSBlock"', () => { + expect(isJSBlock({ type: 'JSBlock' })).toBe(true); + }); +}); diff --git a/packages/utils/test/src/check-types/is-jsexpression.test.ts b/packages/utils/test/src/check-types/is-jsexpression.test.ts new file mode 100644 index 0000000000..dd8509a3b3 --- /dev/null +++ b/packages/utils/test/src/check-types/is-jsexpression.test.ts @@ -0,0 +1,39 @@ +import { isJSExpression } from '../../../src/check-types/is-jsexpression'; + +describe('isJSExpression', () => { + it('should return true if the input is a valid JSExpression object', () => { + const validJSExpression = { + type: 'JSExpression', + extType: 'variable', + }; + + const result = isJSExpression(validJSExpression); + + expect(result).toBe(true); + }); + + it('should return false if the input is not a valid JSExpression object', () => { + const invalidJSExpression = { + type: 'JSExpression', + extType: 'function', + }; + + const result = isJSExpression(invalidJSExpression); + + expect(result).toBe(false); + }); + + it('should return false if the input is null', () => { + const result = isJSExpression(null); + + expect(result).toBe(false); + }); + + it('should return false if the input is undefined', () => { + const result = isJSExpression(undefined); + + expect(result).toBe(false); + }); + + // 添加其他需要的测试 +}); diff --git a/packages/utils/test/src/check-types/is-jsslot.test.ts b/packages/utils/test/src/check-types/is-jsslot.test.ts new file mode 100644 index 0000000000..5c130cddfd --- /dev/null +++ b/packages/utils/test/src/check-types/is-jsslot.test.ts @@ -0,0 +1,37 @@ +import { isJSSlot } from '../../../src/check-types/is-jsslot'; +import { IPublicTypeJSSlot } from '@alilc/lowcode-types'; + +describe('isJSSlot', () => { + it('should return true when input is of type IPublicTypeJSSlot', () => { + const input: IPublicTypeJSSlot = { + type: 'JSSlot', + // other properties of IPublicTypeJSSlot + }; + + const result = isJSSlot(input); + + expect(result).toBe(true); + }); + + it('should return false when input is not of type IPublicTypeJSSlot', () => { + const input = { + type: 'OtherType', + // other properties + }; + + const result = isJSSlot(input); + + expect(result).toBe(false); + }); + + it('should return false when input is null or undefined', () => { + const input1 = null; + const input2 = undefined; + + const result1 = isJSSlot(input1); + const result2 = isJSSlot(input2); + + expect(result1).toBe(false); + expect(result2).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-location-children-detail.test.ts b/packages/utils/test/src/check-types/is-location-children-detail.test.ts new file mode 100644 index 0000000000..f209e8e63f --- /dev/null +++ b/packages/utils/test/src/check-types/is-location-children-detail.test.ts @@ -0,0 +1,27 @@ +import { isLocationChildrenDetail } from '../../../src/check-types/is-location-children-detail'; +import { IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType } from '@alilc/lowcode-types'; + +describe('isLocationChildrenDetail', () => { + it('should return true when obj is IPublicTypeLocationChildrenDetail', () => { + const obj: IPublicTypeLocationChildrenDetail = { + type: IPublicTypeLocationDetailType.Children, + // 添加其他必要的属性 + }; + + expect(isLocationChildrenDetail(obj)).toBe(true); + }); + + it('should return false when obj is not IPublicTypeLocationChildrenDetail', () => { + const obj = { + type: 'other', + // 添加其他必要的属性 + }; + + expect(isLocationChildrenDetail(obj)).toBe(false); + expect(isLocationChildrenDetail(null)).toBe(false); + expect(isLocationChildrenDetail(undefined)).toBe(false); + expect(isLocationChildrenDetail('string')).toBe(false); + expect(isLocationChildrenDetail(0)).toBe(false); + expect(isLocationChildrenDetail(2)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-location-data.test.ts b/packages/utils/test/src/check-types/is-location-data.test.ts new file mode 100644 index 0000000000..ba2e2c8be0 --- /dev/null +++ b/packages/utils/test/src/check-types/is-location-data.test.ts @@ -0,0 +1,44 @@ +import { isLocationData } from '../../../src/check-types/is-location-data'; +import { IPublicTypeLocationData } from '@alilc/lowcode-types'; + +describe('isLocationData', () => { + it('should return true when obj is valid location data', () => { + const obj: IPublicTypeLocationData = { + target: 'some target', + detail: 'some detail', + }; + + const result = isLocationData(obj); + + expect(result).toBe(true); + }); + + it('should return false when obj is missing target or detail', () => { + const obj1 = { + target: 'some target', + // missing detail + }; + + const obj2 = { + // missing target + detail: 'some detail', + }; + + const result1 = isLocationData(obj1); + const result2 = isLocationData(obj2); + + expect(result1).toBe(false); + expect(result2).toBe(false); + }); + + it('should return false when obj is null or undefined', () => { + const obj1 = null; + const obj2 = undefined; + + const result1 = isLocationData(obj1); + const result2 = isLocationData(obj2); + + expect(result1).toBe(false); + expect(result2).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-lowcode-component-type.test.ts b/packages/utils/test/src/check-types/is-lowcode-component-type.test.ts new file mode 100644 index 0000000000..35b76f00b5 --- /dev/null +++ b/packages/utils/test/src/check-types/is-lowcode-component-type.test.ts @@ -0,0 +1,21 @@ +import { isLowCodeComponentType } from '../../../src/check-types/is-lowcode-component-type'; +import { IPublicTypeLowCodeComponent, IPublicTypeProCodeComponent } from '@alilc/lowcode-types'; + +describe('isLowCodeComponentType', () => { + test('should return true for a low code component type', () => { + const desc: IPublicTypeLowCodeComponent = { + // create a valid low code component description + }; + + expect(isLowCodeComponentType(desc)).toBe(true); + }); + + test('should return false for a pro code component type', () => { + const desc: IPublicTypeProCodeComponent = { + // create a valid pro code component description + package: 'pro-code' + }; + + expect(isLowCodeComponentType(desc)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts b/packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts new file mode 100644 index 0000000000..bb750ed88b --- /dev/null +++ b/packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts @@ -0,0 +1,42 @@ +import { isLowcodeProjectSchema } from "../../../src/check-types/is-lowcode-project-schema"; + +describe("isLowcodeProjectSchema", () => { + it("should return false when data is null", () => { + const result = isLowcodeProjectSchema(null); + expect(result).toBe(false); + }); + + it("should return false when data is undefined", () => { + const result = isLowcodeProjectSchema(undefined); + expect(result).toBe(false); + }); + + it("should return false when data is not an object", () => { + const result = isLowcodeProjectSchema("not an object"); + expect(result).toBe(false); + }); + + it("should return false when componentsTree is missing", () => { + const data = { someKey: "someValue" }; + const result = isLowcodeProjectSchema(data); + expect(result).toBe(false); + }); + + it("should return false when componentsTree is an empty array", () => { + const data = { componentsTree: [] }; + const result = isLowcodeProjectSchema(data); + expect(result).toBe(false); + }); + + it("should return false when the first element of componentsTree is not a component schema", () => { + const data = { componentsTree: [{}] }; + const result = isLowcodeProjectSchema(data); + expect(result).toBe(false); + }); + + it("should return true when all conditions are met", () => { + const data = { componentsTree: [{ prop: "value", componentName: 'Component' }] }; + const result = isLowcodeProjectSchema(data); + expect(result).toBe(true); + }); +}); diff --git a/packages/utils/test/src/check-types/is-node-schema.test.ts b/packages/utils/test/src/check-types/is-node-schema.test.ts new file mode 100644 index 0000000000..b5a4e39acb --- /dev/null +++ b/packages/utils/test/src/check-types/is-node-schema.test.ts @@ -0,0 +1,43 @@ +import { isNodeSchema } from '../../../src/check-types/is-node-schema'; + +describe('isNodeSchema', () => { + // 测试正常情况 + it('should return true for valid IPublicTypeNodeSchema', () => { + const validData = { + componentName: 'Component', + isNode: false, + }; + expect(isNodeSchema(validData)).toBe(true); + }); + + // 测试 null 或 undefined + it('should return false for null or undefined', () => { + expect(isNodeSchema(null)).toBe(false); + expect(isNodeSchema(undefined)).toBe(false); + }); + + // 测试没有componentName属性的情况 + it('should return false if componentName is missing', () => { + const invalidData = { + isNode: false, + }; + expect(isNodeSchema(invalidData)).toBe(false); + }); + + // 测试isNode为true的情况 + it('should return false if isNode is true', () => { + const invalidData = { + componentName: 'Component', + isNode: true, + }; + expect(isNodeSchema(invalidData)).toBe(false); + }); + + // 测试其他数据类型的情况 + it('should return false for other data types', () => { + expect(isNodeSchema('string')).toBe(false); + expect(isNodeSchema(123)).toBe(false); + expect(isNodeSchema([])).toBe(false); + expect(isNodeSchema({})).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-node.test.ts b/packages/utils/test/src/check-types/is-node.test.ts new file mode 100644 index 0000000000..d6d8dfc03d --- /dev/null +++ b/packages/utils/test/src/check-types/is-node.test.ts @@ -0,0 +1,19 @@ +import { isNode } from '../../../src/check-types/is-node'; + +describe('isNode', () => { + it('should return true for a valid node', () => { + const node = { isNode: true }; + expect(isNode(node)).toBeTruthy(); + }); + + it('should return false for an invalid node', () => { + const node = { isNode: false }; + expect(isNode(node)).toBeFalsy(); + }); + + it('should return false for an undefined node', () => { + expect(isNode(undefined)).toBeFalsy(); + }); + + // Add more test cases if needed +}); diff --git a/packages/utils/test/src/check-types/is-procode-component-type.test.ts b/packages/utils/test/src/check-types/is-procode-component-type.test.ts new file mode 100644 index 0000000000..58f435b98a --- /dev/null +++ b/packages/utils/test/src/check-types/is-procode-component-type.test.ts @@ -0,0 +1,13 @@ +import { isProCodeComponentType } from '../../../src/check-types/is-procode-component-type'; + +describe('isProCodeComponentType', () => { + it('should return true if the given desc object contains "package" property', () => { + const desc = { package: 'packageName' }; + expect(isProCodeComponentType(desc)).toBe(true); + }); + + it('should return false if the given desc object does not contain "package" property', () => { + const desc = { name: 'componentName' }; + expect(isProCodeComponentType(desc)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-project-schema.test.ts b/packages/utils/test/src/check-types/is-project-schema.test.ts new file mode 100644 index 0000000000..0ec3f47408 --- /dev/null +++ b/packages/utils/test/src/check-types/is-project-schema.test.ts @@ -0,0 +1,28 @@ +import { IPublicTypeProjectSchema } from "@alilc/lowcode-types"; +import { isProjectSchema } from "../../../src/check-types/is-project-schema"; + +describe("isProjectSchema", () => { + it("should return true if data has componentsTree property", () => { + const data: IPublicTypeProjectSchema = { + // ... + componentsTree: { + // ... + }, + }; + expect(isProjectSchema(data)).toBe(true); + }); + + it("should return false if data does not have componentsTree property", () => { + const data = { + // ... + }; + expect(isProjectSchema(data)).toBe(false); + }); + + it("should return false if data is null or undefined", () => { + expect(isProjectSchema(null)).toBe(false); + expect(isProjectSchema(undefined)).toBe(false); + }); + + // 更多的测试用例... +}); diff --git a/packages/utils/test/src/check-types/is-setter-config.test.ts b/packages/utils/test/src/check-types/is-setter-config.test.ts new file mode 100644 index 0000000000..eee234658d --- /dev/null +++ b/packages/utils/test/src/check-types/is-setter-config.test.ts @@ -0,0 +1,26 @@ +import { isSetterConfig } from '../../../src/check-types/is-setter-config'; + +describe('isSetterConfig', () => { + test('should return true for valid setter config', () => { + const config = { + componentName: 'MyComponent', + // Add other required properties here + }; + + expect(isSetterConfig(config)).toBe(true); + }); + + test('should return false for invalid setter config', () => { + const config = { + // Missing componentName property + }; + + expect(isSetterConfig(config)).toBe(false); + expect(isSetterConfig(null)).toBe(false); + expect(isSetterConfig(undefined)).toBe(false); + expect(isSetterConfig(0)).toBe(false); + expect(isSetterConfig(2)).toBe(false); + }); + + // Add more test cases for different scenarios you want to cover +}); diff --git a/packages/utils/test/src/check-types/is-setting-field.test.ts b/packages/utils/test/src/check-types/is-setting-field.test.ts new file mode 100644 index 0000000000..5f9bbd6239 --- /dev/null +++ b/packages/utils/test/src/check-types/is-setting-field.test.ts @@ -0,0 +1,18 @@ +import { isSettingField } from "../../../src/check-types/is-setting-field"; + +describe("isSettingField", () => { + it("should return true for an object that has isSettingField property", () => { + const obj = { isSettingField: true }; + expect(isSettingField(obj)).toBe(true); + }); + + it("should return false for an object that does not have isSettingField property", () => { + const obj = { foo: "bar" }; + expect(isSettingField(obj)).toBe(false); + }); + + it("should return false for a falsy value", () => { + const obj = null; + expect(isSettingField(obj)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-title-config.test.ts b/packages/utils/test/src/check-types/is-title-config.test.ts new file mode 100644 index 0000000000..4aa6d219cb --- /dev/null +++ b/packages/utils/test/src/check-types/is-title-config.test.ts @@ -0,0 +1,18 @@ +import { isTitleConfig } from '../../../src/check-types/is-title-config'; + +describe('isTitleConfig', () => { + it('should return true for valid config object', () => { + const config = { title: 'My Title' }; + expect(isTitleConfig(config)).toBe(true); + }); + + it('should return false for invalid config object', () => { + const config = { title: 'My Title', type: 'i18n' , i18nData: {} }; + expect(isTitleConfig(config)).toBe(false); + }); + + it('should return false for non-object input', () => { + const config = 'invalid'; + expect(isTitleConfig(config)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/clone-deep.test.ts b/packages/utils/test/src/clone-deep.test.ts new file mode 100644 index 0000000000..58fabc6f68 --- /dev/null +++ b/packages/utils/test/src/clone-deep.test.ts @@ -0,0 +1,30 @@ +import { cloneDeep } from '../../src/clone-deep'; + +describe('cloneDeep', () => { + it('should clone null', () => { + const src = null; + expect(cloneDeep(src)).toBeNull(); + }); + + it('should clone undefined', () => { + const src = undefined; + expect(cloneDeep(src)).toBeUndefined(); + }); + + it('should clone an array', () => { + const src = [1, 2, 3, 4]; + expect(cloneDeep(src)).toEqual(src); + }); + + it('should clone an object', () => { + const src = { name: 'John', age: 25 }; + expect(cloneDeep(src)).toEqual(src); + }); + + it('should deep clone nested objects', () => { + const src = { person: { name: 'John', age: 25 } }; + const cloned = cloneDeep(src); + expect(cloned).toEqual(src); + expect(cloned.person).not.toBe(src.person); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/clone-enumerable-property.test.ts b/packages/utils/test/src/clone-enumerable-property.test.ts new file mode 100644 index 0000000000..2eff09e44c --- /dev/null +++ b/packages/utils/test/src/clone-enumerable-property.test.ts @@ -0,0 +1,30 @@ +import { cloneEnumerableProperty } from '../../src/clone-enumerable-property'; + +describe('cloneEnumerableProperty', () => { + test('should clone enumerable properties from origin to target', () => { + // Arrange + const target = {}; + const origin = { prop1: 1, prop2: 'hello', prop3: true }; + + // Act + const result = cloneEnumerableProperty(target, origin); + + // Assert + expect(result).toBe(target); + expect(result).toEqual(origin); + }); + + test('should exclude properties specified in excludePropertyNames', () => { + // Arrange + const target = {}; + const origin = { prop1: 1, prop2: 'hello', prop3: true }; + const excludePropertyNames = ['prop2']; + + // Act + const result = cloneEnumerableProperty(target, origin, excludePropertyNames); + + // Assert + expect(result).toBe(target); + expect(result).toEqual({ prop1: 1, prop3: true }); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/create-content.test.tsx b/packages/utils/test/src/create-content.test.tsx new file mode 100644 index 0000000000..c41fb0f0da --- /dev/null +++ b/packages/utils/test/src/create-content.test.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { createContent } from '../../src/create-content'; + +const MyComponent = () => { + return <div>MyComponent</div> +} +describe('createContent', () => { + test('should return the same content if it is a valid React element', () => { + const content = <div>Hello</div>; + const result = createContent(content); + + expect(result).toEqual(content); + }); + + test('should clone the element with props if props are provided', () => { + const content = <div></div>; + const props = { className: 'my-class' }; + const result = createContent(content, props); + + expect(result.props).toEqual(props); + }); + + test('should create an element with props if the content is a React component', () => { + const content = MyComponent; + const props = { className: 'my-class' }; + const result = createContent(content, props); + + expect(result.type).toEqual(content); + expect(result.props).toEqual(props); + }); + + test('should return the content if it is not a React element or a React component', () => { + const content = 'Hello'; + const result = createContent(content); + + expect(result).toEqual(content); + }); +}); diff --git a/packages/utils/test/src/create-defer.test.ts b/packages/utils/test/src/create-defer.test.ts new file mode 100644 index 0000000000..c6ab9207a9 --- /dev/null +++ b/packages/utils/test/src/create-defer.test.ts @@ -0,0 +1,16 @@ +import { createDefer } from '../../src/create-defer'; + +describe('createDefer', () => { + it('should resolve with given value', async () => { + const defer = createDefer<number>(); + defer.resolve(42); + const result = await defer.promise(); + expect(result).toBe(42); + }); + + it('should reject with given reason', async () => { + const defer = createDefer<number>(); + defer.reject('error'); + await expect(defer.promise()).rejects.toEqual('error'); + }); +}); diff --git a/packages/utils/test/src/is-object.test.ts b/packages/utils/test/src/is-object.test.ts new file mode 100644 index 0000000000..7ae984b8f8 --- /dev/null +++ b/packages/utils/test/src/is-object.test.ts @@ -0,0 +1,45 @@ +import { isObject, isI18NObject } from '../../src/is-object'; + +describe('isObject', () => { + it('should return true for an object', () => { + const obj = { key: 'value' }; + const result = isObject(obj); + expect(result).toBe(true); + }); + + it('should return false for null', () => { + const result = isObject(null); + expect(result).toBe(false); + }); + + it('should return false for a non-object value', () => { + const value = 42; // Not an object + const result = isObject(value); + expect(result).toBe(false); + }); +}); + +describe('isI18NObject', () => { + it('should return true for an I18N object', () => { + const i18nObject = { type: 'i18n', data: 'some data' }; + const result = isI18NObject(i18nObject); + expect(result).toBe(true); + }); + + it('should return false for a non-I18N object', () => { + const nonI18nObject = { type: 'other', data: 'some data' }; + const result = isI18NObject(nonI18nObject); + expect(result).toBe(false); + }); + + it('should return false for null', () => { + const result = isI18NObject(null); + expect(result).toBe(false); + }); + + it('should return false for a non-object value', () => { + const value = 42; // Not an object + const result = isI18NObject(value); + expect(result).toBe(false); + }); +}); diff --git a/packages/utils/test/src/is-react.test.ts b/packages/utils/test/src/is-react.test.ts deleted file mode 100644 index 74c88c9330..0000000000 --- a/packages/utils/test/src/is-react.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react"; -import { isReactComponent, wrapReactClass } from "../../src/is-react"; - -class reactDemo extends React.Component { - -} - -const reactMemo = React.memo(reactDemo); - -const reactForwardRef = React.forwardRef((props, ref): any => { - return ''; -}); - -describe('is-react-ut', () => { - it('isReactComponent', () => { - expect(isReactComponent(null)).toBeFalsy(); - expect(isReactComponent(() => {})).toBeTruthy(); - expect(isReactComponent({ - $$typeof: Symbol.for('react.memo') - })).toBeTruthy(); - expect(isReactComponent({ - $$typeof: Symbol.for('react.forward_ref') - })).toBeTruthy(); - expect(isReactComponent(reactDemo)).toBeTruthy(); - expect(isReactComponent(reactMemo)).toBeTruthy(); - expect(isReactComponent(reactForwardRef)).toBeTruthy(); - - }); - - it('wrapReactClass', () => { - const wrap = wrapReactClass(() => {}); - expect(isReactComponent(wrap)).toBeTruthy(); - - const fun = () => {}; - fun.displayName = 'mock'; - expect(wrapReactClass(fun).displayName).toBe('mock'); - }) -}) \ No newline at end of file diff --git a/packages/utils/test/src/is-react.test.tsx b/packages/utils/test/src/is-react.test.tsx new file mode 100644 index 0000000000..9ed2bd6c38 --- /dev/null +++ b/packages/utils/test/src/is-react.test.tsx @@ -0,0 +1,316 @@ +import React, { Component, createElement } from "react"; +import { + isReactComponent, + wrapReactClass, + isForwardOrMemoForward, + isMemoType, + isForwardRefType, + acceptsRef, + isReactClass, + REACT_MEMO_TYPE, + REACT_FORWARD_REF_TYPE, + } from "../../src/is-react"; + +class reactDemo extends React.Component { + +} + +const reactMemo = React.memo(reactDemo); + +const reactForwardRef = React.forwardRef((props, ref): any => { + return ''; +}); + +describe('is-react-ut', () => { + it('isReactComponent', () => { + expect(isReactComponent(null)).toBeFalsy(); + expect(isReactComponent(() => {})).toBeTruthy(); + expect(isReactComponent({ + $$typeof: Symbol.for('react.memo') + })).toBeTruthy(); + expect(isReactComponent({ + $$typeof: Symbol.for('react.forward_ref') + })).toBeTruthy(); + expect(isReactComponent(reactDemo)).toBeTruthy(); + expect(isReactComponent(reactMemo)).toBeTruthy(); + expect(isReactComponent(reactForwardRef)).toBeTruthy(); + + }); + + it('wrapReactClass', () => { + const wrap = wrapReactClass(() => {}); + expect(isReactComponent(wrap)).toBeTruthy(); + + const fun = () => {}; + fun.displayName = 'mock'; + expect(wrapReactClass(fun).displayName).toBe('mock'); + }) +}) + +describe('wrapReactClass', () => { + it('should wrap a FunctionComponent', () => { + // Create a mock FunctionComponent + const MockComponent: React.FunctionComponent = (props) => { + return <div>{props.children}</div>; + }; + + // Wrap the FunctionComponent using wrapReactClass + const WrappedComponent = wrapReactClass(MockComponent); + const instance = new WrappedComponent(); + + // Check if the WrappedComponent extends Component + expect(instance instanceof React.Component).toBe(true); + }); + + it('should render the FunctionComponent with props', () => { + // Create a mock FunctionComponent + const MockComponent: React.FunctionComponent = (props) => { + return <div>{props.children}</div>; + }; + + MockComponent.displayName = 'FunctionComponent'; + + // Wrap the FunctionComponent using wrapReactClass + const WrappedComponent = wrapReactClass(MockComponent); + + // Create some test props + const testProps = { prop1: 'value1', prop2: 'value2' }; + + // Render the WrappedComponent with test props + const rendered = createElement(WrappedComponent, testProps, 'Child Text'); + + // Check if the WrappedComponent renders the FunctionComponent with props + expect(rendered).toMatchSnapshot(); + }); +}); + +describe('isReactComponent', () => { + it('should identify a class component as a React component', () => { + class ClassComponent extends React.Component { + render() { + return <div>Class Component</div>; + } + } + + expect(isReactComponent(ClassComponent)).toBe(true); + }); + + it('should identify a functional component as a React component', () => { + const FunctionalComponent = () => { + return <div>Functional Component</div>; + }; + + expect(isReactComponent(FunctionalComponent)).toBe(true); + }); + + it('should identify a forward ref component as a React component', () => { + const ForwardRefComponent = React.forwardRef((props, ref) => { + return <div ref={ref}>Forward Ref Component</div>; + }); + + expect(isReactComponent(ForwardRefComponent)).toBe(true); + }); + + it('should identify a memo component as a React component', () => { + const MemoComponent = React.memo(() => { + return <div>Memo Component</div>; + }); + + expect(isReactComponent(MemoComponent)).toBe(true); + }); + + it('should return false for non-React components', () => { + const plainObject = { prop: 'value' }; + const notAComponent = 'Not a component'; + + expect(isReactComponent(plainObject)).toBe(false); + expect(isReactComponent(notAComponent)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isReactComponent(nullValue)).toBe(false); + expect(isReactComponent(undefinedValue)).toBe(false); + }); +}); + +describe('isForwardOrMemoForward', () => { + it('should return true for a forwardRef component', () => { + const forwardRefComponent = React.forwardRef(() => { + return <div>ForwardRef Component</div>; + }); + + expect(isForwardOrMemoForward(forwardRefComponent)).toBe(true); + }); + + it('should return true for a memoized forwardRef component', () => { + const forwardRefComponent = React.forwardRef(() => { + return <div>ForwardRef Component</div>; + }); + + const memoizedComponent = React.memo(forwardRefComponent); + + expect(isForwardOrMemoForward(memoizedComponent)).toBe(true); + }); + + it('should return false for a memoized component that is not a forwardRef', () => { + const memoizedComponent = React.memo(() => { + return <div>Memoized Component</div>; + }); + + expect(isForwardOrMemoForward(memoizedComponent)).toBe(false); + }); + + it('should return false for a plain object', () => { + const plainObject = { prop: 'value' }; + + expect(isForwardOrMemoForward(plainObject)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isForwardOrMemoForward(nullValue)).toBe(false); + expect(isForwardOrMemoForward(undefinedValue)).toBe(false); + }); +}); + +describe('isMemoType', () => { + it('should return true for an object with $$typeof matching REACT_MEMO_TYPE', () => { + const memoTypeObject = { $$typeof: REACT_MEMO_TYPE }; + + expect(isMemoType(memoTypeObject)).toBe(true); + }); + + it('should return false for an object with $$typeof not matching REACT_MEMO_TYPE', () => { + const otherTypeObject = { $$typeof: Symbol.for('other.type') }; + + expect(isMemoType(otherTypeObject)).toBe(false); + }); + + it('should return false for an object with no $$typeof property', () => { + const noTypeObject = { key: 'value' }; + + expect(isMemoType(noTypeObject)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isMemoType(nullValue)).toBe(false); + expect(isMemoType(undefinedValue)).toBe(false); + }); +}); + +describe('isForwardRefType', () => { + it('should return true for an object with $$typeof matching REACT_FORWARD_REF_TYPE', () => { + const forwardRefTypeObject = { $$typeof: REACT_FORWARD_REF_TYPE }; + + expect(isForwardRefType(forwardRefTypeObject)).toBe(true); + }); + + it('should return false for an object with $$typeof not matching REACT_FORWARD_REF_TYPE', () => { + const otherTypeObject = { $$typeof: Symbol.for('other.type') }; + + expect(isForwardRefType(otherTypeObject)).toBe(false); + }); + + it('should return false for an object with no $$typeof property', () => { + const noTypeObject = { key: 'value' }; + + expect(isForwardRefType(noTypeObject)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isForwardRefType(nullValue)).toBe(false); + expect(isForwardRefType(undefinedValue)).toBe(false); + }); +}); + +describe('acceptsRef', () => { + it('should return true for an object with isReactComponent in its prototype', () => { + const objWithIsReactComponent = { + prototype: { + isReactComponent: true, + }, + }; + + expect(acceptsRef(objWithIsReactComponent)).toBe(true); + }); + + it('should return true for an object that is forwardRef or memoized forwardRef', () => { + const forwardRefObject = React.forwardRef(() => { + return null; + }); + + const memoizedForwardRefObject = React.memo(forwardRefObject); + + expect(acceptsRef(forwardRefObject)).toBe(true); + expect(acceptsRef(memoizedForwardRefObject)).toBe(true); + }); + + it('should return false for an object without isReactComponent in its prototype', () => { + const objWithoutIsReactComponent = { + prototype: { + someOtherProperty: true, + }, + }; + + expect(acceptsRef(objWithoutIsReactComponent)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(acceptsRef(nullValue)).toBe(false); + expect(acceptsRef(undefinedValue)).toBe(false); + }); +}); + +describe('isReactClass', () => { + it('should return true for an object with isReactComponent in its prototype', () => { + class ReactClassComponent extends Component { + render() { + return null; + } + } + + expect(isReactClass(ReactClassComponent)).toBe(true); + }); + + it('should return true for an object with Component in its prototype chain', () => { + class CustomComponent extends Component { + render() { + return null; + } + } + + expect(isReactClass(CustomComponent)).toBe(true); + }); + + it('should return false for an object without isReactComponent in its prototype', () => { + class NonReactComponent { + render() { + return null; + } + } + + expect(isReactClass(NonReactComponent)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isReactClass(nullValue)).toBe(false); + expect(isReactClass(undefinedValue)).toBe(false); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/is-shaken.test.ts b/packages/utils/test/src/is-shaken.test.ts new file mode 100644 index 0000000000..35a27af5f6 --- /dev/null +++ b/packages/utils/test/src/is-shaken.test.ts @@ -0,0 +1,45 @@ +import { isShaken } from '../../src/is-shaken'; + +describe('isShaken', () => { + it('should return true if e1 has shaken property', () => { + const e1: any = { shaken: true }; + const e2: MouseEvent | DragEvent = { target: null } as MouseEvent | DragEvent; + + expect(isShaken(e1, e2)).toBe(true); + }); + + it('should return true if e1.target and e2.target are different', () => { + const e1: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent; + const e2: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent; + + expect(isShaken(e1, e2)).toBe(true); + }); + + it('should return false if e1 and e2 targets are the same and distance is less than SHAKE_DISTANCE', () => { + const target = {}; + const e1: MouseEvent | DragEvent = { target: target } as MouseEvent | DragEvent; + const e2: MouseEvent | DragEvent = { target: target } as MouseEvent | DragEvent; + + // Assuming SHAKE_DISTANCE is 100 + e1.clientY = 50; + e2.clientY = 50; + + e1.clientX = 60; + e2.clientX = 60; + + expect(isShaken(e1, e2)).toBe(false); + }); + + it('should return true if e1 and e2 targets are the same and distance is greater than SHAKE_DISTANCE', () => { + const e1: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent; + const e2: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent; + + // Assuming SHAKE_DISTANCE is 100 + e1.clientY = 50; + e1.clientX = 50; + e2.clientY = 200; + e2.clientX = 200; + + expect(isShaken(e1, e2)).toBe(true); + }); +}); diff --git a/packages/utils/test/src/misc.test.ts b/packages/utils/test/src/misc.test.ts index 8873dc4c80..2514661508 100644 --- a/packages/utils/test/src/misc.test.ts +++ b/packages/utils/test/src/misc.test.ts @@ -1,4 +1,321 @@ -import { shouldUseVariableSetter } from '../../src/misc'; +import { + isVariable, + isUseI18NSetter, + convertToI18NObject, + isString, + waitForThing, + arrShallowEquals, + isFromVC, + executePendingFn, + compatStage, + invariant, + isRegExp, + shouldUseVariableSetter, +} from '../../src/misc'; +import { IPublicModelComponentMeta } from '@alilc/lowcode-types'; + +describe('isVariable', () => { + it('should return true for a variable object', () => { + const variable = { type: 'variable', variable: 'foo', value: 'bar' }; + const result = isVariable(variable); + expect(result).toBe(true); + }); + + it('should return false for non-variable objects', () => { + const obj = { type: 'object' }; + const result = isVariable(obj); + expect(result).toBe(false); + }); +}); + +describe('isUseI18NSetter', () => { + it('should return true for a property with I18nSetter', () => { + const prototype = { options: { configure: [{ name: 'propName', setter: { type: { displayName: 'I18nSetter' } } }] } }; + const propName = 'propName'; + const result = isUseI18NSetter(prototype, propName); + expect(result).toBe(true); + }); + + it('should return false for a property without I18nSetter', () => { + const prototype = { options: { configure: [{ name: 'propName', setter: { type: { displayName: 'OtherSetter' } } }] } }; + const propName = 'propName'; + const result = isUseI18NSetter(prototype, propName); + expect(result).toBe(false); + }); +}); + +describe('convertToI18NObject', () => { + it('should return the input if it is already an I18N object', () => { + const i18nObject = { type: 'i18n', use: 'en', en: 'Hello' }; + const result = convertToI18NObject(i18nObject); + expect(result).toEqual(i18nObject); + }); + + it('should convert a string to an I18N object', () => { + const inputString = 'Hello'; + const result = convertToI18NObject(inputString); + const expectedOutput = { type: 'i18n', use: 'zh-CN', 'zh-CN': inputString }; + expect(result).toEqual(expectedOutput); + }); +}); + +describe('isString', () => { + it('should return true for a string', () => { + const stringValue = 'Hello, world!'; + const result = isString(stringValue); + expect(result).toBe(true); + }); + + it('should return true for an empty string', () => { + const emptyString = ''; + const result = isString(emptyString); + expect(result).toBe(true); + }); + + it('should return false for a number', () => { + const numberValue = 42; // Not a string + const result = isString(numberValue); + expect(result).toBe(false); + }); + + it('should return false for an object', () => { + const objectValue = { key: 'value' }; // Not a string + const result = isString(objectValue); + expect(result).toBe(false); + }); + + it('should return false for null', () => { + const result = isString(null); + expect(result).toBe(false); + }); + + it('should return false for undefined', () => { + const undefinedValue = undefined; + const result = isString(undefinedValue); + expect(result).toBe(false); + }); + + it('should return false for a boolean', () => { + const booleanValue = true; // Not a string + const result = isString(booleanValue); + expect(result).toBe(false); + }); +}); + +describe('waitForThing', () => { + it('should resolve immediately if the thing is available', async () => { + const obj = { prop: 'value' }; + const path = 'prop'; + const result = await waitForThing(obj, path); + expect(result).toBe('value'); + }); + + it('should resolve after a delay if the thing becomes available', async () => { + const obj = { prop: undefined }; + const path = 'prop'; + const delay = 100; // Adjust the delay as needed + setTimeout(() => { + obj.prop = 'value'; + }, delay); + + const result = await waitForThing(obj, path); + expect(result).toBe('value'); + }); +}); + +describe('arrShallowEquals', () => { + it('should return true for two empty arrays', () => { + const arr1 = []; + const arr2 = []; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(true); + }); + + it('should return true for two arrays with the same elements in the same order', () => { + const arr1 = [1, 2, 3]; + const arr2 = [1, 2, 3]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(true); + }); + + it('should return true for two arrays with the same elements in a different order', () => { + const arr1 = [1, 2, 3]; + const arr2 = [3, 2, 1]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(true); + }); + + it('should return false for two arrays with different lengths', () => { + const arr1 = [1, 2, 3]; + const arr2 = [1, 2]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(false); + }); + + it('should return false for one array and a non-array', () => { + const arr1 = [1, 2, 3]; + const nonArray = 'not an array'; + const result = arrShallowEquals(arr1, nonArray); + expect(result).toBe(false); + }); + + it('should return false for two arrays with different elements', () => { + const arr1 = [1, 2, 3]; + const arr2 = [3, 4, 5]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(false); + }); + + it('should return true for arrays with duplicate elements', () => { + const arr1 = [1, 2, 2, 3]; + const arr2 = [2, 3, 3, 1]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(true); + }); +}); + +describe('isFromVC', () => { + it('should return true when advanced configuration is present', () => { + // Create a mock meta object with advanced configuration + const meta: IPublicModelComponentMeta = { + getMetadata: () => ({ configure: { advanced: true } }), + }; + + const result = isFromVC(meta); + + expect(result).toBe(true); + }); + + it('should return false when advanced configuration is not present', () => { + // Create a mock meta object without advanced configuration + const meta: IPublicModelComponentMeta = { + getMetadata: () => ({ configure: { advanced: false } }), + }; + + const result = isFromVC(meta); + + expect(result).toBe(false); + }); + + it('should return false when meta is undefined', () => { + const meta: IPublicModelComponentMeta | undefined = undefined; + + const result = isFromVC(meta); + + expect(result).toBe(false); + }); + + it('should return false when meta does not have configure information', () => { + // Create a mock meta object without configure information + const meta: IPublicModelComponentMeta = { + getMetadata: () => ({}), + }; + + const result = isFromVC(meta); + + expect(result).toBe(false); + }); + + it('should return false when configure.advanced is not present', () => { + // Create a mock meta object with incomplete configure information + const meta: IPublicModelComponentMeta = { + getMetadata: () => ({ configure: {} }), + }; + + const result = isFromVC(meta); + + expect(result).toBe(false); + }); +}); + +describe('executePendingFn', () => { + it('should execute the provided function after the specified timeout', async () => { + // Mock the function to execute + const fn = jest.fn(); + + // Call executePendingFn with the mocked function and a short timeout + executePendingFn(fn, 100); + + // Ensure the function has not been called immediately + expect(fn).not.toHaveBeenCalled(); + + // Wait for the specified timeout + await new Promise(resolve => setTimeout(resolve, 100)); + + // Ensure the function has been called after the timeout + expect(fn).toHaveBeenCalled(); + }); + + it('should execute the provided function with a default timeout if not specified', async () => { + // Mock the function to execute + const fn = jest.fn(); + + // Call executePendingFn with the mocked function without specifying a timeout + executePendingFn(fn); + + // Ensure the function has not been called immediately + expect(fn).not.toHaveBeenCalled(); + + // Wait for the default timeout (2000 milliseconds) + await new Promise(resolve => setTimeout(resolve, 2000)); + + // Ensure the function has been called after the default timeout + expect(fn).toHaveBeenCalled(); + }); +}); + +describe('compatStage', () => { + it('should convert a number to an enum stage', () => { + const result = compatStage(3); + expect(result).toBe('save'); + }); + + it('should warn about the deprecated usage', () => { + const warnSpy = jest.spyOn(console, 'warn'); + const result = compatStage(2); + expect(result).toBe('serilize'); + expect(warnSpy).toHaveBeenCalledWith( + 'stage 直接指定为数字的使用方式已经过时,将在下一版本移除,请直接使用 IPublicEnumTransformStage.Render|Serilize|Save|Clone|Init|Upgrade' + ); + warnSpy.mockRestore(); + }); + + it('should return the enum stage if it is already an enum', () => { + const result = compatStage('render'); + expect(result).toBe('render'); + }); +}); + +describe('invariant', () => { + it('should not throw an error if the check is true', () => { + expect(() => invariant(true, 'Test invariant', 'thing')).not.toThrow(); + }); + + it('should throw an error if the check is false', () => { + expect(() => invariant(false, 'Test invariant', 'thing')).toThrowError( + "Invariant failed: Test invariant in 'thing'" + ); + }); +}); + +describe('isRegExp', () => { + it('should return true for a valid RegExp', () => { + const regex = /test/; + const result = isRegExp(regex); + expect(result).toBe(true); + }); + + it('should return false for a non-RegExp object', () => { + const nonRegExp = { test: /test/ }; + const result = isRegExp(nonRegExp); + expect(result).toBe(false); + }); + + it('should return false for null', () => { + const result = isRegExp(null); + expect(result).toBe(false); + }); +}); it('shouldUseVariableSetter', () => { expect(shouldUseVariableSetter(false, true)).toBeFalsy(); diff --git a/packages/utils/test/src/navtive-selection.test.ts b/packages/utils/test/src/navtive-selection.test.ts new file mode 100644 index 0000000000..f45d0e1b2a --- /dev/null +++ b/packages/utils/test/src/navtive-selection.test.ts @@ -0,0 +1,18 @@ +import { setNativeSelection, nativeSelectionEnabled } from '../../src/navtive-selection'; + +describe('setNativeSelection', () => { + beforeEach(() => { + // 在每个测试运行之前重置nativeSelectionEnabled的值 + setNativeSelection(true); + }); + + test('should enable native selection', () => { + setNativeSelection(true); + expect(nativeSelectionEnabled).toBe(true); + }); + + test('should disable native selection', () => { + setNativeSelection(false); + expect(nativeSelectionEnabled).toBe(false); + }); +}); diff --git a/packages/utils/test/src/schema.test.ts b/packages/utils/test/src/schema.test.ts index 138dd7a82e..8d03f58118 100644 --- a/packages/utils/test/src/schema.test.ts +++ b/packages/utils/test/src/schema.test.ts @@ -1,4 +1,132 @@ -import { compatibleLegaoSchema } from '../../src/schema'; +import { + compatibleLegaoSchema, + getNodeSchemaById, + applyActivities, +} from '../../src/schema'; +import { ActivityType } from '@alilc/lowcode-types'; + +describe('compatibleLegaoSchema', () => { + it('should handle null input', () => { + const result = compatibleLegaoSchema(null); + expect(result).toBeNull(); + }); + + it('should convert Legao schema to JSExpression', () => { + // Create your test input + const legaoSchema = { + type: 'LegaoType', + source: 'LegaoSource', + compiled: 'LegaoCompiled', + }; + const result = compatibleLegaoSchema(legaoSchema); + + // Define the expected output + const expectedOutput = { + type: 'JSExpression', + value: 'LegaoCompiled', + extType: 'function', + }; + + // Assert that the result matches the expected output + expect(result).toEqual(expectedOutput); + }); + + // Add more test cases for other scenarios +}); + +describe('getNodeSchemaById', () => { + it('should find a node in the schema', () => { + // Create your test schema and node ID + const testSchema = { + id: 'root', + children: [ + { + id: 'child1', + children: [ + { + id: 'child1.1', + }, + ], + }, + ], + }; + const nodeId = 'child1.1'; + + const result = getNodeSchemaById(testSchema, nodeId); + + // Define the expected output + const expectedOutput = { + id: 'child1.1', + }; + + // Assert that the result matches the expected output + expect(result).toEqual(expectedOutput); + }); + + // Add more test cases for other scenarios +}); + +describe('applyActivities', () => { + it('should apply ADD activity', () => { + // Create your test schema and activities + const testSchema = { + id: 'root', + children: [ + { + id: 'child1', + children: [ + { + id: 'child1.1', + }, + ], + }, + ], + }; + const activities = [ + { + type: ActivityType.ADDED, + payload: { + location: { + parent: { + nodeId: 'child1', + index: 0, + }, + }, + schema: { + id: 'newChild', + }, + }, + }, + ]; + + const result = applyActivities(testSchema, activities); + + // Define the expected output + const expectedOutput = { + id: 'root', + children: [ + { + id: 'child1', + children: [ + { + id: 'newChild', + }, + { + id: 'child1.1', + }, + ], + }, + ], + }; + + // Assert that the result matches the expected output + expect(result).toEqual(expectedOutput); + }); + + // Add more test cases for other activity types and scenarios +}); + + describe('Schema Ut', () => { it('props', () => { const schema = { diff --git a/packages/utils/test/src/script.test.ts b/packages/utils/test/src/script.test.ts new file mode 100644 index 0000000000..d3d4ffd59a --- /dev/null +++ b/packages/utils/test/src/script.test.ts @@ -0,0 +1,47 @@ +import { + evaluate, + evaluateExpression, + newFunction, +} from '../../src/script'; + +describe('evaluate', () => { + test('should evaluate the given script', () => { + const script = 'console.log("Hello, world!");'; + global.console = { log: jest.fn() }; + + evaluate(script); + + expect(global.console.log).toHaveBeenCalledWith('Hello, world!'); + }); +}); + +describe('evaluateExpression', () => { + test('should evaluate the given expression', () => { + const expr = 'return 1 + 2'; + + const result = evaluateExpression(expr); + + expect(result).toBe(3); + }); +}); + +describe('newFunction', () => { + test('should create a new function with the given arguments and code', () => { + const args = 'a, b'; + const code = 'return a + b'; + + const result = newFunction(args, code); + + expect(result).toBeInstanceOf(Function); + expect(result(1, 2)).toBe(3); + }); + + test('should return null if an error occurs', () => { + const args = 'a, b'; + const code = 'return a +;'; // Invalid code + + const result = newFunction(args, code); + + expect(result).toBeNull(); + }); +}); diff --git a/packages/utils/test/src/svg-icon.test.tsx b/packages/utils/test/src/svg-icon.test.tsx new file mode 100644 index 0000000000..bbb6e18b7c --- /dev/null +++ b/packages/utils/test/src/svg-icon.test.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { SVGIcon, IconProps } from '../../src/svg-icon'; + +describe('SVGIcon', () => { + it('should render SVG element with correct size', () => { + const iconProps: IconProps = { + size: 'small', + viewBox: '0 0 24 24', + }; + + const { container } = render(<SVGIcon {...iconProps} />); + + const svgElement = container.querySelector('svg'); + + expect(svgElement).toHaveAttribute('width', '12'); + expect(svgElement).toHaveAttribute('height', '12'); + }); + + it('should render SVG element with custom size', () => { + const iconProps: IconProps = { + size: 24, + viewBox: '0 0 24 24', + }; + + const { container } = render(<SVGIcon {...iconProps} />); + + const svgElement = container.querySelector('svg'); + + expect(svgElement).toHaveAttribute('width', '24'); + expect(svgElement).toHaveAttribute('height', '24'); + }); + + // Add more tests for other scenarios if needed +}); diff --git a/packages/utils/test/src/transaction-manager.test.ts b/packages/utils/test/src/transaction-manager.test.ts new file mode 100644 index 0000000000..42c7fa8bf0 --- /dev/null +++ b/packages/utils/test/src/transaction-manager.test.ts @@ -0,0 +1,58 @@ +import { transactionManager } from '../../src/transaction-manager'; +import { IPublicEnumTransitionType } from '@alilc/lowcode-types'; + +const type = IPublicEnumTransitionType.REPAINT; + +describe('TransactionManager', () => { + let fn1: jest.Mock; + let fn2: jest.Mock; + + beforeEach(() => { + fn1 = jest.fn(); + fn2 = jest.fn(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('executeTransaction should emit startTransaction and endTransaction events', () => { + const startTransactionSpy = jest.spyOn(transactionManager.emitter, 'emit'); + const endTransactionSpy = jest.spyOn(transactionManager.emitter, 'emit'); + + transactionManager.executeTransaction(() => { + // Perform some action within the transaction + }); + + expect(startTransactionSpy).toHaveBeenCalledWith(`[${type}]startTransaction`); + expect(endTransactionSpy).toHaveBeenCalledWith(`[${type}]endTransaction`); + }); + + test('onStartTransaction should register the provided function for startTransaction event', () => { + const offSpy = jest.spyOn(transactionManager.emitter, 'off'); + + const offFunction = transactionManager.onStartTransaction(fn1); + + expect(transactionManager.emitter.listenerCount(`[${type}]startTransaction`)).toBe(1); + expect(offSpy).not.toHaveBeenCalled(); + + offFunction(); + + expect(transactionManager.emitter.listenerCount(`[${type}]startTransaction`)).toBe(0); + expect(offSpy).toHaveBeenCalledWith(`[${type}]startTransaction`, fn1); + }); + + test('onEndTransaction should register the provided function for endTransaction event', () => { + const offSpy = jest.spyOn(transactionManager.emitter, 'off'); + + const offFunction = transactionManager.onEndTransaction(fn2); + + expect(transactionManager.emitter.listenerCount(`[${type}]endTransaction`)).toBe(1); + expect(offSpy).not.toHaveBeenCalled(); + + offFunction(); + + expect(transactionManager.emitter.listenerCount(`[${type}]endTransaction`)).toBe(0); + expect(offSpy).toHaveBeenCalledWith(`[${type}]endTransaction`, fn2); + }); +}); diff --git a/packages/utils/test/src/unique-id.test.ts b/packages/utils/test/src/unique-id.test.ts new file mode 100644 index 0000000000..2b4b6e9e04 --- /dev/null +++ b/packages/utils/test/src/unique-id.test.ts @@ -0,0 +1,11 @@ +import { uniqueId } from '../../src/unique-id'; + +test('uniqueId should return a unique id with prefix', () => { + const id = uniqueId('test'); + expect(id.startsWith('test')).toBeTruthy(); +}); + +test('uniqueId should return a unique id without prefix', () => { + const id = uniqueId(); + expect(id).not.toBeFalsy(); +}); From 151748dbab0989555c1161721044ad4a2d29a2ff Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 13 Nov 2023 13:36:07 +0800 Subject: [PATCH 308/469] docs: add before start doc --- docs/docs/guide/quickStart/demo.md | 2 +- docs/docs/guide/quickStart/intro.md | 17 ++++++++++++++++- docs/docs/guide/quickStart/start.md | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/docs/guide/quickStart/demo.md b/docs/docs/guide/quickStart/demo.md index a05a42486d..ee76d5aa1b 100644 --- a/docs/docs/guide/quickStart/demo.md +++ b/docs/docs/guide/quickStart/demo.md @@ -1,6 +1,6 @@ --- title: 试用低代码引擎 Demo -sidebar_position: 1 +sidebar_position: 2 --- ## 访问地址 diff --git a/docs/docs/guide/quickStart/intro.md b/docs/docs/guide/quickStart/intro.md index 661f5912f7..b65baac269 100644 --- a/docs/docs/guide/quickStart/intro.md +++ b/docs/docs/guide/quickStart/intro.md @@ -1,6 +1,6 @@ --- title: 简介 -sidebar_position: 0 +sidebar_position: 1 --- # 阿里低代码引擎简介 @@ -46,3 +46,18 @@ sidebar_position: 0 **低代码设计器研发框架** 低代码引擎的核心是设计器,通过扩展、周边生态等可以产出各式各样的设计器。它不是一套可以适合所有人的低代码平台,而是帮助低代码平台的开发者,快速生产低代码平台的工具。 + +## 寻找适合您的低代码解决方案 + +帮助用户根据个人或企业需求选择合适的低代码产品。 + +| 特性/产品 | 低代码引擎 | Lab平台 | UIPaaS | +|-----------------|-----------------------------------------|-----------------------------------------|--------------------------------------------| +| **适用用户** | 前端开发者 | 需要快速搭建应用/页面的用户 | 企业用户,需要大规模部署低代码解决方案的组织 | +| **产品特点** | 设计器研发框架,适合定制开发 | 低代码平台, 可视化操作界面,易于上手 | 低代码平台孵化器,企业级功能 | +| **使用场景** | 定制和开发低代码平台的设计器部分 | 通过可视化, 快速开发应用或页面 | 帮助具有一定规模软件研发团队的的企业低成本定制低代码平台 | +| **产品关系** | 开源产品 | 基于UIPaaS技术实现, 展示了UIPaaS的部分能力 | 提供完整的低代码平台解决方案,商业产品 | +| **收费情况** | 免费 | 可免费使用(有额度限制),不提供私有化部署售卖 | 仅提供私有化部署售卖 | +| **官方网站** | [低代码引擎官网](https://lowcode-engine.cn/) | [Lab平台官网](https://lab.lowcode-engine.cn/) | [UIPaaS官网](https://uipaas.net/) | + +*注:请根据您的具体需求和条件选择合适的产品。如需更详细的信息,请访问各产品的官方网站。* diff --git a/docs/docs/guide/quickStart/start.md b/docs/docs/guide/quickStart/start.md index b2b728b9fe..356f501769 100644 --- a/docs/docs/guide/quickStart/start.md +++ b/docs/docs/guide/quickStart/start.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 3 title: 快速开始 --- From ef6a203a45ae7d8d0d4708bac28d36d10d7d4b07 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 13 Nov 2023 14:09:58 +0800 Subject: [PATCH 309/469] chore(docs): publish docs 1.1.16 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 27d1a17d04..c206cdf16a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.15", + "version": "1.1.16", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 9108e8cfabdb442064f43be0533538ebbaff7f4a Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 13 Nov 2023 18:46:17 +0800 Subject: [PATCH 310/469] feat(types): add IPublicTypeInstanceOf to prop-types --- packages/types/src/shell/type/prop-types.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/types/src/shell/type/prop-types.ts b/packages/types/src/shell/type/prop-types.ts index a3344b0591..22d84c86fc 100644 --- a/packages/types/src/shell/type/prop-types.ts +++ b/packages/types/src/shell/type/prop-types.ts @@ -3,7 +3,7 @@ import { IPublicTypePropConfig } from './'; export type IPublicTypePropType = IPublicTypeBasicType | IPublicTypeRequiredType | IPublicTypeComplexType; export type IPublicTypeBasicType = 'array' | 'bool' | 'func' | 'number' | 'object' | 'string' | 'node' | 'element' | 'any'; -export type IPublicTypeComplexType = IPublicTypeOneOf | IPublicTypeOneOfType | IPublicTypeArrayOf | IPublicTypeObjectOf | IPublicTypeShape | IPublicTypeExact; +export type IPublicTypeComplexType = IPublicTypeOneOf | IPublicTypeOneOfType | IPublicTypeArrayOf | IPublicTypeObjectOf | IPublicTypeShape | IPublicTypeExact | IPublicTypeInstanceOf; export interface IPublicTypeRequiredType { type: IPublicTypeBasicType; @@ -40,3 +40,9 @@ export interface IPublicTypeExact { value: IPublicTypePropConfig[]; isRequired?: boolean; } + +export interface IPublicTypeInstanceOf { + type: 'instanceOf'; + value: IPublicTypePropConfig; + isRequired?: boolean; +} From 1020f98756c6a4886f8dd755c5fca3ff6f374876 Mon Sep 17 00:00:00 2001 From: beautiful-boyyy <66351806+beautiful-boyyy@users.noreply.github.com> Date: Tue, 14 Nov 2023 09:48:36 +0800 Subject: [PATCH 311/469] chore: remove useless code (#2643) --- .../editor-skeleton/src/components/widget-views/index.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index 513fc1bdd6..ba49b3d1ab 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -232,12 +232,8 @@ export class PanelView extends Component<{ this.lastVisible = currentVisible; if (this.lastVisible) { panel.skeleton.postEvent(SkeletonEvents.PANEL_SHOW, panel.name, panel); - // FIXME! remove this line - panel.skeleton.postEvent('leftPanel.show' as any, panel.name, panel); } else { panel.skeleton.postEvent(SkeletonEvents.PANEL_HIDE, panel.name, panel); - // FIXME! remove this line - panel.skeleton.postEvent('leftPanel.hide' as any, panel.name, panel); } } } From b697ea9ad4399a90cf2560b45beb4ae669700fbc Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 14 Nov 2023 09:55:58 +0800 Subject: [PATCH 312/469] feat(render-core): update logger to console --- .../designer/src/builtin-simulator/index.ts | 1 + .../builtin-simulator/utils/parse-metadata.ts | 6 ++- packages/renderer-core/babel.config.js | 1 + packages/renderer-core/src/hoc/leaf.tsx | 3 +- packages/renderer-core/src/renderer/addon.tsx | 3 +- packages/renderer-core/src/renderer/base.tsx | 14 +++---- packages/renderer-core/src/renderer/temp.tsx | 3 +- packages/renderer-core/src/utils/common.ts | 6 +-- .../renderer-core/src/utils/data-helper.ts | 10 ++--- .../renderer-core/tests/utils/common.test.ts | 40 ++++++++++++++++++- .../tests/utils/data-helper.test.ts | 10 ----- 11 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 packages/renderer-core/babel.config.js diff --git a/packages/designer/src/builtin-simulator/index.ts b/packages/designer/src/builtin-simulator/index.ts index 6bcee7eb76..6977fd66c6 100644 --- a/packages/designer/src/builtin-simulator/index.ts +++ b/packages/designer/src/builtin-simulator/index.ts @@ -2,3 +2,4 @@ export * from './host'; export * from './host-view'; export * from './renderer'; export * from './live-editing/live-editing'; +export { LowcodeTypes } from './utils/parse-metadata'; diff --git a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts index b84e4e6985..5c81340a14 100644 --- a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts +++ b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts @@ -46,13 +46,15 @@ function define(propType: any = PropTypes.any, lowcodeType: string | object = {} return lowcodeCheckType; } -const LowcodeTypes: any = { +export const LowcodeTypes: any = { ...PropTypes, define, }; (window as any).PropTypes = LowcodeTypes; -(window as any).React.PropTypes = LowcodeTypes; +if ((window as any).React) { + (window as any).React.PropTypes = LowcodeTypes; +} // override primitive type checkers primitiveTypes.forEach((type) => { diff --git a/packages/renderer-core/babel.config.js b/packages/renderer-core/babel.config.js new file mode 100644 index 0000000000..c5986f2bc0 --- /dev/null +++ b/packages/renderer-core/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../../babel.config'); \ No newline at end of file diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index 1ff91cb147..2bb3c0b368 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -4,6 +4,7 @@ import { isReactComponent, cloneEnumerableProperty } from '@alilc/lowcode-utils' import { debounce } from '../utils/common'; import adapter from '../adapter'; import * as types from '../types/index'; +import logger from '../utils/logger'; export interface IComponentHocInfo { schema: any; @@ -183,7 +184,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { } if (!isReactComponent(Comp)) { - console.error(`${schema.componentName} component may be has errors: `, Comp); + logger.error(`${schema.componentName} component may be has errors: `, Comp); } initRerenderEvent({ diff --git a/packages/renderer-core/src/renderer/addon.tsx b/packages/renderer-core/src/renderer/addon.tsx index 9cb114bee4..211ec182f2 100644 --- a/packages/renderer-core/src/renderer/addon.tsx +++ b/packages/renderer-core/src/renderer/addon.tsx @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import baseRendererFactory from './base'; import { isEmpty } from '../utils'; import { IRendererAppHelper, IBaseRendererProps, IBaseRenderComponent } from '../types'; +import logger from '../utils/logger'; export default function addonRendererFactory(): IBaseRenderComponent { const BaseRenderer = baseRendererFactory(); @@ -32,7 +33,7 @@ export default function addonRendererFactory(): IBaseRenderComponent { const schema = props.__schema || {}; this.state = this.__parseData(schema.state || {}); if (isEmpty(props.config) || !props.config?.addonKey) { - console.warn('lce addon has wrong config'); + logger.warn('lce addon has wrong config'); this.setState({ __hasError: true, }); diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 1980734e43..6c2a04aa78 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -56,14 +56,14 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche } if (typeof fn !== 'function') { - console.error(`生命周期${method}类型不符`, fn); + logger.error(`生命周期${method}类型不符`, fn); return; } try { return fn.apply(context, args); } catch (e) { - console.error(`[${schema.componentName}]生命周期${method}出错`, e); + logger.error(`[${schema.componentName}]生命周期${method}出错`, e); } } @@ -208,7 +208,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { async componentDidCatch(...args: any[]) { this.__executeLifeCycleMethod('componentDidCatch', args); - console.warn(args); + logger.warn(args); } reloadDataSource = () => new Promise((resolve, reject) => { @@ -278,7 +278,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { value = this.__parseExpression(value, this); } if (typeof value !== 'function') { - console.error(`custom method ${key} can not be parsed to a valid function`, value); + logger.error(`custom method ${key} can not be parsed to a valid function`, value); return; } this[key] = value.bind(this); @@ -369,7 +369,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { this.setLocale = (loc: string) => { const setLocaleFn = this.appHelper?.utils?.i18n?.setLocale; if (!setLocaleFn || typeof setLocaleFn !== 'function') { - console.warn('initI18nAPIs Failed, i18n only works when appHelper.utils.i18n.setLocale() exists'); + logger.warn('initI18nAPIs Failed, i18n only works when appHelper.utils.i18n.setLocale() exists'); return undefined; } return setLocaleFn(loc); @@ -527,7 +527,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { : {}; if (!Comp) { - console.error(`${schema.componentName} component is not found in components list! component list is:`, components || this.props.__container?.components); + logger.error(`${schema.componentName} component is not found in components list! component list is:`, components || this.props.__container?.components); return engine.createElement( engine.getNotFoundComponent(), { @@ -749,7 +749,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { __createLoopVirtualDom = (schema: IPublicTypeNodeSchema, scope: any, parentInfo: INodeInfo, idx: number | string) => { if (isFileSchema(schema)) { - console.warn('file type not support Loop'); + logger.warn('file type not support Loop'); return null; } if (!Array.isArray(schema.loop)) { diff --git a/packages/renderer-core/src/renderer/temp.tsx b/packages/renderer-core/src/renderer/temp.tsx index 83adef7e30..1432da5fd2 100644 --- a/packages/renderer-core/src/renderer/temp.tsx +++ b/packages/renderer-core/src/renderer/temp.tsx @@ -1,4 +1,5 @@ import { IBaseRenderComponent } from '../types'; +import logger from '../utils/logger'; import baseRendererFactory from './base'; export default function tempRendererFactory(): IBaseRenderComponent { @@ -41,7 +42,7 @@ export default function tempRendererFactory(): IBaseRenderComponent { } async componentDidCatch(e: any) { - console.warn(e); + logger.warn(e); this.__debug(`componentDidCatch - ${this.props.__schema.fileName}`); } diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts index 29381b5473..495744acd9 100644 --- a/packages/renderer-core/src/utils/common.ts +++ b/packages/renderer-core/src/utils/common.ts @@ -183,13 +183,13 @@ export function transformArrayToMap(arr: any[], key: string, overwrite = true) { return res; } -export function checkPropTypes(value: any, name: string, rule: any, componentName: string) { +export function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean { let ruleFunction = rule; if (typeof rule === 'string') { ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2); } if (!ruleFunction || typeof ruleFunction !== 'function') { - console.warn('checkPropTypes should have a function type rule argument'); + logger.warn('checkPropTypes should have a function type rule argument'); return true; } const err = ruleFunction( @@ -203,7 +203,7 @@ export function checkPropTypes(value: any, name: string, rule: any, componentNam ReactPropTypesSecret, ); if (err) { - console.warn(err); + logger.warn(err); } return !err; } diff --git a/packages/renderer-core/src/utils/data-helper.ts b/packages/renderer-core/src/utils/data-helper.ts index d884c13c97..41bcb9bfa0 100644 --- a/packages/renderer-core/src/utils/data-helper.ts +++ b/packages/renderer-core/src/utils/data-helper.ts @@ -186,7 +186,7 @@ export class DataHelper { } const { headers, ...otherProps } = otherOptionsObj || {}; if (!req) { - console.warn(`getDataSource API named ${id} not exist`); + logger.warn(`getDataSource API named ${id} not exist`); return; } @@ -215,7 +215,7 @@ export class DataHelper { try { callbackFn && callbackFn(res && res[id]); } catch (e) { - console.error('load请求回调函数报错', e); + logger.error('load请求回调函数报错', e); } return res && res[id]; }) @@ -223,7 +223,7 @@ export class DataHelper { try { callbackFn && callbackFn(null, err); } catch (e) { - console.error('load请求回调函数报错', e); + logger.error('load请求回调函数报错', e); } return err; }); @@ -300,9 +300,9 @@ export class DataHelper { return dataHandlerFun.call(this.host, data, error); } catch (e) { if (id) { - console.error(`[${id}]单个请求数据处理函数运行出错`, e); + logger.error(`[${id}]单个请求数据处理函数运行出错`, e); } else { - console.error('请求数据处理函数运行出错', e); + logger.error('请求数据处理函数运行出错', e); } } } diff --git a/packages/renderer-core/tests/utils/common.test.ts b/packages/renderer-core/tests/utils/common.test.ts index 995e55642e..2ee3ed4dcc 100644 --- a/packages/renderer-core/tests/utils/common.test.ts +++ b/packages/renderer-core/tests/utils/common.test.ts @@ -1,4 +1,4 @@ -// @ts-nocheck +import factoryWithTypeCheckers from 'prop-types/factoryWithTypeCheckers'; import { isSchema, isFileSchema, @@ -18,9 +18,14 @@ import { parseThisRequiredExpression, parseI18n, parseData, + checkPropTypes, } from '../../src/utils/common'; import logger from '../../src/utils/logger'; +var ReactIs = require('react-is'); + +const PropTypes = factoryWithTypeCheckers(ReactIs.isElement, true); + describe('test isSchema', () => { it('should be false when empty value is passed', () => { expect(isSchema(null)).toBeFalsy(); @@ -461,4 +466,37 @@ describe('test parseData ', () => { expect(result.__privateKey).toBeUndefined(); }); +}); + +describe('checkPropTypes', () => { + it('should validate correctly with valid prop type', () => { + expect(checkPropTypes(123, 'age', PropTypes.number, 'TestComponent')).toBe(true); + expect(checkPropTypes('123', 'age', PropTypes.string, 'TestComponent')).toBe(true); + }); + + it('should log a warning and return false with invalid prop type', () => { + expect(checkPropTypes(123, 'age', PropTypes.string, 'TestComponent')).toBe(false); + expect(checkPropTypes('123', 'age', PropTypes.number, 'TestComponent')).toBe(false); + }); + + it('should handle custom rule functions correctly', () => { + const customRule = (props, propName) => { + if (props[propName] !== 123) { + return new Error('Invalid value'); + } + }; + const result = checkPropTypes(123, 'customProp', customRule, 'TestComponent'); + expect(result).toBe(true); + }); + + + it('should interpret and validate a rule given as a string', () => { + const result = checkPropTypes(123, 'age', 'PropTypes.number', 'TestComponent'); + expect(result).toBe(true); + }); + + it('should log a warning for invalid rule type', () => { + const result = checkPropTypes(123, 'age', 123, 'TestComponent'); + expect(result).toBe(true); + }); }); \ No newline at end of file diff --git a/packages/renderer-core/tests/utils/data-helper.test.ts b/packages/renderer-core/tests/utils/data-helper.test.ts index cd4508ea87..f4b388ce92 100644 --- a/packages/renderer-core/tests/utils/data-helper.test.ts +++ b/packages/renderer-core/tests/utils/data-helper.test.ts @@ -346,11 +346,6 @@ describe('test DataHelper ', () => { result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null); expect(result).toStrictEqual({ data: 'mockDataValue' }); - // test exception - const mockError = jest.fn(); - const orginalConsole = global.console; - global.console = { error: mockError }; - // exception with id mockDataHandler = { type: 'JSFunction', @@ -358,7 +353,6 @@ describe('test DataHelper ', () => { }; result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null); expect(result).toBeUndefined(); - expect(mockError).toBeCalledWith('[fullConfigGet]单个请求数据处理函数运行出错', expect.anything()); // exception without id mockDataHandler = { @@ -367,12 +361,8 @@ describe('test DataHelper ', () => { }; result = dataHelper.handleData(null, mockDataHandler, { data: 'mockDataValue' }, null); expect(result).toBeUndefined(); - expect(mockError).toBeCalledWith('请求数据处理函数运行出错', expect.anything()); - - global.console = orginalConsole; }); - it('updateConfig should work', () => { const mockHost = { stateA: 'aValue'}; const mockDataSourceConfig = { From 944012ab3ff56bb9ec5781b1c9ecb0d14a165581 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 14 Nov 2023 11:46:13 +0800 Subject: [PATCH 313/469] test(designer): add test ut to sequencify --- packages/designer/jest.config.js | 1 + packages/designer/src/plugin/sequencify.ts | 58 ++++++-- .../designer/tests/plugin/sequencify.test.ts | 128 ++++++++++++++++++ 3 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 packages/designer/tests/plugin/sequencify.test.ts diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index 1ecebd9388..f0ad2e861e 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -20,6 +20,7 @@ const jestConfig = { // testMatch: ['**/node.test.ts'], // testMatch: ['**/builtin-hotkey.test.ts'], // testMatch: ['**/selection.test.ts'], + // testMatch: ['**/plugin/sequencify.test.ts'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], diff --git a/packages/designer/src/plugin/sequencify.ts b/packages/designer/src/plugin/sequencify.ts index a312df2075..9084b0a0e6 100644 --- a/packages/designer/src/plugin/sequencify.ts +++ b/packages/designer/src/plugin/sequencify.ts @@ -1,19 +1,50 @@ -function sequence(tasks, names, results, missing, recursive, nest) { +interface ITaks { + [key: string]: { + name: string; + dep: string[]; + }; +} + +export function sequence({ + tasks, + names, + results, + missing, + recursive, + nest, + parentName, +}: { + tasks: ITaks; + names: string[]; + results: string[]; + missing: string[]; + recursive: string[][]; + nest: string[]; + parentName: string; +}) { names.forEach((name) => { if (results.indexOf(name) !== -1) { return; // de-dup results } const node = tasks[name]; if (!node) { - missing.push(name); + missing.push([parentName, name].filter((d => !!d)).join('.')); } else if (nest.indexOf(name) > -1) { nest.push(name); recursive.push(nest.slice(0)); - nest.pop(name); + nest.pop(); } else if (node.dep.length) { nest.push(name); - sequence(tasks, node.dep, results, missing, recursive, nest); // recurse - nest.pop(name); + sequence({ + tasks, + parentName: name, + names: node.dep, + results, + missing, + recursive, + nest, + }); // recurse + nest.pop(); } results.push(name); }); @@ -21,12 +52,19 @@ function sequence(tasks, names, results, missing, recursive, nest) { // tasks: object with keys as task names // names: array of task names -export default function (tasks, names) { - let results = []; // the final sequence - const missing = []; // missing tasks - const recursive = []; // recursive task dependencies +export default function (tasks: ITaks, names: string[]) { + let results: string[] = []; // the final sequence + const missing: string[] = []; // missing tasks + const recursive: string[][] = []; // recursive task dependencies - sequence(tasks, names, results, missing, recursive, []); + sequence({ + tasks, + names, + results, + missing, + recursive, + nest: [], + }); if (missing.length || recursive.length) { results = []; // results are incomplete at best, completely wrong at worst, remove them to avoid confusion diff --git a/packages/designer/tests/plugin/sequencify.test.ts b/packages/designer/tests/plugin/sequencify.test.ts new file mode 100644 index 0000000000..89140e2794 --- /dev/null +++ b/packages/designer/tests/plugin/sequencify.test.ts @@ -0,0 +1,128 @@ +import sequencify, { sequence } from '../../src/plugin/sequencify'; + +describe('sequence', () => { + it('handles tasks with no dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: [] } + }; + const results = []; + const missing = []; + const recursive = []; + sequence({ tasks, names: ['task1', 'task2'], results, missing, recursive, nest: [] }); + + expect(results).toEqual(['task1', 'task2']); + expect(missing).toEqual([]); + expect(recursive).toEqual([]); + }); + + it('correctly orders tasks based on dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: ['task1'] } + }; + const results = []; + const missing = []; + const recursive = []; + sequence({ tasks, names: ['task2', 'task1'], results, missing, recursive, nest: [] }); + + expect(results).toEqual(['task1', 'task2']); + expect(missing).toEqual([]); + expect(recursive).toEqual([]); + }); + + it('identifies missing tasks', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] } + }; + const results = []; + const missing = []; + const recursive = []; + const nest = [] + sequence({ tasks, names: ['task2'], results, missing, recursive, nest }); + + expect(results).toEqual(['task2']); + expect(missing).toEqual(['task2']); + expect(recursive).toEqual([]); + expect(nest).toEqual([]); + }); + + it('detects recursive dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: ['task2'] }, + task2: { name: 'Task 2', dep: ['task1'] } + }; + const results = []; + const missing = []; + const recursive = []; + const nest = [] + sequence({ tasks, names: ['task1', 'task2'], results, missing, recursive, nest }); + + expect(results).toEqual(['task1', 'task2', 'task1']); + expect(missing).toEqual([]); + expect(recursive).toEqual([['task1', 'task2', 'task1']]); + expect(nest).toEqual([]); + }); +}); + +describe('sequence', () => { + + it('should return tasks in sequence without dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: [] }, + task3: { name: 'Task 3', dep: [] } + }; + const names = ['task1', 'task2', 'task3']; + const expected = { + sequence: ['task1', 'task2', 'task3'], + missingTasks: [], + recursiveDependencies: [] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + + it('should handle tasks with dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: ['task1'] }, + task3: { name: 'Task 3', dep: ['task2'] } + }; + const names = ['task3', 'task2', 'task1']; + const expected = { + sequence: ['task1', 'task2', 'task3'], + missingTasks: [], + recursiveDependencies: [] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + + it('should identify missing tasks', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: ['task3'] } // task3 is missing + }; + const names = ['task1', 'task2']; + const expected = { + sequence: [], + missingTasks: ['task2.task3'], + recursiveDependencies: [] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + + it('should detect recursive dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: ['task2'] }, + task2: { name: 'Task 2', dep: ['task1'] } // Recursive dependency + }; + const names = ['task1', 'task2']; + const expected = { + sequence: [], + missingTasks: [], + recursiveDependencies: [['task1', 'task2', 'task1']] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + +}); \ No newline at end of file From 736cb0e96552c557aa3f2c6d290cc3c915fb8adb Mon Sep 17 00:00:00 2001 From: beautiful-boyyy <beautiful_boyyy@outlook.com> Date: Wed, 15 Nov 2023 12:09:55 +0800 Subject: [PATCH 314/469] docs: update prepare.md --- docs/docs/participate/prepare.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/docs/participate/prepare.md b/docs/docs/participate/prepare.md index c0e1d5880e..acb0947f22 100644 --- a/docs/docs/participate/prepare.md +++ b/docs/docs/participate/prepare.md @@ -33,27 +33,27 @@ npm install && npm start "proxy": [ [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js", - "http://localhost:5555/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/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/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/react-simulator-renderer.css" + "http://localhost:5555/css/ReactSimulatorRenderer.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/rax-simulator-renderer.js" + "http://localhost:5555/js/RaxSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/rax-simulator-renderer.css" + "http://localhost:5555/css/RaxSimulatorRenderer.css" ], ] } From 6cba4bcc206c148ec87aa2aed5ffd382ae3fe438 Mon Sep 17 00:00:00 2001 From: beautiful-boyyy <beautiful_boyyy@outlook.com> Date: Wed, 15 Nov 2023 12:09:55 +0800 Subject: [PATCH 315/469] docs: update prepare.md --- docs/docs/participate/prepare.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/docs/participate/prepare.md b/docs/docs/participate/prepare.md index c0e1d5880e..acb0947f22 100644 --- a/docs/docs/participate/prepare.md +++ b/docs/docs/participate/prepare.md @@ -33,27 +33,27 @@ npm install && npm start "proxy": [ [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js", - "http://localhost:5555/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/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/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/react-simulator-renderer.css" + "http://localhost:5555/css/ReactSimulatorRenderer.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/rax-simulator-renderer.js" + "http://localhost:5555/js/RaxSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/rax-simulator-renderer.css" + "http://localhost:5555/css/RaxSimulatorRenderer.css" ], ] } From e7884fdb5a9b448aa92ca3e897def4c05bc8caa6 Mon Sep 17 00:00:00 2001 From: Super-Rz <41566502+Super-Rz@users.noreply.github.com> Date: Wed, 15 Nov 2023 14:23:07 +0800 Subject: [PATCH 316/469] fix: createIcon props (#2629) * fix: createIcon props * fix: createIcon props --- .../src/builtin-simulator/bem-tools/border-selecting.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx index 0e9d734b60..4f452727d2 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx @@ -143,7 +143,7 @@ function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActio }); }} > - {icon && createIcon(icon)} + {icon && createIcon(icon, { key, node: node.internalToShellNode() })} <Tip>{title}</Tip> </div> ); From 058e184b21b15bcf512d796aea825b69756db537 Mon Sep 17 00:00:00 2001 From: beautiful-boyyy <beautiful_boyyy@outlook.com> Date: Wed, 15 Nov 2023 15:18:18 +0800 Subject: [PATCH 317/469] fix: fixed string trim issue --- packages/renderer-core/src/renderer/base.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 6c2a04aa78..ac4b1de125 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -901,9 +901,6 @@ export default function baseRendererFactory(): IBaseRenderComponent { }); return checkProps(res); } - if (typeof props === 'string') { - return checkProps(props.trim()); - } return checkProps(props); }; From 8898f1c4a7bb9766a0ce78632501b98942070ab4 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 15 Nov 2023 15:23:03 +0800 Subject: [PATCH 318/469] fix: fix engine-core classes is undefined --- packages/engine/src/engine-core.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 204b9b30ab..2b59ba1b6d 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -54,7 +54,7 @@ import { } from '@alilc/lowcode-shell'; import { isPlainObject } from '@alilc/lowcode-utils'; import './modules/live-editing'; -import classes from './modules/classes'; +import * as classes from './modules/classes'; import symbols from './modules/symbols'; import { componentMetaParser } from './inner-plugins/component-meta-parser'; import { setterRegistry } from './inner-plugins/setter-registry'; From 0f8bc8228236439775a0429c488308ba32ab7a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 20 Nov 2023 16:04:26 +0800 Subject: [PATCH 319/469] Update index.md --- docs/docs/article/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index e62f8f9d87..2de0b059ee 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -6,6 +6,7 @@ - [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) +- [基于 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) From 8208dd3a324081eeed3718d0924a397142c0c950 Mon Sep 17 00:00:00 2001 From: AprChell <smile_zchi@163.com> Date: Mon, 20 Nov 2023 16:24:27 +0800 Subject: [PATCH 320/469] fix(exportschema): exportSchema(IPublicEnumTransformStage.Save) type conver (#2661) * fix(exportschema): exportSchema(IPublicEnumTransformStage.Save) type conver * test(prop): nullProp equals null, not --- .../designer/src/document/node/props/prop.ts | 4 ---- .../tests/document/node/props/prop.test.ts | 2 +- packages/designer/tests/fixtures/schema/form.ts | 16 ++++++++-------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 01b2dc26b9..e2d9f12e8e 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -290,10 +290,6 @@ export class Prop implements IProp, IPropParent { } if (type === 'literal' || type === 'expression') { - // TODO 后端改造之后删除此逻辑 - if (this._value === null && stage === IPublicEnumTransformStage.Save) { - return ''; - } return this._value; } diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 58c24a4ea4..4424eb6010 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -136,7 +136,7 @@ describe('Prop 类测试', () => { expect(boolProp.export(IPublicEnumTransformStage.Save)).toBe(true); expect(strProp.export(IPublicEnumTransformStage.Save)).toBe('haha'); expect(numProp.export(IPublicEnumTransformStage.Save)).toBe(1); - expect(nullProp.export(IPublicEnumTransformStage.Save)).toBe(''); + expect(nullProp.export(IPublicEnumTransformStage.Save)).toBe(null); expect(nullProp.export(IPublicEnumTransformStage.Serilize)).toBe(null); expect(expProp.export(IPublicEnumTransformStage.Save)).toEqual({ type: 'JSExpression', diff --git a/packages/designer/tests/fixtures/schema/form.ts b/packages/designer/tests/fixtures/schema/form.ts index 8da6faf9e1..e8479629f8 100644 --- a/packages/designer/tests/fixtures/schema/form.ts +++ b/packages/designer/tests/fixtures/schema/form.ts @@ -267,7 +267,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -337,7 +337,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -407,7 +407,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -489,7 +489,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -578,7 +578,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, searchDelay: 300, @@ -697,7 +697,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -789,7 +789,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -871,7 +871,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, From 3c4bd1d2d0321453b3a1fa5253b0340c3dde8afc Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 20 Nov 2023 16:45:11 +0800 Subject: [PATCH 321/469] chore(docs): publish docs 1.1.17 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index c206cdf16a..81703741ac 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.16", + "version": "1.1.17", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 396e99aa11d442f1ace9ff138b2d4698ef57d9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 20 Nov 2023 17:00:36 +0800 Subject: [PATCH 322/469] docs: update index.md --- docs/docs/article/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index 2de0b059ee..c223137b25 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -6,7 +6,7 @@ - [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) -- [基于 LowCodeEngine 的调试能力建设与实践](https://mp.weixin.qq.com/s/H8KvEOylmzLPgIuuBO0S9w) +- [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) From bf50071cc8ca2c06b70f03c16347fc85533bd8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 20 Nov 2023 17:03:11 +0800 Subject: [PATCH 323/469] docs: update index.md --- docs/docs/video/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md index 9f348e4e65..2f8a5f49ce 100644 --- a/docs/docs/video/index.md +++ b/docs/docs/video/index.md @@ -1,4 +1,5 @@ # 官方视频 +- [2023/11/17 云栖大会|阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Qw411H7DH) - [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) # 社区视频 From d47df9dc441cfc5f0a3490e2243e90473e3469e1 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 20 Nov 2023 17:33:53 +0800 Subject: [PATCH 324/469] style: add --workspace-left-area-width --- docs/docs/guide/expand/editor/theme.md | 1 + packages/editor-skeleton/src/layouts/workbench.less | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index b62fb4f28c..94e434580d 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -72,6 +72,7 @@ sidebar_position: 9 - `--workspace-sub-top-area-height`: 应用级二级 topArea 高度 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding +- `--workspace-left-area-width`: 应用级 leftArea width ### 生态使用主题色变量 diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 6d0604a1f1..eb86bfe04c 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -13,6 +13,7 @@ --popup-border-radius: @popup-border-radius; --left-area-width: 48px; + --workspace-left-area-width: 48px; --right-area-width: 300px; --top-area-height: 48px; --toolbar-height: 36px; @@ -273,7 +274,7 @@ body { } .lc-left-area, .lc-workspace-left-area { height: 100%; - width: var(--left-area-width); + width: var(--workspace-left-area-width, --left-area-width); display: none; flex-shrink: 0; flex-direction: column; From 322313ceada4bf3d2011a0032f0be598c73ebeab Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 20 Nov 2023 18:14:15 +0800 Subject: [PATCH 325/469] docs: update faq list --- docs/docs/faq/index.md | 43 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/docs/docs/faq/index.md b/docs/docs/faq/index.md index ed31bad28e..5e5eee8ac4 100644 --- a/docs/docs/faq/index.md +++ b/docs/docs/faq/index.md @@ -1,7 +1,46 @@ --- title: FAQ 概述 -sidebar_position: 1 +sidebar_position: -1 tags: [FAQ] --- -不定期将社区常见问题及答案维护到此处 \ No newline at end of file +不定期将社区常见问题及答案维护到此处 + +## Demo 使用 +- [渲染唯一标识(key)](/site/docs/faq/faq002) +- [点击事件如何添加参数](/site/docs/faq/faq003) +- [如何通过 API 手动调用数据源请求](/site/docs/faq/faq006) + +## 设计器定制 +- [如何通过 this.utils 使用第三方工具扩展](/site/docs/faq/faq005) +- [设置面板中的高级 tab 如何配置](/site/docs/faq/faq007) +- [插件面板如何调整位置](/site/docs/faq/faq010) + +## 源码和依赖 +- [某某 npm 包对应的源码在哪里?](/site/docs/faq/faq008) + +## 错误和报错 +- [物料出现 Component Not Found 相关报错](/site/docs/faq/faq009) +- [VERSION_PLACEHOLDER is not defined](/site/docs/faq/faq014) +- [Cannot read property 'Icon' of Undefined](/site/docs/faq/faq016) +- [windows 下运行低代码引擎源码出现报错](/site/docs/faq/faq019) +- [Can't import the named export from non ECMAScript module](/site/docs/faq/faq020) +- [Slot组件渲染报错问题](/site/docs/faq/faq023) + +## 物料相关问题 +- [如何获取物料当前处于编辑态还是渲染态](/site/docs/faq/faq011) +- [Procode 物料如何调用数据源方法](/site/docs/faq/faq012) +- [已有组件如何快速接入引擎](/site/docs/faq/faq015) +- [Modal 类组件 hidden 属性被强制设置 true](/site/docs/faq/faq013) +- [最小渲染单元配置](/site/docs/faq/faq004) +- [节点无法拖拽到 Page 下](/site/docs/faq/faq022) + +## 其他说明 +- [vue 画布支持说明](/site/docs/faq/faq017) +- [是否可以生成 Vue 页面代码?](/site/docs/faq/faq018) + +## 参与贡献 +- [提交 PR 时,明明签署过 CLA,仍被提示需要签署](/site/docs/faq/faq021) + +## 相关依赖文档 +- [build-scripts 的使用文档](/site/docs/faq/faq001) From e35c672a50dc877f5768c1092e330bfb0424cfe2 Mon Sep 17 00:00:00 2001 From: "chenkeyao.chenkeya" <chenkeyao.chenkeya@alibaba-inc.com> Date: Mon, 20 Nov 2023 21:02:05 +0800 Subject: [PATCH 326/469] feat: add new video --- docs/docs/video/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md index 2f8a5f49ce..8ae21620bc 100644 --- a/docs/docs/video/index.md +++ b/docs/docs/video/index.md @@ -1,5 +1,5 @@ # 官方视频 -- [2023/11/17 云栖大会|阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Qw411H7DH) +- [2023/11/20 云栖大会|阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Ku4y1w7Zr) - [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) # 社区视频 From 7c72261fef0324cb57fd3e42331ede0f5b680573 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 21 Nov 2023 10:28:27 +0800 Subject: [PATCH 327/469] chore(docs): publish docs 1.2.0 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 81703741ac..cb3cb946dc 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.17", + "version": "1.2.0", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 394b56d0cef70101709802fb6ab1fda8f0ec2e3a Mon Sep 17 00:00:00 2001 From: 1ncounter <1ncounter.100@gmail.com> Date: Wed, 22 Nov 2023 19:50:22 +0800 Subject: [PATCH 328/469] fix: recover component lifecycle and avoid execute from scope __proto__ --- packages/renderer-core/src/renderer/base.tsx | 5 +++++ .../renderer-core/src/renderer/component.tsx | 21 ------------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index ac4b1de125..dddc55e838 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -50,6 +50,11 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche return; } + // avoid execute lifeCycle method from __proto__'s method (it is React class Component Class lifeCycle) + if (!Object.prototype.hasOwnProperty.call(context, method) && method !== 'constructor') { + return; + } + // TODO: cache if (isJSExpression(fn) || isJSFunction(fn)) { fn = thisRequiredInJSE ? parseThisRequiredExpression(fn, context) : parseExpression(fn, context); diff --git a/packages/renderer-core/src/renderer/component.tsx b/packages/renderer-core/src/renderer/component.tsx index f9f6e8f96e..3dfc1df33f 100644 --- a/packages/renderer-core/src/renderer/component.tsx +++ b/packages/renderer-core/src/renderer/component.tsx @@ -46,26 +46,5 @@ export default function componentRendererFactory(): IBaseRenderComponent { return this.__renderComp(Component, this.__renderContextProvider({ compContext: this })); } - - getComponentName() { - return this.props?.componentName; - } - - /** 需要重载下面几个方法,如果在低代码组件中绑定了对应的生命周期时会出现死循环 */ - componentDidMount() { - this.__debug(`componentDidMount - ${this.getComponentName()}`); - } - getSnapshotBeforeUpdate() { - this.__debug(`getSnapshotBeforeUpdate - ${this.getComponentName()}`); - } - componentDidUpdate() { - this.__debug(`componentDidUpdate - ${this.getComponentName()}`); - } - componentWillUnmount() { - this.__debug(`componentWillUnmount - ${this.getComponentName()}`); - } - componentDidCatch() { - this.__debug(`componentDidCatch - ${this.getComponentName()}`); - } }; } From 27e914cecee34a886680db3f2bc0c69f2b62c726 Mon Sep 17 00:00:00 2001 From: andylili21 <101868030+andylili21@users.noreply.github.com> Date: Thu, 23 Nov 2023 16:05:07 +0800 Subject: [PATCH 329/469] fix: Improve code and simplify logic (#2651) * fix: Improve code and simplify logic --- packages/designer/src/document/node/node.ts | 14 ++--- .../designer/tests/document/node/node.test.ts | 61 +++++++++++++++++-- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 9effc341dd..145a5a85ec 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -440,23 +440,23 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> } private initialChildren(children: IPublicTypeNodeData | IPublicTypeNodeData[] | undefined): IPublicTypeNodeData[] { - // FIXME! this is dirty code + const { initialChildren } = this.componentMeta.advanced; + if (children == null) { - const { initialChildren } = this.componentMeta.advanced; if (initialChildren) { if (typeof initialChildren === 'function') { return initialChildren(this.internalToShellNode()!) || []; } return initialChildren; } + return []; } + if (Array.isArray(children)) { return children; - } else if (children) { - return [children]; - } else { - return []; } + + return [children]; } isContainer(): boolean { @@ -1094,7 +1094,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> } /** - * 是否可执行某action + * 是否可执行某 action */ canPerformAction(actionName: string): boolean { const availableActions = diff --git a/packages/designer/tests/document/node/node.test.ts b/packages/designer/tests/document/node/node.test.ts index c4717b3a02..2695d6c838 100644 --- a/packages/designer/tests/document/node/node.test.ts +++ b/packages/designer/tests/document/node/node.test.ts @@ -54,7 +54,60 @@ describe('Node 方法测试', () => { project = null; }); - it('condition group', () => {}); + // Case 1: When children is null + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const result = node.initialChildren(null); + // 预期结果是一个空数组 + expect(result).toEqual([]); + }); + + // Case 2: When children is undefined + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const result = node.initialChildren(undefined); + // 预期结果是一个空数组 + expect(result).toEqual([]); + }); + + // Case 3: When children is array + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childrenArray = [{ id: 1, name: 'Child 1' }, { id: 2, name: 'Child 2' }]; + const result = node.initialChildren(childrenArray); + // 预期结果是一个数组 + expect(result).toEqual(childrenArray); + }); + + // Case 4: When children is not null and not an array + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childObject = { id: 1, name: 'Child 1' }; + const result = node.initialChildren(childObject); + // 预期结果是一个数组 + expect(result).toEqual([childObject]); + }); + + // Case 5: When children 0 + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childObject = 0; + const result = node.initialChildren(childObject); + // 预期结果是一个数组 + expect(result).toEqual([0]); + }); + + // Case 6: When children false + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childObject = false; + const result = node.initialChildren(childObject); + // 预期结果是一个数组 + expect(result).toEqual([false]); + }); + + + it('condition group', () => { }); it('getExtraProp / setExtraProp', () => { const firstBtn = doc.getNode('node_k1ow3cbn')!; @@ -367,7 +420,7 @@ describe('Node 方法测试', () => { expect(mockFn).not.toHaveBeenCalled(); }); - it('addSlot / unlinkSlot / removeSlot', () => {}); + it('addSlot / unlinkSlot / removeSlot', () => { }); it('setProps', () => { const firstBtn = doc.getNode('node_k1ow3cbn')!; @@ -407,7 +460,7 @@ describe('Node 方法测试', () => { designer.createComponentMeta(btnMetadata); const btn = doc.getNode('node_k1ow3cbn'); // 从 componentMeta 中获取到 title 值 - expect(btn.title).toEqual({ type: 'i18n', 'zh-CN': '按钮', 'en-US': 'Button' } ); + expect(btn.title).toEqual({ type: 'i18n', 'zh-CN': '按钮', 'en-US': 'Button' }); // 从 extraProp 中获取值 btn.setExtraProp('title', 'hello button'); expect(btn.title).toBe('hello button'); @@ -546,7 +599,7 @@ describe('Node 方法测试', () => { expect(comparePosition(firstBtn, firstCard)).toBe(PositionNO.BeforeOrAfter); }); - it('getZLevelTop', () => {}); + it('getZLevelTop', () => { }); it('propsData', () => { expect(new Node(doc, { componentName: 'Leaf' }).propsData).toBeNull(); expect(new Node(doc, { componentName: 'Fragment' }).propsData).toBeNull(); From ad044f49ed9064fe1afa5195f68759a76bda5f5e Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 23 Nov 2023 11:01:50 +0800 Subject: [PATCH 330/469] feat(utils): add workspace utils --- packages/designer/src/plugin/plugin-types.ts | 1 + packages/engine/src/engine-core.ts | 1 + .../types/src/shell/model/plugin-context.ts | 2 + packages/utils/src/index.ts | 1 + packages/utils/src/workspace.tsx | 54 +++++++++++++++++++ .../workspace/src/context/base-context.ts | 1 + 6 files changed, 60 insertions(+) create mode 100644 packages/utils/src/workspace.tsx diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index ac08d7d0ca..6091170f02 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -60,6 +60,7 @@ export interface ILowCodePluginContextPrivate { set workspace(workspace: IPublicApiWorkspace); set editorWindow(window: IPublicModelWindow); set registerLevel(level: IPublicEnumPluginRegisterLevel); + set isPluginRegisteredInWorkspace(flag: boolean); } export interface ILowCodePluginContextApiAssembler { assembleApis( diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 2b59ba1b6d..3ac4c32a75 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -139,6 +139,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.workspace = workspace; context.registerLevel = IPublicEnumPluginRegisterLevel.Default; + context.isPluginRegisteredInWorkspace = false; }, }; diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts index 1f3d3b5e85..35e7e38af3 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -108,6 +108,8 @@ export interface IPublicModelPluginContext { */ get registerLevel(): IPublicEnumPluginRegisterLevel; + get isPluginRegisteredInWorkspace(): boolean; + get editorWindow(): IPublicModelWindow; } diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index e3f70ff80a..3e37f46ba6 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -30,3 +30,4 @@ export * from './is-plugin-event-name'; export * as css from './css-helper'; export { transactionManager } from './transaction-manager'; export * from './check-types'; +export * from './workspace'; diff --git a/packages/utils/src/workspace.tsx b/packages/utils/src/workspace.tsx new file mode 100644 index 0000000000..446530ce8e --- /dev/null +++ b/packages/utils/src/workspace.tsx @@ -0,0 +1,54 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import { IPublicModelPluginContext, IPublicEnumPluginRegisterLevel, IPublicModelWindow, IPublicModelEditorView } from '@alilc/lowcode-types'; + +/** + * 高阶组件(HOC):为组件提供 view 插件上下文。 + * + * @param {React.ComponentType} Component - 需要被封装的组件。 + * @param {string|string[]} viewName - 视图名称或视图名称数组,用于过滤特定的视图插件上下文。 + * @returns {React.ComponentType} 返回封装后的组件。 + * + * @example + * // 用法示例(函数组件): + * const EnhancedComponent = ProvideViewPluginContext(MyComponent, "viewName"); + */ +export const ProvideViewPluginContext = (Component: any, viewName?: string | string[]) => { + // 创建一个新的函数组件,以便在其中使用 Hooks + return function WithPluginContext(props: { + [key: string]: any; + + pluginContext?: IPublicModelPluginContext; + }) { + const getPluginContextFun = useCallback((editorWindow?: IPublicModelWindow | null) => { + if (!editorWindow?.currentEditorView) { + return null; + } + if (viewName) { + const items = editorWindow?.editorViews.filter(d => (d as any).viewName === viewName || (Array.isArray(viewName) && viewName.includes((d as any).viewName))); + return items[0]; + } else { + return editorWindow.currentEditorView; + } + }, []); + + const { workspace } = props.pluginContext || {}; + const [pluginContext, setPluginContext] = useState<IPublicModelEditorView | null>(getPluginContextFun(workspace?.window)); + + useEffect(() => { + if (workspace?.window) { + const ctx = getPluginContextFun(workspace.window); + ctx && setPluginContext(ctx); + } + return workspace?.onChangeActiveEditorView(() => { + const ctx = getPluginContextFun(workspace.window); + ctx && setPluginContext(ctx); + }); + }, [workspace, getPluginContextFun]); + + if (props.pluginContext?.registerLevel !== IPublicEnumPluginRegisterLevel.Workspace || !props.pluginContext) { + return <Component {...props} />; + } + + return <Component {...props} pluginContext={pluginContext} />; + }; +}; diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index b359a6139f..78f32079ff 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -170,6 +170,7 @@ export class BasicContext implements IBasicContext { context.editorWindow = new Window(editorWindow); } context.registerLevel = registerLevel; + context.isPluginRegisteredInWorkspace = registerLevel === IPublicEnumPluginRegisterLevel.Workspace; }, }; From 029fd1ce67739e85dd669c61ebfedf52199c2d11 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 23 Nov 2023 11:23:34 +0800 Subject: [PATCH 331/469] feat(outline-pane): suport registry in workspace level --- .../src/controllers/tree-master.ts | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/plugin-outline-pane/src/controllers/tree-master.ts b/packages/plugin-outline-pane/src/controllers/tree-master.ts index 40162d808f..ede5f0f5f3 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-master.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-master.ts @@ -41,22 +41,19 @@ export class TreeMaster { this.initEvent(); if (pluginContext.registerLevel === IPublicEnumPluginRegisterLevel.Workspace) { this.setPluginContext(workspace.window?.currentEditorView); - workspace.onWindowRendererReady(() => { - this.setPluginContext(workspace.window?.currentEditorView); - let dispose: IPublicTypeDisposable | undefined; - const windowViewTypeChangeEvent = () => { - dispose = workspace.window?.onChangeViewType(() => { - this.setPluginContext(workspace.window?.currentEditorView); - }); - }; - - windowViewTypeChangeEvent(); - - workspace.onChangeActiveWindow(() => { - windowViewTypeChangeEvent(); + let dispose: IPublicTypeDisposable | undefined; + const windowViewTypeChangeEvent = () => { + dispose = workspace.window?.onChangeViewType(() => { this.setPluginContext(workspace.window?.currentEditorView); - dispose && dispose(); }); + }; + + windowViewTypeChangeEvent(); + + workspace.onChangeActiveWindow(() => { + windowViewTypeChangeEvent(); + this.setPluginContext(workspace.window?.currentEditorView); + dispose && dispose(); }); } } From a3fef9c13d39ac1b35b200cf0f711cf7c7c233d8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 23 Nov 2023 15:32:54 +0800 Subject: [PATCH 332/469] feat(skeleton): add registerConfigTransducer API --- docs/docs/api/skeleton.md | 62 +++++++++++++++++++ packages/editor-skeleton/src/skeleton.ts | 31 +++++++++- packages/shell/src/api/skeleton.ts | 6 +- packages/types/src/shell/api/skeleton.ts | 19 +++++- .../types/src/shell/type/config-transducer.ts | 9 +++ packages/types/src/shell/type/index.ts | 1 + 6 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 packages/types/src/shell/type/config-transducer.ts diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index c378792de0..90cf1a2c17 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -295,6 +295,68 @@ showArea(areaName: string): void; */ hideArea(areaName: string): void; ``` + +### 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 diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 89bffc4cfe..13967e94d6 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -28,6 +28,7 @@ import { IPublicTypeWidgetConfigArea, IPublicTypeSkeletonConfig, IPublicApiSkeleton, + IPublicTypeConfigTransducer, } from '@alilc/lowcode-types'; const logger = new Logger({ level: 'warn', bizName: 'skeleton' }); @@ -111,6 +112,8 @@ export interface ISkeleton extends Omit<IPublicApiSkeleton, export class Skeleton implements ISkeleton { private panels = new Map<string, Panel>(); + private configTransducers: IPublicTypeConfigTransducer[] = []; + private containers = new Map<string, WidgetContainer<any>>(); readonly leftArea: Area<DockConfig | PanelDockConfig | DialogDockConfig>; @@ -448,11 +451,35 @@ export class Skeleton implements ISkeleton { return restConfig; } + registerConfigTransducer( + transducer: IPublicTypeConfigTransducer, + level = 100, + id?: string, + ) { + transducer.level = level; + transducer.id = id; + const i = this.configTransducers.findIndex((item) => item.level != null && item.level > level); + if (i < 0) { + this.configTransducers.push(transducer); + } else { + this.configTransducers.splice(i, 0, transducer); + } + } + + getRegisteredConfigTransducers(): IPublicTypeConfigTransducer[] { + return this.configTransducers; + } + add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined { - const parsedConfig = { + const registeredTransducers = this.getRegisteredConfigTransducers(); + + const parsedConfig = registeredTransducers.reduce((prevConfig, current) => { + return current(prevConfig); + }, { ...this.parseConfig(config), ...extraConfig, - }; + }); + let { area } = parsedConfig; if (!area) { if (parsedConfig.type === 'Panel') { diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index 0d17075257..07a1727dd3 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -4,7 +4,7 @@ import { SkeletonEvents, } from '@alilc/lowcode-editor-skeleton'; import { skeletonSymbol } from '../symbols'; -import { IPublicApiSkeleton, IPublicModelSkeletonItem, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; +import { IPublicApiSkeleton, IPublicModelSkeletonItem, IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; import { getLogger } from '@alilc/lowcode-utils'; import { SkeletonItem } from '../model/skeleton-item'; @@ -208,6 +208,10 @@ export class Skeleton implements IPublicApiSkeleton { }); return () => editor.eventBus.off(SkeletonEvents.WIDGET_HIDE, listener); } + + registerConfigTransducer(fn: IPublicTypeConfigTransducer, level: number, id?: string) { + this[skeletonSymbol].registerConfigTransducer(fn, level, id); + } } function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea' | 'rightArea' | 'topArea' | 'toolbar' | 'mainArea' | 'bottomArea' | 'leftFixedArea' | 'leftFloatArea' | 'stages' | 'subTopArea' { diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts index 2ad561518b..9a36aa4690 100644 --- a/packages/types/src/shell/api/skeleton.ts +++ b/packages/types/src/shell/api/skeleton.ts @@ -1,5 +1,5 @@ import { IPublicModelSkeletonItem } from '../model'; -import { IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type'; +import { IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type'; export interface IPublicApiSkeleton { @@ -114,4 +114,21 @@ export interface IPublicApiSkeleton { * @returns */ onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; + + /** + * 注册一个面板的配置转换器(transducer)。 + * Registers a configuration transducer for a panel. + * @param {IPublicTypeConfigTransducer} transducer + * - 要注册的转换器函数。该函数接受一个配置对象(类型为 IPublicTypeSkeletonConfig)作为输入,并返回修改后的配置对象。 + * - The transducer function to be registered. This function takes a configuration object (of type IPublicTypeSkeletonConfig) as input and returns a modified 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; } diff --git a/packages/types/src/shell/type/config-transducer.ts b/packages/types/src/shell/type/config-transducer.ts new file mode 100644 index 0000000000..64c33a5c4e --- /dev/null +++ b/packages/types/src/shell/type/config-transducer.ts @@ -0,0 +1,9 @@ +import { IPublicTypeSkeletonConfig } from '.'; + +export interface IPublicTypeConfigTransducer { + (prev: IPublicTypeSkeletonConfig): IPublicTypeSkeletonConfig; + + level?: number; + + id?: string; +} diff --git a/packages/types/src/shell/type/index.ts b/packages/types/src/shell/type/index.ts index 7232ffbbdc..b2fd3313f9 100644 --- a/packages/types/src/shell/type/index.ts +++ b/packages/types/src/shell/type/index.ts @@ -91,3 +91,4 @@ export * from './hotkey-callback-config'; export * from './hotkey-callbacks'; export * from './scrollable'; export * from './simulator-renderer'; +export * from './config-transducer'; \ No newline at end of file From 7e80d1f863f934720915df35db3b27415a11ebb7 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 23 Nov 2023 16:33:45 +0800 Subject: [PATCH 333/469] chore(docs): publish docs 1.2.1 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index cb3cb946dc..14d0c99e55 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.0", + "version": "1.2.1", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From dc1e0f5a49a81b3fb8c47b4a1495d06e16798fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 18:58:24 +0800 Subject: [PATCH 334/469] Fix/component lifecycle not execute (#2690) * fix: recover component lifecycle and avoid execute from scope __proto__ From 6c7a52652131b0a18a03bf6f90b8730544b8be34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 19:28:41 +0800 Subject: [PATCH 335/469] Fix/component lifecycle not execute (#2692) * fix: recover component lifecycle and avoid execute from scope __proto__ From c643c0fc4f4c9eb90b8d273447fef04d28cfe13d Mon Sep 17 00:00:00 2001 From: 1ncounter <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 19:35:37 +0800 Subject: [PATCH 336/469] fix(renderer-core): remove compatibility with uipaas --- packages/renderer-core/src/renderer/base.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index dddc55e838..ac4b1de125 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -50,11 +50,6 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche return; } - // avoid execute lifeCycle method from __proto__'s method (it is React class Component Class lifeCycle) - if (!Object.prototype.hasOwnProperty.call(context, method) && method !== 'constructor') { - return; - } - // TODO: cache if (isJSExpression(fn) || isJSFunction(fn)) { fn = thisRequiredInJSE ? parseThisRequiredExpression(fn, context) : parseExpression(fn, context); From 1c2f195e8bce05284419eb7bbbba33bb97acf30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 27 Nov 2023 16:22:29 +0800 Subject: [PATCH 337/469] docs: update skeleton.md --- docs/docs/api/skeleton.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index 90cf1a2c17..5bfa239724 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -69,6 +69,7 @@ skeleton.add({ props: { align: "left", icon: "wenjian", + title: '标题', // 图标下方展示的标题 description: "JS 面板", }, panelProps: { From 20bf62aed3c67753c265c38dffaa5e5a31c2b4ee Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 27 Nov 2023 17:50:48 +0800 Subject: [PATCH 338/469] chore(docs): publish docs 1.2.2 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 14d0c99e55..e9d5b87b43 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.1", + "version": "1.2.2", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From d41f2c13d24a0270616ae4d2d2484e347ca02573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 27 Nov 2023 21:40:25 +0800 Subject: [PATCH 339/469] docs: update material.md --- docs/docs/api/material.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index 8b1214476b..51ed4e3054 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -116,6 +116,21 @@ 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 From f75b9ae61cdc46618038b3fe43e6744aa8d56f5c Mon Sep 17 00:00:00 2001 From: owenchen1004 <yoga981004@gmail.com> Date: Tue, 28 Nov 2023 10:50:38 +0800 Subject: [PATCH 340/469] fix: executeLifeCycleMethod return bug in renderer --- packages/renderer-core/src/renderer/base.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 1980734e43..640763538a 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -182,7 +182,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { __afterInit(_props: IBaseRendererProps) { } static getDerivedStateFromProps(props: IBaseRendererProps, state: any) { - return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE); + return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE) || null; } async getSnapshotBeforeUpdate(...args: any[]) { From b786c8fcaad1376d1d4d1316f75e283418f93913 Mon Sep 17 00:00:00 2001 From: owenchen1004 <yoga981004@gmail.com> Date: Tue, 28 Nov 2023 11:04:37 +0800 Subject: [PATCH 341/469] fix: coding style update --- packages/renderer-core/src/renderer/base.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 640763538a..ebaa8eadc8 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -182,7 +182,8 @@ export default function baseRendererFactory(): IBaseRenderComponent { __afterInit(_props: IBaseRendererProps) { } static getDerivedStateFromProps(props: IBaseRendererProps, state: any) { - return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE) || null; + const result = executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE); + return result === undefined ? null : result; } async getSnapshotBeforeUpdate(...args: any[]) { From d199b44eca0b1fe47d1744421a275188f69533e1 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 28 Nov 2023 16:11:04 +0800 Subject: [PATCH 342/469] style: add --color-toolbar-background --- docs/docs/guide/expand/editor/theme.md | 73 +++++++++++++++---- .../src/layouts/workbench.less | 2 +- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 94e434580d..16bcf04b09 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -3,23 +3,46 @@ 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`: 品牌色(light) -- `--color-brand-dark`: 品牌色(dark) -- `--color-icon-normal`: 正常 icon 颜色 -- `--color-icon-hover`: icon hover 态颜色 -- `--color-icon-active`: icon active 态颜色 -- `--color-icon-reverse`: icon 反色 -- `--color-icon-disabled`: icon 禁用态颜色 -- `--color-icon-pane`: icon 面板颜色 +以下是低代码引擎设计器支持的主题色变量列表,以及它们的用途说明: + +#### 品牌相关颜色 + +- `--color-brand`: 主品牌色 +- `--color-brand-light`: 浅色品牌色 +- `--color-brand-dark`: 深色品牌色 + +#### Icon 相关颜色 + +- `--color-icon-normal`: 默认状态 +- `--color-icon-hover`: 鼠标悬停状态 +- `--color-icon-active`: 激活状态 +- `--color-icon-reverse`: 反色状态 +- `--color-icon-disabled`: 禁用状态 +- `--color-icon-pane`: 面板颜色 + +#### 线条和文本颜色 + - `--color-line-normal`: 线条颜色 - `--color-line-darken`: 线条颜色(darken) - `--color-title`: 标题颜色 @@ -29,6 +52,9 @@ sidebar_position: 9 - `--color-text-reverse`: 反色情况下,文字颜色 - `--color-text-regular`: 文字颜色(regular) - `--color-text-disabled`: 禁用态文字颜色 + +#### 字段和边框颜色 + - `--color-field-label`: field 标签颜色 - `--color-field-text`: field 文本颜色 - `--color-field-placeholder`: field placeholder 颜色 @@ -36,6 +62,9 @@ sidebar_position: 9 - `--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) @@ -50,7 +79,9 @@ sidebar_position: 9 - `--color-error-light`: error 颜色(light) - `--color-purple`: purple 颜色 - `--color-brown`: brown 颜色 -- `--color-pane-background`: 面板背景色 + +#### 区块背景色 + - `--color-block-background-normal`: 区块背景色 - `--color-block-background-light`: 区块背景色(light), 作用于画布组件 hover 时遮罩背景色。 - `--color-block-background-shallow`: 区块背景色 shallow @@ -61,20 +92,30 @@ sidebar_position: 9 - `--color-block-background-error`: 区块背景色(error) - `--color-block-background-success`: 区块背景色(success) - `--color-block-background-deep-dark`: 区块背景色(deep-dark),作用于多个组件同时拖拽的背景色。 + +#### 其他区域背景色 + - `--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 高度 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding - `--workspace-left-area-width`: 应用级 leftArea width -### 生态使用主题色变量 + + +### 低代码引擎生态主题色定制 插件、物料、设置器等生态为了支持主题色需要对样式进行改造,需要对生态中的样式升级为 css 变量。例如: @@ -87,6 +128,8 @@ background: var(--color-brand, #006cff); ``` +这里 `var(--color-brand, #默认色)` 表示使用 `--color-brand` 变量,如果该变量未定义,则使用默认颜色(#默认色)。 + ### fusion 物料进行主题色扩展 -如果使用了 fusion 组件,可以通过 https://fusion.alibaba-inc.com/ 平台进行主题色定制。 \ No newline at end of file +如果使用了 fusion 组件时,可以通过 [fusion 平台](https://fusion.design/) 进行主题色定制。在平台上,您可以选择不同的主题颜色,并直接应用于您的 fusion 组件,这样可以无缝地集成到您的应用设计中。 \ No newline at end of file diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index eb86bfe04c..1f0eae8ec8 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -366,7 +366,7 @@ body { .lc-toolbar { display: flex; height: var(--toolbar-height); - background-color: var(--color-pane-background); + background-color: var(--color-toolbar-background, var(--color-pane-background)); padding: 8px 16px; .lc-toolbar-center { display: flex; From d703e64ac958de5e91d34f4741b49b94a6b467ea Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Wed, 29 Nov 2023 11:10:29 +0800 Subject: [PATCH 343/469] chore(docs): publish docs 1.2.3 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index e9d5b87b43..00887a7588 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.2", + "version": "1.2.3", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 19bf6ad28456feab9b58de3a00023898c72d8fde Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 29 Nov 2023 11:29:33 +0800 Subject: [PATCH 344/469] style: add --color-toolbar-background --- packages/editor-skeleton/src/layouts/workbench.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 1f0eae8ec8..2cddb25372 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -452,7 +452,7 @@ body { .lc-toolbar { display: flex; height: var(--toolbar-height); - background-color: var(--color-pane-background); + background-color: var(--color-toolbar-background, var(--color-pane-background)); padding: 8px 16px; .lc-toolbar-center { display: flex; From 1a328bd1f63a27074ba4b07c9b866ef85038e6e2 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 30 Nov 2023 17:36:55 +0800 Subject: [PATCH 345/469] style: fix --workspace-left-area-width style bug --- docs/docs/guide/expand/editor/theme.md | 1 + packages/editor-skeleton/src/layouts/workbench.less | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 16bcf04b09..35a77f2ac6 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -112,6 +112,7 @@ sidebar_position: 9 - `--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 diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 2cddb25372..565b6f07d7 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -443,6 +443,10 @@ body { min-height: 0; position: relative; + > .lc-left-float-pane { + left: calc(var(--workspace-left-area-width, var(--left-area-width)) + 1px); + } + .lc-workspace-workbench-center { flex: 1; display: flex; From 8f5ba69813bf4cf1a3b084c2a1eb24f2dbc8be35 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 1 Dec 2023 14:23:29 +0800 Subject: [PATCH 346/469] docs: add meet docs --- docs/docs/participate/meet.md | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 docs/docs/participate/meet.md diff --git a/docs/docs/participate/meet.md b/docs/docs/participate/meet.md new file mode 100644 index 0000000000..23226bf1cd --- /dev/null +++ b/docs/docs/participate/meet.md @@ -0,0 +1,55 @@ +--- +title: 开源社区例会 +sidebar_position: 0 +--- + +## **简介** + +低代码引擎开源社区致力于共同推动低代码技术的发展和创新。本社区汇集了低代码技术领域的开发者、技术专家和行业观察者,通过定期的例会来交流思想、分享经验、讨论新技术,并探索低代码技术的未来发展方向。 + +## 参与要求 + +为了确保例会的质量和效果,我们建议以下人员参加: + +- **已参与低代码引擎贡献的成员**:那些对低代码引擎有实际贡献的社区成员。 +- **参考贡献指南**:可查阅[贡献指南](https://lowcode-engine.cn/site/docs/participate/)获取更多信息。 +- **提供过优秀建议的成员**:那些在过去为低代码引擎提供过有价值建议的成员。 + +## **时间周期** + +- **周期性**:月例会 + +### **特别说明** + +- 例会周期可根据成员反馈进行调整。如果讨论的议题较多,可增加例会频率;若议题较少,单次例会可能取消。若多次取消,可能会暂停例会。 + +## **例会流程** + +### **准备阶段** + +- **定期确定议题**:会前一周确定下一次会议的议题。 +- **分发会议通知**:提前发送会议时间、议程和参与方式。 + +### **会议阶段** + +- **开场和介绍**:简短开场和自我介绍,特别是新成员加入时。 +- **议题讨论**:按照议程进行议题讨论,每个议题分配一定时间,并留足够时间供讨论和提问。 +- **记录要点和决定**:记录讨论要点、决策和任何行动事项。 + +### **后续阶段** + +- **分享会议纪要**:会后将会议纪要和行动计划分发给所有成员。 +- **执行和跟进**:根据会议中的讨论和决策执行相关任务,并在下次会议中进行跟进汇报。 + +## **开源例会议题** + +开源例会议题包括但不限于: + +- **共建低代码行业发展**:探讨通过开源社区合作加速低代码行业发展。 +- **改进建议和反馈收集**:讨论社区成员对低代码引擎的使用体验和改进建议。 +- **前端技术与低代码的结合**:针对前端开发者,讨论将前端技术与低代码引擎结合的方式。 +- **低代码业务场景和经验分享**:邀请社区成员分享低代码引擎的实际应用经验。 +- **低代码技术原理介绍**:深入理解低代码引擎的技术原理和实现方式。 +- **低代码引擎的最新进展**:分享低代码引擎的最新进展,包括新版本发布和新功能实现等。 +- **低代码技术的未来展望**:讨论低代码技术的未来发展方向。 +- **最新低代码平台功能和趋势分析**:分享和讨论当前低代码平台的新功能、趋势和发展方向。 \ No newline at end of file From ebdcc4146135ae3d41c8cf79024e9247238a8c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Fri, 1 Dec 2023 15:27:30 +0800 Subject: [PATCH 347/469] fix: scope props merge defaultProps (#2716) --- packages/renderer-core/src/renderer/base.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index f6930e86d5..9d9e88ab59 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -429,7 +429,14 @@ export default function baseRendererFactory(): IBaseRenderComponent { __createDom = () => { const { __schema, __ctx, __components = {} } = this.props; - const scope: any = {}; + // merge defaultProps + const scopeProps = { + ...__schema.defaultProps, + ...this.props, + }; + const scope: any = { + props: scopeProps, + }; scope.__proto__ = __ctx || this; const _children = getSchemaChildren(__schema); From 4d03610fd3b6d056fa7ce35f127cf7a90f99dd6c Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 30 Nov 2023 20:38:12 +0800 Subject: [PATCH 348/469] feat: update types define --- packages/types/src/shell/type/plugin-config.ts | 4 ++-- packages/types/src/shell/type/resource-type-config.ts | 3 ++- packages/types/src/shell/type/resource-type.ts | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/types/src/shell/type/plugin-config.ts b/packages/types/src/shell/type/plugin-config.ts index e9e65192e0..2d841dd804 100644 --- a/packages/types/src/shell/type/plugin-config.ts +++ b/packages/types/src/shell/type/plugin-config.ts @@ -1,5 +1,5 @@ export interface IPublicTypePluginConfig { - init(): Promise<void>; - destroy?(): Promise<void>; + init(): Promise<void> | void; + destroy?(): Promise<void> | void; exports?(): any; } diff --git a/packages/types/src/shell/type/resource-type-config.ts b/packages/types/src/shell/type/resource-type-config.ts index 474987b529..01b49aa2bd 100644 --- a/packages/types/src/shell/type/resource-type-config.ts +++ b/packages/types/src/shell/type/resource-type-config.ts @@ -1,3 +1,4 @@ +import React from 'react'; import { IPublicTypeEditorView } from './editor-view'; export interface IPublicResourceTypeConfig { @@ -6,7 +7,7 @@ export interface IPublicResourceTypeConfig { description?: string; /** 资源 icon 标识 */ - icon?: React.ReactElement; + icon?: React.ReactElement | React.FunctionComponent | React.ComponentClass; /** * 默认视图类型 diff --git a/packages/types/src/shell/type/resource-type.ts b/packages/types/src/shell/type/resource-type.ts index 7cfb125aaf..7d64a4463d 100644 --- a/packages/types/src/shell/type/resource-type.ts +++ b/packages/types/src/shell/type/resource-type.ts @@ -4,7 +4,7 @@ import { IPublicResourceTypeConfig } from './resource-type-config'; export interface IPublicTypeResourceType { resourceName: string; - resourceType: 'editor' | 'webview'; + resourceType: 'editor' | 'webview' | string; (ctx: IPublicModelPluginContext, options: Object): IPublicResourceTypeConfig; } \ No newline at end of file From 70845a1eca349c5786101119537ff9664fbe9056 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 5 Dec 2023 09:32:21 +0800 Subject: [PATCH 349/469] chore(docs): publish docs 1.2.4 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 00887a7588..d5d42cf96d 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.3", + "version": "1.2.4", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 0a50cf5a0d351fd3f140f4893140193f6aa5231c Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 5 Dec 2023 13:05:08 +0800 Subject: [PATCH 350/469] docs: update participate docs --- docs/docs/participate/config.md | 88 -------------------- docs/docs/participate/doc.md | 25 ------ docs/docs/participate/index.md | 133 ++++++++++++++++++++++++++----- docs/docs/participate/prepare.md | 64 --------------- 4 files changed, 114 insertions(+), 196 deletions(-) delete mode 100644 docs/docs/participate/config.md delete mode 100644 docs/docs/participate/doc.md delete mode 100644 docs/docs/participate/prepare.md diff --git a/docs/docs/participate/config.md b/docs/docs/participate/config.md deleted file mode 100644 index 1d70a7a89e..0000000000 --- a/docs/docs/participate/config.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: 工程化配置 -sidebar_position: 3 ---- -目前引擎体系共包含 2 个 js 文件 (配套 2 个 css),即: - - -```html -<!-- 低代码引擎的页面框架样式 --> -<link rel="stylesheet" href="https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/css/engine-core.css" /> -<!-- 低代码引擎官方扩展的样式 --> -<link rel="stylesheet" href="https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine-ext/1.0.5/dist/css/engine-ext.css" /> - -<!-- 低代码引擎的主包 --> -<script crossorigin="anonymous" src="https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/js/engine-core.js"></script> -<!-- 低代码引擎官方扩展的主包 --> -<script crossorigin="anonymous" src="https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine-ext/1.0.5/dist/js/engine-ext.js"></script> -``` - -> 注,这里的版本号是示例,请尽量选用最新版 - -工程化配置我们进行了统一,具体如下: -```shell -{ - "entry": { - ... - }, - "library": "...", - "libraryTarget": "umd", - "externals": { - "react": "var window.React", - "react-dom": "var window.ReactDOM", - "prop-types": "var window.PropTypes", - "@alilc/lowcode-engine": "var window.AliLowCodeEngine", - "@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt", - "moment": "var moment", - "lodash": "var _", - "@alifd/next": "var Next" - }, - "polyfill": false, - "outputDir": "dist", - "vendor": false, - "ignoreHtmlTemplate": true, - "sourceMap": true, - "plugins": [ - "build-plugin-react-app", - ["build-plugin-fusion", { - }], - ["build-plugin-moment-locales", { - "locales": ["zh-CN"] - }], - "./build.plugin.js" - ] -} - -``` -总结一下,有 2 点: - -1. **都不包含 polyfill,**需要应用级别单独引入 polyfill,推荐动态 polyfill -2. **都不包含 lodash / moment / next** - - -#### 前置依赖资源: -```html -<link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.20.25/next.min.css"> - -<script src="//polyfill.alicdn.com/s/polyfill.min.js?features=default,es2017,es6,fetch,RegeneratorRuntime"></script> -<script src="//alifd.alicdn.com/npm/@alifd/next/1.20.25/next.min.js"></script> -<script src="//g.alicdn.com/platform/c/lodash/4.6.1/lodash.min.js"></script> -<script src="//g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script> -``` - - -#### 所有资源: -```html -<link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.20.25/next.min.css"> -<link rel="stylesheet" href="//uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/css/engine-core.css"/> -<link rel="stylesheet" href="//uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.5/dist/css/engine-ext.css"/> - -<script src="//polyfill.alicdn.com/s/polyfill.min.js?features=default,es2017,es6,fetch,RegeneratorRuntime"></script> -<script src="//alifd.alicdn.com/npm/@alifd/next/1.20.25/next.min.js"></script> -<script src="//g.alicdn.com/platform/c/lodash/4.6.1/lodash.min.js"></script> -<script src="//g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script> -<!-- engine-core 引擎的 core,负责引擎的基础模块 --> -<script crossorigin="anonymous" src="//uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/js/engine-core.js"></script> -<!-- engine-ext 引擎的扩展包,负责收拢内置 setters / plugins,方便迭代 --> -<script crossorigin="anonymous" src="//uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.5/dist/js/engine-ext.js"></script> -``` diff --git a/docs/docs/participate/doc.md b/docs/docs/participate/doc.md deleted file mode 100644 index 1e19918db5..0000000000 --- a/docs/docs/participate/doc.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: 参与文档贡献 -sidebar_position: 3 ---- - -## 基本原则 - -### 维护方式 - -- 官方文档通过 github 管理文档源,官网文档与[主仓库 develop 分支](https://github.com/alibaba/lowcode-engine/tree/develop/docs)保持同步。 -- 点击每篇文档下发的 `编辑此页` 可直接定位到 github 中位置。 -- 欢迎 PR,文档 PR 也会作为贡献者贡献,会用于贡献度统计。 -- **文档同步到官方网站由官方人员进行操作**,如有需要可以通过 issue 或 贡献者群与相关人员沟通。 -- 为了提供更好的阅读和使用体验,文档中的图片文件会定期转换成可信的 CDN 地址。 - -### PR 提交注意事项 - -- 指向 develop 分支。 -- 涉及到图片的,需附在文档同级的 img 目录下,通过相对地址引用。 - -### 文档格式 - -本项目文档参考[文档编写指南](https://github.com/sparanoid/chinese-copywriting-guidelines)。 - -使用 vscode 进行编辑的朋友可以安装 vscode 插件 [huacnlee.autocorrect](https://github.com/huacnlee/autocorrect) 辅助文档 lint。 diff --git a/docs/docs/participate/index.md b/docs/docs/participate/index.md index ea87651ffd..4540fa640d 100644 --- a/docs/docs/participate/index.md +++ b/docs/docs/participate/index.md @@ -1,31 +1,126 @@ --- -title: 贡献者指南 +title: 参与贡献 sidebar_position: 0 --- -### 首个 Pull Request -在写第一个 Pull Request?你可以从这一系列视频中学习怎么做: -[How to Contribute to an Open Source Project on GitHub](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github) -为了使你能够快速上手和熟悉贡献流程,我们这里有个列表 [good first issues](https://github.com/alibaba/lowcode-engine/issues?q=is:open+is:issue+label:%22good+first+issue%22),里面有相对没那么笼统的漏洞,从这开始是个不错的选择。 +### 环境准备 + +开发 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" + ], + [ + "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", + "http://localhost:5555/js/RaxSimulatorRenderer.js" + ], + [ + "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", + "http://localhost:5555/css/RaxSimulatorRenderer.css" + ], + ] +} +``` + +#### 开发 + +``` +npm start +``` + +选择一个环境进行调试,例如[低代码引擎在线 DEMO](https://lowcode-engine.cn/demo/demo-general/index.html) + +开启代理之后,就可以进行开发调试了。 -如果你想解决一个 issue,请确定检查了该 issue 下的评论以防有人正在处理它。如果目前没人在处理该 issue,那么请留下评论去表明你想处理该 issue 以便其他人不会意外重复你的工作。 -如果有人留言表明要处理该 issue 但是超过两周没有跟进,你可以接手工作,不过也应该留言说明。 +### 贡献低代码引擎文档 -### 提交 Pull Request -核心团队时刻关注 pull requests,我们会先评审你的 pull request,之后可能会合并,可能会要求再次更改,也可能会关闭该 pull request 并对此作出解释。我们会尽力全程更新和反馈。 +#### 开发文档 -**提交 pull request 前**,请确保完成以下步骤: +在 lowcode-engine 目录下执行下面命令 +``` +cd docs -1. Fork [此仓库](https://github.com/alibaba/lowcode-engine),从 main 创建分支。 -2. 在仓库根目录下执行 yarn。 -3. 如果你修复了 bug 或者添加了代码,而这些内容需要测试,请添加测试! -4. 确保通过测试套件(yarn test)。 -5. 请签订贡献者许可证协议(Contributor License Agreement)。 - > 如已签署 CLA 仍被提示需要签署,[解决办法](/site/docs/faq/faq021) +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` 说明一下。 +2. 填写问卷后加微信号 `wxidvlalalalal` (注明 github id)我们会拉你到群里。 + +如果你不知道可以贡献什么,可以到源码里搜 TODO 或 FIXME 找找。 + +为了使你能够快速上手和熟悉贡献流程,我们这里有个列表 [good first issues](https://github.com/alibaba/lowcode-engine/issues?q=is:open+is:issue+label:%22good+first+issue%22),里面有相对没那么笼统的漏洞,从这开始是个不错的选择。 + +### PR 提交注意事项 + +- lowcode-engine 仓库建议从 develop 创建分支,PR 指向 develop 分支。 +- 其他仓库从 main 分支创建分支,PR 指向 main 分支 +- 如果你修复了 bug 或者添加了代码,而这些内容需要测试,请添加测试! +- 确保通过测试套件(yarn test)。 +- 请签订贡献者许可证协议(Contributor License Agreement)。 + > 如已签署 CLA 仍被提示需要签署,[解决办法](/site/docs/faq/faq021) \ No newline at end of file diff --git a/docs/docs/participate/prepare.md b/docs/docs/participate/prepare.md deleted file mode 100644 index acb0947f22..0000000000 --- a/docs/docs/participate/prepare.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: 调试环境配置 -sidebar_position: 1 ---- -低代码引擎的核心仓库是不包含任何物料、插件、setter 的,它本身用于生成低代码引擎的主包。 - -如果您需要对低代码的主包进行开发和调试,需要用到本文里介绍的知识。 - -如果您需要对低代码编辑器进行定制,您可能只需要 clone [lowcode-demo 项目](https://github.com/alibaba/lowcode-demo)并进行修改,参考“[配置低代码扩展点](/site/docs/guide/expand/editor/summary)”章节。 - -> 前置条件: -> node 推荐使用 16.18.0(14.x 也可以) - -### 1. 拉取代码,启动项目 -```bash -git clone git@github.com:alibaba/lowcode-engine.git -cd lowcode-engine -npm install && npm run setup -npm start - - -git clone git@github.com:alibaba/lowcode-demo.git -cd lowcode-demo -npm install && npm start -``` - -### 2. 配置资源代理 -本质上是将 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" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/RaxSimulatorRenderer.js" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/RaxSimulatorRenderer.css" - ], - ] -} -``` - -### 3. 本地调试物料/插件/设置器 - -详见[低代码生态脚手架 & 调试机制](/site/docs/guide/expand/editor/cli) From 28fdf9a37d04fc4c5d942aca4f87511bb0f901fe Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 5 Dec 2023 13:29:16 +0800 Subject: [PATCH 351/469] chore(docs): publish docs 1.2.5 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index d5d42cf96d..75704e688c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.4", + "version": "1.2.5", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From a87dcaada18eb28d0b67fa99e4ab82ca1d552d7d Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 5 Dec 2023 15:25:28 +0800 Subject: [PATCH 352/469] chore: create publish docs.yml --- .github/workflows/publish docs.yml | 51 ++++++++++++++++++++++++++++++ docs/package.json | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/publish docs.yml diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml new file mode 100644 index 0000000000..dcbeec3844 --- /dev/null +++ b/.github/workflows/publish docs.yml @@ -0,0 +1,51 @@ +name: Update and Publish Docs + +on: + push: + branches: + - develop + paths: + - 'docs/**' + +jobs: + publish-docs: + 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: 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 "Update package version" + git push + - run: cd docs && npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Get version + id: get_version + run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" + + 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 }}' + }) \ No newline at end of file diff --git a/docs/package.json b/docs/package.json index 75704e688c..8af810d33e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.5", + "version": "1.2.6", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 77aea1bfbafe4315e8488417d862d820e81dd573 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 5 Dec 2023 07:29:34 +0000 Subject: [PATCH 353/469] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 8af810d33e..634f73bee1 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.6", + "version": "1.2.7", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 398f06974571a05af5b03b3d7c651c3f604f5967 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 5 Dec 2023 14:42:28 +0800 Subject: [PATCH 354/469] style: add css themes vars --- docs/docs/guide/expand/editor/theme.md | 11 ++++++++++- .../designer/src/builtin-simulator/host.less | 8 ++++---- packages/editor-skeleton/src/layouts/theme.less | 2 +- .../editor-skeleton/src/layouts/workbench.less | 16 ++++++++-------- .../types/src/shell/type/widget-base-config.ts | 5 +++++ 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 35a77f2ac6..36500cb458 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -50,7 +50,6 @@ sidebar_position: 9 - `--color-text-dark`: 文字颜色(dark) - `--color-text-light`: 文字颜色(light) - `--color-text-reverse`: 反色情况下,文字颜色 -- `--color-text-regular`: 文字颜色(regular) - `--color-text-disabled`: 禁用态文字颜色 #### 字段和边框颜色 @@ -109,10 +108,20 @@ sidebar_position: 9 #### 其他变量 - `--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`: 面板标题边距 diff --git a/packages/designer/src/builtin-simulator/host.less b/packages/designer/src/builtin-simulator/host.less index 7130c42972..9a00963f24 100644 --- a/packages/designer/src/builtin-simulator/host.less +++ b/packages/designer/src/builtin-simulator/host.less @@ -73,10 +73,10 @@ } &-device-default { - top: 16px; - right: 16px; - bottom: 16px; - left: 16px; + top: var(--simulator-top-distance, 16px); + right: var(--simulator-right-distance, 16px); + bottom: var(--simulator-bottom-distance, 16px); + left: var(--simulator-left-distance, 16px); width: auto; box-shadow: 0 1px 4px 0 var(--color-block-background-shallow, rgba(31, 50, 88, 0.125)); } diff --git a/packages/editor-skeleton/src/layouts/theme.less b/packages/editor-skeleton/src/layouts/theme.less index 716ab3a99e..78c6fa5fd6 100644 --- a/packages/editor-skeleton/src/layouts/theme.less +++ b/packages/editor-skeleton/src/layouts/theme.less @@ -27,7 +27,6 @@ --color-text-dark: darken(@dark-alpha-3, 10%); --color-text-light: lighten(@dark-alpha-3, 10%); --color-text-reverse: @white-alpha-2; - --color-text-regular: @normal-alpha-2; --color-text-disabled: @gray-light; --color-field-label: @dark-alpha-4; @@ -87,4 +86,5 @@ --color-function-error-light: lighten(@brand-danger, 10%); --color-function-purple: rgb(144, 94, 190); --color-function-brown: #7b605b; + --color-text-regular: @normal-alpha-2; } diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 565b6f07d7..596ea69f60 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -66,16 +66,16 @@ body { } } > .lc-panel-title { - height: 48px; - font-size: 16px; - padding: 0 15px; + height: var(--pane-title-height, 48px); + font-size: var(--pane-title-font-size, 16px); + padding: var(--pane-title-padding, 0 15px); color: var(--color-title, #0f1726); font-weight: bold; } .lc-panel-body { position: absolute; - top: 48px; + top: var(--pane-title-height, 48px); bottom: 0; left: 0; right: 0; @@ -234,7 +234,7 @@ body { .lc-pane-icon-close { position: absolute; right: 16px; - top: 14px; + top: calc(var(--pane-title-height, 48px) / 2 - 10px); height: auto; z-index: 2; .next-icon { @@ -247,7 +247,7 @@ body { .lc-pane-icon-float { position: absolute; right: 38px; - top: 14px; + top: calc(var(--pane-title-height, 48px) / 2 - 10px); height: auto; z-index: 2; svg { @@ -367,7 +367,7 @@ body { display: flex; height: var(--toolbar-height); background-color: var(--color-toolbar-background, var(--color-pane-background)); - padding: 8px 16px; + padding: var(--toolbar-padding, 8px 16px); .lc-toolbar-center { display: flex; justify-content: center; @@ -457,7 +457,7 @@ body { display: flex; height: var(--toolbar-height); background-color: var(--color-toolbar-background, var(--color-pane-background)); - padding: 8px 16px; + padding: var(--toolbar-padding, 8px 16px); .lc-toolbar-center { display: flex; justify-content: center; diff --git a/packages/types/src/shell/type/widget-base-config.ts b/packages/types/src/shell/type/widget-base-config.ts index edddf2d68f..b23ba0f137 100644 --- a/packages/types/src/shell/type/widget-base-config.ts +++ b/packages/types/src/shell/type/widget-base-config.ts @@ -15,6 +15,11 @@ export interface IPublicTypeWidgetBaseConfig { props?: Record<string, any>; content?: any; contentProps?: Record<string, any>; + + /** + * 优先级,值越小,优先级越高,优先级高的会排在前面 + */ + index?: number; } export interface IPublicTypePanelDockConfig extends IPublicTypeWidgetBaseConfig { From 3786b3a7ff09c4223f0b84fc15da58356c123694 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 5 Dec 2023 07:38:51 +0000 Subject: [PATCH 355/469] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 634f73bee1..f175552e54 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.7", + "version": "1.2.8", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 1f214918bb5ce4d03132b78081eb63c815b0c347 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 7 Dec 2023 11:03:07 +0800 Subject: [PATCH 356/469] style: add css themes vars --- docs/docs/guide/expand/editor/theme.md | 8 +++++++- .../designer/src/builtin-simulator/bem-tools/borders.less | 2 +- packages/editor-skeleton/src/layouts/theme.less | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 36500cb458..ef0e04d28d 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -35,6 +35,7 @@ sidebar_position: 9 #### Icon 相关颜色 - `--color-icon-normal`: 默认状态 +- `--color-icon-light`: icon light 状态 - `--color-icon-hover`: 鼠标悬停状态 - `--color-icon-active`: 激活状态 - `--color-icon-reverse`: 反色状态 @@ -82,16 +83,21 @@ sidebar_position: 9 #### 区块背景色 - `--color-block-background-normal`: 区块背景色 -- `--color-block-background-light`: 区块背景色(light), 作用于画布组件 hover 时遮罩背景色。 +- `--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`: 拖拽元素时,元素原来位置的遮罩背景色 diff --git a/packages/designer/src/builtin-simulator/bem-tools/borders.less b/packages/designer/src/builtin-simulator/bem-tools/borders.less index 43fba6a2b8..cb83d36f38 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/borders.less +++ b/packages/designer/src/builtin-simulator/bem-tools/borders.less @@ -100,7 +100,7 @@ &&-detecting { z-index: 1; border-style: dashed; - background: var(--color-block-background-light, rgba(0,121,242,.04)); + background: var(--color-canvas-detecting-background, rgba(0,121,242,.04)); } &&-selecting { diff --git a/packages/editor-skeleton/src/layouts/theme.less b/packages/editor-skeleton/src/layouts/theme.less index 78c6fa5fd6..01542c7584 100644 --- a/packages/editor-skeleton/src/layouts/theme.less +++ b/packages/editor-skeleton/src/layouts/theme.less @@ -14,6 +14,7 @@ --color-icon-normal: @normal-alpha-4; --color-icon-hover: @normal-alpha-3; + --color-icon-light: @normal-alpha-5; --color-icon-active: @brand-color-1; --color-icon-reverse: @white-alpha-1; --color-icon-disabled: @normal-alpha-6; @@ -55,10 +56,11 @@ --color-pane-background: @white-alpha-1; --color-block-background-normal: @white-alpha-1; --color-block-background-light: @normal-alpha-9; - --color-block-background-shallow: @normal-alpha-8; --color-block-background-dark: @normal-alpha-7; + --color-block-background-shallow: @normal-alpha-8; --color-block-background-disabled: @normal-alpha-6; - --color-block-background-active: @brand-color-1-7; + --color-block-background-active: @brand-color-1; + --color-block-background-active-light: @brand-color-1-7; --color-block-background-warning: @brand-warning-alpha-7; --color-block-background-error: @brand-danger-alpha-7; --color-block-background-success: @brand-success-alpha-7; @@ -67,6 +69,8 @@ --color-layer-tooltip-background: rgba(44,47,51,0.8); --color-background: #edeff3; + --color-canvas-detecting-background: rgba(0,121,242,.04); + --pane-title-bg-color: rgba(31,56,88,.04); } From 6932c3bdc7def44a7db971672469c18e5fbc2e63 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 7 Dec 2023 05:49:17 +0000 Subject: [PATCH 357/469] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index f175552e54..a1b6d646f5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.8", + "version": "1.2.9", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 014834a31f1ebbcfb21c8993534046d753540b99 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 13 Dec 2023 12:16:28 +0800 Subject: [PATCH 358/469] style(outline): update outline-filter-icon style --- packages/plugin-outline-pane/src/views/style.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index 15f115ea6b..8521883b49 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -28,7 +28,7 @@ } .lc-outline-filter-icon { - background: var(--color-block-background-shallow, #ebecf0); + background: var(--color-block-background-light, #ebecf0); border: 1px solid var(--color-field-border, #c4c6cf); display: flex; align-items: center; From a0975428c4c7301b9d678cf0c19e6e49c241ee79 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 13 Dec 2023 14:21:59 +0800 Subject: [PATCH 359/469] docs: add faq024 --- docs/docs/faq/faq024.md | 133 ++++++++++++++++++++++++++++++++++++++++ docs/docs/faq/index.md | 1 + 2 files changed, 134 insertions(+) create mode 100644 docs/docs/faq/faq024.md diff --git a/docs/docs/faq/faq024.md b/docs/docs/faq/faq024.md new file mode 100644 index 0000000000..ab1b68f5d7 --- /dev/null +++ b/docs/docs/faq/faq024.md @@ -0,0 +1,133 @@ +--- +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<void>;` 来打开视图窗口。这里的 **resource** 参数指的是您要打开的特定资源,可通过 [workspace.resourceList](/site/docs/api/workspace#resourcelist) 获取。 +- **不推荐使用的过时方法**:有一个过时的方法 `openEditorWindow(resourceName: string, id: string, extra: Object, viewName?: string, sleep?: boolean): Promise<void>;` 也用于打开视图窗口。虽然仍然可用,但官方不推荐使用此方法,并计划在后续版本中废弃,因为它在维护和可扩展性方面存在限制。 + + + +#### 如何在全局插件中获取视图的上下文? + +- 在阿里低代码引擎的全局插件中获取视图的上下文,可以通过使用 **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 <div>/* 组件内容 */</div>; +}; +``` + +**定义全局插件**:定义一个函数,这个函数会在插件被注册时调用。这个函数通常接受一个上下文对象 **ctx**,它提供了对引擎功能的访问。 + +```javascript +const globalPlugin = (ctx) => { + const { skeleton } = ctx; + + skeleton.add({ + type: 'PanelDock', + name: 'datapool', + content: ProvideViewPluginContext((props) => { + // 组件内容 + return ( + <MyComponent {...props} /> + ) + }), + // 其他配置 + contentProps: { + // 需要提供 pluginContext 作为参数 + pluginContext: ctx, + } + }); +}; +``` + +通过这些步骤,您的全局插件中的 React 组件就能够获取并使用视图的上下文了。这为您在插件中实现更复杂的功能和交互提供了基础。 + + + +**注意事项** + +- **组件重渲染**:正常情况下,**pluginsContext** 是视图的上下文。当视图切换时,组件会重新渲染。如果需要在组件中处理视图切换导致的重新渲染,可以利用 React 的 **key** 属性。 + +**示例代码** + +```typescript +ProvideViewPluginContext(props => { + return ( + <DataPoolPane + {...props} + key={props.pluginContext?.editorWindow?.id} + ); +}); +``` + +通过这种方式,当视图切换时,组件会根据视图的不同进行重新渲染,确保组件状态与当前视图的上下文保持一致。这对于在低代码平台上开发复杂插件和交互功能是非常有用的。 + + + +#### 如何判断插件是否在 Workspace 模式下注册? + +**使用** **ctx.isPluginRegisteredInWorkspace()** **方法**: + +通过 **ctx.isPluginRegisteredInWorkspace()** 方法,可以判断一个插件是否在 Workspace 级别注册。以下是一个示例代码片段: + +```javascript +if (ctx.isPluginRegisteredInWorkspace('pluginName')) { + console.log('插件已在 Workspace 模式下注册。'); +} else { + console.log('插件未在 Workspace 模式下注册。'); +} +``` + +注意:此方法目前在 beta 版本中,可能会有 TypeScript 提示显示已移除。 + +**检查** **ctx.registerLevel** **的值**: + +可以通过比较 **ctx.registerLevel** 的值来判断插件的注册级别。示例代码如下: + +```javascript +if (ctx.registerLevel !== IPublicEnumPluginRegisterLevel.Workspace) { + console.log('插件未在 Workspace 模式下注册。'); +} else { + console.log('插件已在 Workspace 模式下注册。'); +} +``` diff --git a/docs/docs/faq/index.md b/docs/docs/faq/index.md index 5e5eee8ac4..ef8d7b3b15 100644 --- a/docs/docs/faq/index.md +++ b/docs/docs/faq/index.md @@ -15,6 +15,7 @@ tags: [FAQ] - [如何通过 this.utils 使用第三方工具扩展](/site/docs/faq/faq005) - [设置面板中的高级 tab 如何配置](/site/docs/faq/faq007) - [插件面板如何调整位置](/site/docs/faq/faq010) +- [workspace 模式常见问题](/site/docs/faq/faq024) ## 源码和依赖 - [某某 npm 包对应的源码在哪里?](/site/docs/faq/faq008) From 07ee7e0355bdb251053afdb860bae3c87012b1b9 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 13 Dec 2023 06:37:30 +0000 Subject: [PATCH 360/469] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index a1b6d646f5..eaf87ac219 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.9", + "version": "1.2.10", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 271aef4fb964f2fab74f1a70b020ab679564a10f Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 13 Dec 2023 16:12:15 +0800 Subject: [PATCH 361/469] chore: add publish engine actions --- .github/workflows/publish docs.yml | 2 +- .github/workflows/publish engine beta.yml | 30 +++++++++++++++++++ .github/workflows/publish engine.yml | 26 ++++++++++++++++ package.json | 4 +-- .../src/layouts/workbench.less | 1 + 5 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/publish engine beta.yml create mode 100644 .github/workflows/publish engine.yml diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index dcbeec3844..ed16bb869a 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -5,7 +5,7 @@ on: branches: - develop paths: - - 'docs/**' + - 'docs/docs/**' jobs: publish-docs: diff --git a/.github/workflows/publish engine beta.yml b/.github/workflows/publish engine beta.yml new file mode 100644 index 0000000000..ab498c8df6 --- /dev/null +++ b/.github/workflows/publish engine beta.yml @@ -0,0 +1,30 @@ +name: Update and Publish Docs + +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 "::set-output name=version::$(node -p "require('./docs/package.json').version")" diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml new file mode 100644 index 0000000000..3710cf816c --- /dev/null +++ b/.github/workflows/publish engine.yml @@ -0,0 +1,26 @@ +name: Update and Publish Docs + +on: + workflow_dispatch: + +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 + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Get version + id: get_version + run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" diff --git a/package.json b/package.json index aded2a3015..caabbeeb13 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,11 @@ "lint:fix": "f2elint fix -i ./packages/*/src", "lint:modules": "f2elint scan -q -i ./modules/*/src", "lint:modules:fix": "f2elint fix -i ./modules/*/src", - "pub": "npm run watchdog:build && lerna publish patch --force-publish --exact --no-changelog", + "pub": "npm run watchdog:build && lerna publish patch --yes --force-publish --exact --no-changelog", "pub:premajor": "npm run watchdog:build && lerna publish premajor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:preminor": "npm run watchdog:build && lerna publish preminor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:prepatch": "npm run watchdog:build && lerna publish prepatch --force-publish --exact --dist-tag beta --preid beta --no-changelog", - "pub:prerelease": "npm run watchdog:build && lerna publish prerelease --force-publish --exact --dist-tag beta --preid beta --no-changelog", + "pub:prerelease": "npm run watchdog:build && lerna publish prerelease --yes --force-publish --exact --dist-tag beta --preid beta --no-changelog", "setup": "node ./scripts/setup.js", "setup:test": "./scripts/setup-for-test.sh", "setup:skip-build": "./scripts/setup-skip-build.sh", diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 596ea69f60..97a017523d 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -105,6 +105,7 @@ body { right: 0; bottom: 0; z-index: -1; + overflow: hidden; &.active { z-index: 999; From a25aad4975231706a9e47ba3e62e17034ce18846 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 13 Dec 2023 16:43:51 +0800 Subject: [PATCH 362/469] fix(outline): fix view change bugs in workspace mode --- .github/workflows/publish engine beta.yml | 4 ++-- .github/workflows/publish engine.yml | 4 ++-- packages/plugin-outline-pane/src/controllers/tree-master.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish engine beta.yml b/.github/workflows/publish engine beta.yml index ab498c8df6..32c5b4c15b 100644 --- a/.github/workflows/publish engine beta.yml +++ b/.github/workflows/publish engine beta.yml @@ -1,4 +1,4 @@ -name: Update and Publish Docs +name: Publish Engine Beta on: push: @@ -27,4 +27,4 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version id: get_version - run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" + run: echo "::set-output name=version::$(node -p "require('./package.json').version")" diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index 3710cf816c..f9206d4cb9 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -1,4 +1,4 @@ -name: Update and Publish Docs +name: Publish Engine on: workflow_dispatch: @@ -23,4 +23,4 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version id: get_version - run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" + run: echo "::set-output name=version::$(node -p "require('./package.json').version")" diff --git a/packages/plugin-outline-pane/src/controllers/tree-master.ts b/packages/plugin-outline-pane/src/controllers/tree-master.ts index ede5f0f5f3..f86ce3deca 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-master.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-master.ts @@ -51,9 +51,9 @@ export class TreeMaster { windowViewTypeChangeEvent(); workspace.onChangeActiveWindow(() => { - windowViewTypeChangeEvent(); this.setPluginContext(workspace.window?.currentEditorView); dispose && dispose(); + windowViewTypeChangeEvent(); }); } } From 2ec9bf7cdf203c3d4cdda8dc4048c44851019028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Wed, 13 Dec 2023 17:05:03 +0800 Subject: [PATCH 363/469] chore: create publish engine.yml --- .github/workflows/publish engine.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/publish engine.yml diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml new file mode 100644 index 0000000000..7c245a3d82 --- /dev/null +++ b/.github/workflows/publish engine.yml @@ -0,0 +1,26 @@ +name: Publish Engine + +on: + workflow_dispatch: + +jobs: + publish-engine: + runs-on: ubuntu-latest + 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 pub + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Get version + id: get_version + run: echo "::set-output name=version::$(node -p "require('./package.json').version")" From 3c3a305c7aa00544d1f28084367eb43f3e42b5a1 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 13 Dec 2023 17:22:40 +0800 Subject: [PATCH 364/469] chore: update publish engine.yml --- .github/workflows/publish engine.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index 7c245a3d82..6825c66fca 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -6,6 +6,9 @@ on: jobs: publish-engine: runs-on: ubuntu-latest + if: >- + contains(github.ref, 'refs/heads/release/') && + (github.actor == 'JackLian' || github.actor == 'liujuping') steps: - uses: actions/checkout@v2 - name: Setup Node.js From 2e604c99109b82d2dc1f447ab1de37f623e3188d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 18:58:24 +0800 Subject: [PATCH 365/469] Fix/component lifecycle not execute (#2690) * fix: recover component lifecycle and avoid execute from scope __proto__ From c3d0ffb62cd03d81f4fc46d01b1714eb1dd79a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 19:28:41 +0800 Subject: [PATCH 366/469] Fix/component lifecycle not execute (#2692) * fix: recover component lifecycle and avoid execute from scope __proto__ From f418e5b2c18ddb5299a575f0888ad67de642bcf2 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 13 Dec 2023 09:34:24 +0000 Subject: [PATCH 367/469] chore(release): publish 1.2.3 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 34be89faa8..98ef80f138 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.2", + "version": "1.2.3", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 69a402ed22..e961451d88 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.2", + "version": "1.2.3", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index de9d30bc8b..345783c806 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.2", + "version": "1.2.3", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index fe2d0d43ff..fa5c1e13e6 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.2", + "version": "1.2.3", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 3ea47f79da..c9eef3534c 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.2", + "version": "1.2.3", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-editor-skeleton": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-editor-skeleton": "1.2.3", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.2", - "@alilc/lowcode-plugin-outline-pane": "1.2.2", - "@alilc/lowcode-shell": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", - "@alilc/lowcode-workspace": "1.2.2", + "@alilc/lowcode-plugin-designer": "1.2.3", + "@alilc/lowcode-plugin-outline-pane": "1.2.3", + "@alilc/lowcode-shell": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-workspace": "1.2.3", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index d737a7c868..71a21484c4 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.2", + "version": "1.2.3", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index fe653568bb..500c0c9611 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.2", + "version": "1.2.3", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 2540ca5ad4..5a2ef38a45 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.2", + "version": "1.2.3", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 60ea0c6981..837aebc85e 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.2", + "version": "1.2.3", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-renderer-core": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 520ff32c89..dc9b7b1478 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.2", + "version": "1.2.3", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-rax-renderer": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-rax-renderer": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index a35039fc3c..1dceb9c2e7 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.2", + "version": "1.2.3", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.2" + "@alilc/lowcode-renderer-core": "1.2.3" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 413b1825f8..8935c92eef 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.2", + "version": "1.2.3", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-react-renderer": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-react-renderer": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 3b96ef40b3..4774ae3689 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.2", + "version": "1.2.3", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 7e20192352..2ebf14bbc2 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.2", + "version": "1.2.3", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-editor-skeleton": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", - "@alilc/lowcode-workspace": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-editor-skeleton": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-workspace": "1.2.3", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index c4fa290036..c0b8e203fe 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.2", + "version": "1.2.3", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index af76e9e2f6..00efffb8d3 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.2", + "version": "1.2.3", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-types": "1.2.3", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 4724323797..8c09a93b6c 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.2", + "version": "1.2.3", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-editor-skeleton": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-editor-skeleton": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From f2d8fca18840cfaaa531219b0cb430294d99f01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Thu, 14 Dec 2023 09:55:14 +0800 Subject: [PATCH 368/469] docs: update workspace.md --- docs/docs/api/workspace.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/api/workspace.md b/docs/docs/api/workspace.md index 9911dc93ad..6d0714ae09 100644 --- a/docs/docs/api/workspace.md +++ b/docs/docs/api/workspace.md @@ -87,7 +87,7 @@ registerResourceType(resourceTypeModel: IPublicTypeResourceType): void; setResourceList(resourceList: IPublicResourceList) {} ``` -相关类型:[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts) +相关类型:[IPublicResourceData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-list.ts) ### openEditorWindow From c0ddba5543d7fee9735445774806396fec82fdfc Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 14 Dec 2023 02:15:38 +0000 Subject: [PATCH 369/469] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index eaf87ac219..3c43bff657 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.10", + "version": "1.2.11", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 27bf7babe53ac07bf165832cd4eb55f4aafcf37c Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 10:16:30 +0800 Subject: [PATCH 370/469] chore: use tnpm as oss-syncing source --- scripts/sync-oss.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/sync-oss.js b/scripts/sync-oss.js index ba4a77be37..2108e676d2 100644 --- a/scripts/sync-oss.js +++ b/scripts/sync-oss.js @@ -19,7 +19,7 @@ const onResponse = function (res) { chunks.push(chunk); }); - res.on('end', (chunk) => { + res.on('end', () => { const body = Buffer.concat(chunks); console.table(JSON.stringify(JSON.parse(body.toString()), null, 2)); }); @@ -39,9 +39,9 @@ const postData = JSON.stringify({ }, ], // 可以发布指定源的 npm 包,默认公网 npm - useTnpm: false, + useTnpm: true, }); req.write(postData); -req.end(); \ No newline at end of file +req.end(); From 9d526ebcd8a43635a27a300f00d8223f74ecc353 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 10:22:26 +0800 Subject: [PATCH 371/469] chore(workflows/publish-docs): update commit message --- .github/workflows/publish docs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index ed16bb869a..4bddec3ba3 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -24,7 +24,7 @@ jobs: git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add package.json - git commit -m "Update package version" + git commit -m "chore(docs): publish documentation" git push - run: cd docs && npm publish env: @@ -48,4 +48,4 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, body: '🚀 New version has been released: ' + '${{ needs.publish-docs.outputs.version }}' - }) \ No newline at end of file + }) From bb50a20ef11367fbfe52efc800194697c0c3056e Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 10:44:34 +0800 Subject: [PATCH 372/469] chore(docs): use tnpm as oss-syncing source --- docs/scripts/sync-oss.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/scripts/sync-oss.js b/docs/scripts/sync-oss.js index 9518a8ea7f..2d052dfa12 100644 --- a/docs/scripts/sync-oss.js +++ b/docs/scripts/sync-oss.js @@ -19,7 +19,7 @@ const onResponse = function (res) { chunks.push(chunk); }); - res.on('end', (chunk) => { + res.on('end', () => { const body = Buffer.concat(chunks); console.table(JSON.stringify(JSON.parse(body.toString()), null, 2)); }); @@ -39,9 +39,9 @@ const postData = JSON.stringify({ }, ], // 可以发布指定源的 npm 包,默认公网 npm - useTnpm: false, + useTnpm: true, }); req.write(postData); -req.end(); \ No newline at end of file +req.end(); From a567f12473791f05a4282bc04299d936d4fd8a30 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 11:08:47 +0800 Subject: [PATCH 373/469] docs: add new link to video page --- docs/docs/video/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md index 8ae21620bc..d7d438e4f7 100644 --- a/docs/docs/video/index.md +++ b/docs/docs/video/index.md @@ -3,6 +3,7 @@ - [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) # 社区视频 +- [低代码从入门到实战:低代码引擎实践](https://www.bilibili.com/video/BV1aP4y1Q7Xa/?vd_source=cb026325b1d587f9669d09fb586bc020) - [阿里低代码引擎项目实战 (1)-引擎 demo 部署到 faas 服务](https://www.bilibili.com/video/BV1B44y1P7GM/) - [【有翻车】阿里低代码引擎项目实战 (2)-保存页面到远端存储](https://www.bilibili.com/video/BV1AS4y1K7DP/) - [阿里巴巴低代码引擎项目实战 (3)-自定义组件接入](https://www.bilibili.com/video/BV1dZ4y1m76S/) From ef573d3ad9e3c3c8304957c4198f4217a394400a Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 14 Dec 2023 03:09:41 +0000 Subject: [PATCH 374/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 3c43bff657..75d7f1f28f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.11", + "version": "1.2.12", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From ec843543f04a9e10c221b1d99368d3b45986747a Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 14 Dec 2023 11:31:05 +0800 Subject: [PATCH 375/469] chore: update docs publish action --- .github/workflows/publish docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index 4bddec3ba3..7218976e42 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -26,7 +26,7 @@ jobs: git add package.json git commit -m "chore(docs): publish documentation" git push - - run: cd docs && npm publish + - run: cd docs && npm build && npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version From 08401c76f93ccb9200c43d3fec2455ea6dd89cf6 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 13:57:29 +0800 Subject: [PATCH 376/469] chore(workflows/publish-docs): add workflow_dispatch trigger --- .github/workflows/publish docs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index 7218976e42..3b42398310 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -6,6 +6,7 @@ on: - develop paths: - 'docs/docs/**' + workflow_dispatch: jobs: publish-docs: From 613142b2d836f73e98ad22f443f96e99e706ef4f Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:00:52 +0800 Subject: [PATCH 377/469] chore(workflows/publish-docs): add workflow_dispatch trigger --- .github/workflows/publish docs.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index ed16bb869a..3b42398310 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -6,6 +6,7 @@ on: - develop paths: - 'docs/docs/**' + workflow_dispatch: jobs: publish-docs: @@ -24,9 +25,9 @@ jobs: git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add package.json - git commit -m "Update package version" + git commit -m "chore(docs): publish documentation" git push - - run: cd docs && npm publish + - run: cd docs && npm build && npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version @@ -48,4 +49,4 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, body: '🚀 New version has been released: ' + '${{ needs.publish-docs.outputs.version }}' - }) \ No newline at end of file + }) From cdcc8c8a90e9e7075d9ca8ade90fe84adccde7e3 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 14 Dec 2023 06:04:49 +0000 Subject: [PATCH 378/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 75d7f1f28f..0d4964cd9a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.12", + "version": "1.2.13", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From b56a2a92742e170b95766e2907a3bde099d8a833 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:13:58 +0800 Subject: [PATCH 379/469] chore(workflows/publish-docs): update config --- .github/workflows/publish docs.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index 3b42398310..e85d08f2a9 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -16,7 +16,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v2 with: - node-version: '14' + ref: 'develop' + node-version: '16' registry-url: 'https://registry.npmjs.org' - run: cd docs && npm install - run: | @@ -27,7 +28,7 @@ jobs: git add package.json git commit -m "chore(docs): publish documentation" git push - - run: cd docs && npm build && npm publish + - run: cd docs && npm run build && npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version From 729b123e462b17123b691ba1925dab2b8af07ee6 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 14 Dec 2023 06:16:05 +0000 Subject: [PATCH 380/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 0d4964cd9a..c1d9fe53fb 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.13", + "version": "1.2.14", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 729083aa01844d2b40ca39a45e69cfd82028279e Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:18:57 +0800 Subject: [PATCH 381/469] chore(workflows/publish-docs): update config --- .github/workflows/publish docs.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index 3b42398310..e85d08f2a9 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -16,7 +16,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v2 with: - node-version: '14' + ref: 'develop' + node-version: '16' registry-url: 'https://registry.npmjs.org' - run: cd docs && npm install - run: | @@ -27,7 +28,7 @@ jobs: git add package.json git commit -m "chore(docs): publish documentation" git push - - run: cd docs && npm build && npm publish + - run: cd docs && npm run build && npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version From 5d08b6858d73f24cae33b07c22474c83f3868d27 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:45:01 +0800 Subject: [PATCH 382/469] chore(workflows/publish-docs): update config --- .github/workflows/publish docs.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index e85d08f2a9..7553fa50f8 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -7,6 +7,14 @@ on: paths: - 'docs/docs/**' workflow_dispatch: + inputs: + branch: + description: 'doc is designed be published from develop' + required: true + default: 'develop' + type: choice + options: + - 'develop' jobs: publish-docs: From 53078ba5f0c973ccf137def297cdd3dc0ba23a0c Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:46:17 +0800 Subject: [PATCH 383/469] chore(workflows/publish-docs): update config --- .github/workflows/publish docs.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index e85d08f2a9..7553fa50f8 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -7,6 +7,14 @@ on: paths: - 'docs/docs/**' workflow_dispatch: + inputs: + branch: + description: 'doc is designed be published from develop' + required: true + default: 'develop' + type: choice + options: + - 'develop' jobs: publish-docs: From 9394aecc7c612ab6818d3d5751d69d2a19eb2b16 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:49:25 +0800 Subject: [PATCH 384/469] chore(workflows/publish-docs): update config --- .github/workflows/publish docs.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index 7553fa50f8..e85d08f2a9 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -7,14 +7,6 @@ on: paths: - 'docs/docs/**' workflow_dispatch: - inputs: - branch: - description: 'doc is designed be published from develop' - required: true - default: 'develop' - type: choice - options: - - 'develop' jobs: publish-docs: From 39d030bfc3a1546b6ca13208734be28c30561e2d Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:49:25 +0800 Subject: [PATCH 385/469] chore(workflows/publish-docs): update config --- .github/workflows/publish docs.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index 7553fa50f8..e85d08f2a9 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -7,14 +7,6 @@ on: paths: - 'docs/docs/**' workflow_dispatch: - inputs: - branch: - description: 'doc is designed be published from develop' - required: true - default: 'develop' - type: choice - options: - - 'develop' jobs: publish-docs: From 230e63ce5527078b2d223f873cd0c2f3796cf871 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 17:27:07 +0800 Subject: [PATCH 386/469] docs: add new link to video page --- docs/docs/video/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md index d7d438e4f7..38a0e8a5ce 100644 --- a/docs/docs/video/index.md +++ b/docs/docs/video/index.md @@ -3,7 +3,8 @@ - [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) # 社区视频 -- [低代码从入门到实战:低代码引擎实践](https://www.bilibili.com/video/BV1aP4y1Q7Xa/?vd_source=cb026325b1d587f9669d09fb586bc020) +- [低代码从入门到实战:低代码引擎实践](https://www.bilibili.com/video/BV1aP4y1Q7Xa/) +- [低代码技术在研发团队的应用模式](https://www.bilibili.com/video/BV1L14y1Y72J/) - [阿里低代码引擎项目实战 (1)-引擎 demo 部署到 faas 服务](https://www.bilibili.com/video/BV1B44y1P7GM/) - [【有翻车】阿里低代码引擎项目实战 (2)-保存页面到远端存储](https://www.bilibili.com/video/BV1AS4y1K7DP/) - [阿里巴巴低代码引擎项目实战 (3)-自定义组件接入](https://www.bilibili.com/video/BV1dZ4y1m76S/) From c6e00252568f7429385d31996ee2f9062ca2575e Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 14 Dec 2023 09:28:13 +0000 Subject: [PATCH 387/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index c1d9fe53fb..3b9e4902a2 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.14", + "version": "1.2.15", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 711a5f66b912da315fcdd2a16c65ba188b9623f6 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Sat, 16 Dec 2023 18:30:03 +0800 Subject: [PATCH 388/469] style: remove .lc-workbench-center z-index --- packages/editor-skeleton/src/layouts/workbench.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 97a017523d..9c7a9815dd 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -363,7 +363,7 @@ body { flex: 1; display: flex; flex-direction: column; - z-index: 10; + .lc-toolbar { display: flex; height: var(--toolbar-height); From 16713f4b848f3648fa93c82d70007fbec4e8a816 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Sun, 17 Dec 2023 16:37:17 +0800 Subject: [PATCH 389/469] feat(skeleton): Add TS defs for modules & optimize Tabs display with array contents --- .../src/components/widget-views/index.tsx | 23 ++++++++--- .../src/layouts/left-fixed-pane.tsx | 7 ++-- .../src/layouts/left-float-pane.tsx | 5 +-- packages/editor-skeleton/src/skeleton.ts | 38 +++++++++---------- packages/editor-skeleton/src/types.ts | 33 +++------------- packages/editor-skeleton/src/widget/panel.ts | 15 +++----- .../src/shell/type/widget-base-config.ts | 27 ++++++++++++- 7 files changed, 78 insertions(+), 70 deletions(-) diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index ba49b3d1ab..2b2f6931cb 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -266,15 +266,28 @@ export class PanelView extends Component<{ } @observer -export class TabsPanelView extends Component<{ container: WidgetContainer<Panel> }> { +export class TabsPanelView extends Component<{ + container: WidgetContainer<Panel>; + // shouldHideSingleTab: 一个布尔值,用于控制当 Tabs 组件只有一个标签时是否隐藏该标签。 + shouldHideSingleTab?: boolean; +}> { render() { const { container } = this.props; const titles: ReactElement[] = []; const contents: ReactElement[] = []; - container.items.forEach((item: any) => { - titles.push(<PanelTitle key={item.id} panel={item} className="lc-tab-title" />); - contents.push(<PanelView key={item.id} panel={item} hideOperationRow hideDragLine />); - }); + // 如果只有一个标签且 shouldHideSingleTab 为 true,则不显示 Tabs + if (this.props.shouldHideSingleTab && container.items.length === 1) { + contents.push(<PanelView key={container.items[0].id} panel={container.items[0]} hideOperationRow hideDragLine />); + } else { + container.items.forEach((item: any) => { + titles.push(<PanelTitle key={item.id} panel={item} className="lc-tab-title" />); + contents.push(<PanelView key={item.id} panel={item} hideOperationRow hideDragLine />); + }); + } + + if (!titles.length) { + return contents; + } return ( <div className="lc-tabs"> diff --git a/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx b/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx index cda600f74a..a56b449079 100644 --- a/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx +++ b/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx @@ -2,17 +2,16 @@ import { Component, Fragment } from 'react'; import classNames from 'classnames'; import { observer } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; -import { PanelConfig } from '../types'; import { Panel } from '../widget/panel'; +import { IPublicTypePanelConfig } from '@alilc/lowcode-types'; @observer -export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, Panel> }> { +export default class LeftFixedPane extends Component<{ area: Area<IPublicTypePanelConfig, Panel> }> { componentDidUpdate() { // FIXME: dirty fix, need deep think this.props.area.skeleton.editor.get('designer')?.touchOffsetObserver(); } - render() { const { area } = this.props; const width = area.current?.config.props?.width; @@ -36,7 +35,7 @@ export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, P } @observer -class Contents extends Component<{ area: Area<PanelConfig, Panel> }> { +class Contents extends Component<{ area: Area<IPublicTypePanelConfig, Panel> }> { render() { const { area } = this.props; return <Fragment>{area.container.items.map((panel) => panel.content)}</Fragment>; diff --git a/packages/editor-skeleton/src/layouts/left-float-pane.tsx b/packages/editor-skeleton/src/layouts/left-float-pane.tsx index 15f4926199..296f083211 100644 --- a/packages/editor-skeleton/src/layouts/left-float-pane.tsx +++ b/packages/editor-skeleton/src/layouts/left-float-pane.tsx @@ -3,11 +3,10 @@ import classNames from 'classnames'; import { observer, Focusable } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; import { Panel } from '../widget/panel'; -import { PanelConfig } from '../types'; -import { IPublicApiProject } from '@alilc/lowcode-types'; +import { IPublicApiProject, IPublicTypePanelConfig } from '@alilc/lowcode-types'; @observer -export default class LeftFloatPane extends Component<{ area: Area<PanelConfig, Panel> }> { +export default class LeftFloatPane extends Component<{ area: Area<IPublicTypePanelConfig, Panel> }> { private dispose?: () => void; private focusing?: Focusable; diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 13967e94d6..7ff462391d 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -1,7 +1,6 @@ import { action, makeObservable, obx, engineConfig, IEditor, FocusTracker } from '@alilc/lowcode-editor-core'; import { DockConfig, - PanelConfig, WidgetConfig, PanelDockConfig, DialogDockConfig, @@ -29,6 +28,7 @@ import { IPublicTypeSkeletonConfig, IPublicApiSkeleton, IPublicTypeConfigTransducer, + IPublicTypePanelConfig, } from '@alilc/lowcode-types'; const logger = new Logger({ level: 'warn', bizName: 'skeleton' }); @@ -70,15 +70,15 @@ export interface ISkeleton extends Omit<IPublicApiSkeleton, readonly toolbar: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>; - readonly leftFixedArea: Area<PanelConfig, Panel>; + readonly leftFixedArea: Area<IPublicTypePanelConfig, Panel>; - readonly leftFloatArea: Area<PanelConfig, Panel>; + readonly leftFloatArea: Area<IPublicTypePanelConfig, Panel>; - readonly rightArea: Area<PanelConfig, Panel>; + readonly rightArea: Area<IPublicTypePanelConfig, Panel>; - readonly mainArea: Area<WidgetConfig | PanelConfig, Widget | Panel>; + readonly mainArea: Area<WidgetConfig | IPublicTypePanelConfig, Widget | Panel>; - readonly bottomArea: Area<PanelConfig, Panel>; + readonly bottomArea: Area<IPublicTypePanelConfig, Panel>; readonly stages: Area<StageConfig, Stage>; @@ -104,7 +104,7 @@ export interface ISkeleton extends Omit<IPublicApiSkeleton, defaultSetCurrent?: boolean, ): WidgetContainer; - createPanel(config: PanelConfig): Panel; + createPanel(config: IPublicTypePanelConfig): Panel; add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined; } @@ -124,15 +124,15 @@ export class Skeleton implements ISkeleton { readonly toolbar: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>; - readonly leftFixedArea: Area<PanelConfig, Panel>; + readonly leftFixedArea: Area<IPublicTypePanelConfig, Panel>; - readonly leftFloatArea: Area<PanelConfig, Panel>; + readonly leftFloatArea: Area<IPublicTypePanelConfig, Panel>; - readonly rightArea: Area<PanelConfig, Panel>; + readonly rightArea: Area<IPublicTypePanelConfig, Panel>; - @obx readonly mainArea: Area<WidgetConfig | PanelConfig, Widget | Panel>; + @obx readonly mainArea: Area<WidgetConfig | IPublicTypePanelConfig, Widget | Panel>; - readonly bottomArea: Area<PanelConfig, Panel>; + readonly bottomArea: Area<IPublicTypePanelConfig, Panel>; readonly stages: Area<StageConfig, Stage>; @@ -388,9 +388,9 @@ export class Skeleton implements ISkeleton { return this.widgets.find(widget => widget.name === name); } - createPanel(config: PanelConfig) { + createPanel(config: IPublicTypePanelConfig) { const parsedConfig = this.parseConfig(config); - const panel = new Panel(this, parsedConfig as PanelConfig); + const panel = new Panel(this, parsedConfig as IPublicTypePanelConfig); this.panels.set(panel.name, panel); logger.debug(`Panel created with name: ${panel.name} \nconfig:`, config, '\n current panels: ', this.panels); return panel; @@ -496,7 +496,7 @@ export class Skeleton implements ISkeleton { return this.leftArea.add(parsedConfig as PanelDockConfig); case 'rightArea': case 'right': - return this.rightArea.add(parsedConfig as PanelConfig); + return this.rightArea.add(parsedConfig as IPublicTypePanelConfig); case 'topArea': case 'top': return this.topArea.add(parsedConfig as PanelDockConfig); @@ -508,14 +508,14 @@ export class Skeleton implements ISkeleton { case 'main': case 'center': case 'centerArea': - return this.mainArea.add(parsedConfig as PanelConfig); + return this.mainArea.add(parsedConfig as IPublicTypePanelConfig); case 'bottomArea': case 'bottom': - return this.bottomArea.add(parsedConfig as PanelConfig); + return this.bottomArea.add(parsedConfig as IPublicTypePanelConfig); case 'leftFixedArea': - return this.leftFixedArea.add(parsedConfig as PanelConfig); + return this.leftFixedArea.add(parsedConfig as IPublicTypePanelConfig); case 'leftFloatArea': - return this.leftFloatArea.add(parsedConfig as PanelConfig); + return this.leftFloatArea.add(parsedConfig as IPublicTypePanelConfig); case 'stages': return this.stages.add(parsedConfig as StageConfig); default: diff --git a/packages/editor-skeleton/src/types.ts b/packages/editor-skeleton/src/types.ts index b73dc4adce..8c5f1484a0 100644 --- a/packages/editor-skeleton/src/types.ts +++ b/packages/editor-skeleton/src/types.ts @@ -1,11 +1,11 @@ import { ReactElement, ComponentType } from 'react'; import { IPublicTypeTitleContent, - IPublicTypeI18nData, IPublicTypeWidgetConfigArea, IPublicTypeWidgetBaseConfig, - IPublicTypePanelDockPanelProps, IPublicTypePanelDockProps, + IPublicTypePanelConfigProps, + IPublicTypePanelConfig, } from '@alilc/lowcode-types'; import { IWidget } from './widget/widget'; @@ -66,40 +66,17 @@ export function isDialogDockConfig(obj: any): obj is DialogDockConfig { return obj && obj.type === 'DialogDock'; } -// 窗格扩展 -export interface PanelConfig extends IPublicTypeWidgetBaseConfig { - type: 'Panel'; - content?: string | ReactElement | ComponentType<any> | PanelConfig[]; // as children - props?: PanelProps; -} - -export function isPanelConfig(obj: any): obj is PanelConfig { +export function isPanelConfig(obj: any): obj is IPublicTypePanelConfig { return obj && obj.type === 'Panel'; } -export type HelpTipConfig = string | { url?: string; content?: string | ReactElement }; - -export interface PanelProps extends IPublicTypePanelDockPanelProps { - title?: IPublicTypeTitleContent; - icon?: any; // 冗余字段 - description?: string | IPublicTypeI18nData; - help?: HelpTipConfig; // 显示问号帮助 - hiddenWhenInit?: boolean; // when this is true, by default will be hidden - condition?: (widget: IWidget) => any; - onInit?: (widget: IWidget) => any; - onDestroy?: () => any; - shortcut?: string; // 只有在特定位置,可触发 toggle show - enableDrag?: boolean; // 是否开启通过 drag 调整 宽度 - keepVisibleWhileDragging?: boolean; // 是否在该 panel 范围内拖拽时保持 visible 状态 -} - export interface PanelDockConfig extends IDockBaseConfig { type: 'PanelDock'; panelName?: string; - panelProps?: PanelProps & { + panelProps?: IPublicTypePanelConfigProps & { area?: IPublicTypeWidgetConfigArea; }; - content?: string | ReactElement | ComponentType<any> | PanelConfig[]; // content for pane + content?: string | ReactElement | ComponentType<any> | IPublicTypePanelConfig[]; // content for pane } export function isPanelDockConfig(obj: any): obj is PanelDockConfig { diff --git a/packages/editor-skeleton/src/widget/panel.ts b/packages/editor-skeleton/src/widget/panel.ts index b35af6a212..3a1ce3b00b 100644 --- a/packages/editor-skeleton/src/widget/panel.ts +++ b/packages/editor-skeleton/src/widget/panel.ts @@ -1,10 +1,9 @@ import { createElement, ReactNode } from 'react'; import { obx, computed, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { uniqueId, createContent } from '@alilc/lowcode-utils'; -import { IPublicTypeTitleContent } from '@alilc/lowcode-types'; +import { IPublicTypeHelpTipConfig, IPublicTypePanelConfig, IPublicTypeTitleContent } from '@alilc/lowcode-types'; import { WidgetContainer } from './widget-container'; import { getEvent } from '@alilc/lowcode-shell'; -import { PanelConfig, HelpTipConfig } from '../types'; import { TitledPanelView, TabsPanelView, PanelView } from '../components/widget-views'; import { ISkeleton } from '../skeleton'; import { composeTitle } from './utils'; @@ -45,6 +44,7 @@ export class Panel implements IWidget { if (this.container) { return createElement(TabsPanelView, { container: this.container, + shouldHideSingleTab: true, }); } @@ -72,15 +72,15 @@ export class Panel implements IWidget { readonly title: IPublicTypeTitleContent; - readonly help?: HelpTipConfig; + readonly help?: IPublicTypeHelpTipConfig; private plain = false; - private container?: WidgetContainer<Panel, PanelConfig>; + private container?: WidgetContainer<Panel, IPublicTypePanelConfig>; @obx.ref public parent?: WidgetContainer; - constructor(readonly skeleton: ISkeleton, readonly config: PanelConfig) { + constructor(readonly skeleton: ISkeleton, readonly config: IPublicTypePanelConfig) { makeObservable(this); const { name, content, props = {} } = config; const { hideTitleBar, title, icon, description, help } = props; @@ -90,9 +90,6 @@ export class Panel implements IWidget { this.plain = hideTitleBar || !title; this.help = help; if (Array.isArray(content)) { - if (content.length === 1) { - // todo: not show tabs - } this.container = this.skeleton.createContainer( name, (item) => { @@ -127,7 +124,7 @@ export class Panel implements IWidget { this.parent = parent; } - add(item: Panel | PanelConfig) { + add(item: Panel | IPublicTypePanelConfig) { return this.container?.add(item); } diff --git a/packages/types/src/shell/type/widget-base-config.ts b/packages/types/src/shell/type/widget-base-config.ts index b23ba0f137..2764ce1927 100644 --- a/packages/types/src/shell/type/widget-base-config.ts +++ b/packages/types/src/shell/type/widget-base-config.ts @@ -1,4 +1,27 @@ -import { IPublicTypeIconType, IPublicTypeTitleContent, IPublicTypeWidgetConfigArea, TipContent } from './'; +import { ReactElement, ComponentType } from 'react'; +import { IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeTitleContent, IPublicTypeWidgetConfigArea, TipContent } from './'; + +export type IPublicTypeHelpTipConfig = string | { url?: string; content?: string | ReactElement }; + +export interface IPublicTypePanelConfigProps extends IPublicTypePanelDockPanelProps { + title?: IPublicTypeTitleContent; + icon?: any; // 冗余字段 + description?: string | IPublicTypeI18nData; + help?: IPublicTypeHelpTipConfig; // 显示问号帮助 + hiddenWhenInit?: boolean; // when this is true, by default will be hidden + condition?: (widget: any) => any; + onInit?: (widget: any) => any; + onDestroy?: () => any; + shortcut?: string; // 只有在特定位置,可触发 toggle show + enableDrag?: boolean; // 是否开启通过 drag 调整 宽度 + keepVisibleWhileDragging?: boolean; // 是否在该 panel 范围内拖拽时保持 visible 状态 +} + +export interface IPublicTypePanelConfig extends IPublicTypeWidgetBaseConfig { + type: 'Panel'; + content?: string | ReactElement | ComponentType<any> | IPublicTypePanelConfig[]; // as children + props?: IPublicTypePanelConfigProps; +} export interface IPublicTypeWidgetBaseConfig { [extra: string]: any; @@ -13,7 +36,7 @@ export interface IPublicTypeWidgetBaseConfig { */ area?: IPublicTypeWidgetConfigArea; props?: Record<string, any>; - content?: any; + content?: string | ReactElement | ComponentType<any> | IPublicTypePanelConfig[]; contentProps?: Record<string, any>; /** From 594abc4e6c967dc75a6e4aedfd132a778b8312a9 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 18 Dec 2023 14:27:31 +0800 Subject: [PATCH 390/469] style(designer): update bem-tools index --- .../designer/src/builtin-simulator/bem-tools/bem-tools.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/designer/src/builtin-simulator/bem-tools/bem-tools.less b/packages/designer/src/builtin-simulator/bem-tools/bem-tools.less index 83a411e566..8c66e85139 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/bem-tools.less +++ b/packages/designer/src/builtin-simulator/bem-tools/bem-tools.less @@ -6,5 +6,5 @@ bottom: 0; right: 0; overflow: visible; - z-index: 800; + z-index: 1; } From 2bf3aa70a70ebde17139330423d0f02d2a1a8945 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 18 Dec 2023 19:16:42 +0800 Subject: [PATCH 391/469] docs: add skeleton.getAreaItems docs --- docs/docs/api/skeleton.md | 17 +++++++++++++++++ packages/types/src/shell/api/skeleton.ts | 8 +++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index 5bfa239724..ea5672172c 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -297,7 +297,24 @@ showArea(areaName: string): void; 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 diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts index 9a36aa4690..83a3f97788 100644 --- a/packages/types/src/shell/api/skeleton.ts +++ b/packages/types/src/shell/api/skeleton.ts @@ -1,5 +1,5 @@ import { IPublicModelSkeletonItem } from '../model'; -import { IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type'; +import { IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '../type'; export interface IPublicApiSkeleton { @@ -20,6 +20,12 @@ export interface IPublicApiSkeleton { */ remove(config: IPublicTypeSkeletonConfig): number | undefined; + /** + * 获取某个区域下的所有面板实例 + * @param areaName IPublicTypeWidgetConfigArea + */ + getAreaItems(areaName: IPublicTypeWidgetConfigArea): IPublicModelSkeletonItem[] | undefined; + /** * 获取面板实例 * @param name 面板名称 From 4a502f823c149fb10aaa178ec9a2de82476bef71 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 19 Dec 2023 01:32:47 +0000 Subject: [PATCH 392/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 3b9e4902a2..457af1fe31 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.15", + "version": "1.2.16", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From e79f68611a4779e30a9bd455dd1d8e20275823f6 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 19 Dec 2023 17:40:20 +0800 Subject: [PATCH 393/469] feat(skeleton): add onDisableWidget & onEnableWidget APIs --- docs/docs/api/skeleton.md | 35 +++++++++++++++++++++--- packages/shell/src/api/skeleton.ts | 34 ++++++++++++++--------- packages/types/src/shell/api/skeleton.ts | 20 +++++++++++--- 3 files changed, 68 insertions(+), 21 deletions(-) diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index ea5672172c..0713546e19 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -387,7 +387,7 @@ export default controlPanelWidthPlugin; * @param listener * @returns */ -onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable; +onShowPanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; ``` 相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) @@ -403,11 +403,38 @@ onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable; * @param listener * @returns */ -onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable; +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 @@ -420,7 +447,7 @@ onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable; * @param listener * @returns */ -onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; +onShowWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; ``` 相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) @@ -436,7 +463,7 @@ onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; * @param listener * @returns */ -onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; +onHideWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; ``` 相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index 07a1727dd3..c61edf95d0 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -154,16 +154,30 @@ export class Skeleton implements IPublicApiSkeleton { * @param listener * @returns */ - onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable { + onShowPanel(listener: (paneName: string, panel: IPublicModelSkeletonItem) => void): IPublicTypeDisposable { const { editor } = this[skeletonSymbol]; editor.eventBus.on(SkeletonEvents.PANEL_SHOW, (name: any, panel: any) => { - // 不泄漏 skeleton - const { skeleton, ...restPanel } = panel; - listener(name, restPanel); + listener(name, new SkeletonItem(panel)); }); return () => editor.eventBus.off(SkeletonEvents.PANEL_SHOW, listener); } + onDisableWidget(listener: (...args: any[]) => void): IPublicTypeDisposable { + const { editor } = this[skeletonSymbol]; + editor.eventBus.on(SkeletonEvents.WIDGET_DISABLE, (name: any, panel: any) => { + listener(name, new SkeletonItem(panel)); + }); + return () => editor.eventBus.off(SkeletonEvents.WIDGET_DISABLE, listener); + } + + onEnableWidget(listener: (...args: any[]) => void): IPublicTypeDisposable { + const { editor } = this[skeletonSymbol]; + editor.eventBus.on(SkeletonEvents.WIDGET_ENABLE, (name: any, panel: any) => { + listener(name, new SkeletonItem(panel)); + }); + return () => editor.eventBus.off(SkeletonEvents.WIDGET_ENABLE, listener); + } + /** * 监听 panel 隐藏事件 * @param listener @@ -172,9 +186,7 @@ export class Skeleton implements IPublicApiSkeleton { onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable { const { editor } = this[skeletonSymbol]; editor.eventBus.on(SkeletonEvents.PANEL_HIDE, (name: any, panel: any) => { - // 不泄漏 skeleton - const { skeleton, ...restPanel } = panel; - listener(name, restPanel); + listener(name, new SkeletonItem(panel)); }); return () => editor.eventBus.off(SkeletonEvents.PANEL_HIDE, listener); } @@ -187,9 +199,7 @@ export class Skeleton implements IPublicApiSkeleton { onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable { const { editor } = this[skeletonSymbol]; editor.eventBus.on(SkeletonEvents.WIDGET_SHOW, (name: any, panel: any) => { - // 不泄漏 skeleton - const { skeleton, ...rest } = panel; - listener(name, rest); + listener(name, new SkeletonItem(panel)); }); return () => editor.eventBus.off(SkeletonEvents.WIDGET_SHOW, listener); } @@ -202,9 +212,7 @@ export class Skeleton implements IPublicApiSkeleton { onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable { const { editor } = this[skeletonSymbol]; editor.eventBus.on(SkeletonEvents.WIDGET_HIDE, (name: any, panel: any) => { - // 不泄漏 skeleton - const { skeleton, ...rest } = panel; - listener(name, rest); + listener(name, new SkeletonItem(panel)); }); return () => editor.eventBus.off(SkeletonEvents.WIDGET_HIDE, listener); } diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts index 83a3f97788..1bf788e121 100644 --- a/packages/types/src/shell/api/skeleton.ts +++ b/packages/types/src/shell/api/skeleton.ts @@ -95,7 +95,7 @@ export interface IPublicApiSkeleton { * @param listener * @returns */ - onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable; + onShowPanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; /** * 监听 Panel 实例隐藏事件 @@ -103,7 +103,19 @@ export interface IPublicApiSkeleton { * @param listener * @returns */ - onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable; + onHidePanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; + + /** + * 监听 Widget 实例 Disable 事件 + * @param listener + */ + onDisableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; + + /** + * 监听 Widget 实例 Enable 事件 + * @param listener + */ + onEnableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; /** * 监听 Widget 显示事件 @@ -111,7 +123,7 @@ export interface IPublicApiSkeleton { * @param listener * @returns */ - onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; + onShowWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; /** * 监听 Widget 隐藏事件 @@ -119,7 +131,7 @@ export interface IPublicApiSkeleton { * @param listener * @returns */ - onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; + onHideWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; /** * 注册一个面板的配置转换器(transducer)。 From 733229985b1835ef273770e1b4da363d948121da Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 19 Dec 2023 09:57:55 +0000 Subject: [PATCH 394/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 457af1fe31..ab6edf5cb5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.16", + "version": "1.2.17", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 73dacadaee254dd0d6a5229f3ad869168360d47f Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 25 Dec 2023 19:44:40 +0800 Subject: [PATCH 395/469] style(skeleton): update setting pane styles --- .../src/components/settings/settings-primary-pane.tsx | 6 ++++-- packages/utils/src/create-icon.tsx | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx index a68647ed0d..747a2ea1df 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -65,8 +65,10 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, { {createIcon(settings.componentMeta?.icon, { className: 'lc-settings-navigator-icon', })} - <Title title={settings.componentMeta!.title} /> - <span> x {settings.nodes.length}</span> + <div style={{ marginLeft: '5px' }}> + <Title title={settings.componentMeta!.title} /> + <span> x {settings.nodes.length}</span> + </div> </div> ); } diff --git a/packages/utils/src/create-icon.tsx b/packages/utils/src/create-icon.tsx index 0a5d6c1ff7..621b5c7ab4 100644 --- a/packages/utils/src/create-icon.tsx +++ b/packages/utils/src/create-icon.tsx @@ -30,7 +30,10 @@ export function createIcon( return cloneElement(icon, { ...props }); } if (isReactComponent(icon)) { - return createElement(icon, { ...props }); + return createElement(icon, { + class: props?.className, + ...props, + }); } return <Icon {...icon} {...props} />; From f483970aef86c0e9591ec4f9bdf6fa9be75f5f46 Mon Sep 17 00:00:00 2001 From: eightHundreds <mingoing@outlook.com> Date: Tue, 12 Dec 2023 16:12:45 +0800 Subject: [PATCH 396/469] fix: trigger node.add event on mergeChildren --- packages/designer/src/document/node/node-children.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index bf982cbfa7..65210fe62c 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -462,6 +462,9 @@ export class NodeChildren implements INodeChildren { const node: INode = this.owner.document?.createNode(child); this.children.push(node); node.internalSetParent(this.owner); + /* istanbul ignore next */ + const editor = node.document?.designer.editor; + editor?.eventBus.emit('node.add', { node }); }); changed = true; } From f7ba053476302b5b87d01a856e1ab98076591a3a Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 26 Dec 2023 14:52:24 +0800 Subject: [PATCH 397/469] fix(outline-pane): hover invalid --- packages/plugin-outline-pane/src/views/tree.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-outline-pane/src/views/tree.tsx b/packages/plugin-outline-pane/src/views/tree.tsx index 675f70c2b3..8428ec944c 100644 --- a/packages/plugin-outline-pane/src/views/tree.tsx +++ b/packages/plugin-outline-pane/src/views/tree.tsx @@ -40,7 +40,7 @@ export default class TreeView extends PureComponent<{ return; } const node = this.getTreeNodeFromEvent(e)?.node; - detecting?.capture(node as any); + node?.id && detecting?.capture(node.id); } private onClick = (e: ReactMouseEvent) => { From 89e912ba1a3a4e33c0de72773f5fda36a09c4702 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 28 Dec 2023 05:57:44 +0000 Subject: [PATCH 398/469] chore(release): publish 1.2.4 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 98ef80f138..323f3fb412 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.3", + "version": "1.2.4", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index e961451d88..a681a03bc8 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.3", + "version": "1.2.4", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.3", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.4", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 345783c806..ba638df961 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.3", + "version": "1.2.4", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index fa5c1e13e6..e8b42920f7 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.3", + "version": "1.2.4", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-editor-core": "1.2.3", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-editor-core": "1.2.4", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index c9eef3534c..092b7c39b3 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.3", + "version": "1.2.4", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-editor-core": "1.2.3", - "@alilc/lowcode-editor-skeleton": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-editor-core": "1.2.4", + "@alilc/lowcode-editor-skeleton": "1.2.4", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.3", - "@alilc/lowcode-plugin-outline-pane": "1.2.3", - "@alilc/lowcode-shell": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", - "@alilc/lowcode-workspace": "1.2.3", + "@alilc/lowcode-plugin-designer": "1.2.4", + "@alilc/lowcode-plugin-outline-pane": "1.2.4", + "@alilc/lowcode-shell": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-workspace": "1.2.4", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 71a21484c4..bdc73a24a8 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.3", + "version": "1.2.4", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 500c0c9611..8a3c532e6a 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.3", + "version": "1.2.4", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-editor-core": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-editor-core": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 5a2ef38a45..c2b6424d68 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.3", + "version": "1.2.4", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 837aebc85e..fa66dbb084 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.3", + "version": "1.2.4", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-renderer-core": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index dc9b7b1478..511cfa46dc 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.3", + "version": "1.2.4", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-rax-renderer": "1.2.3", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-rax-renderer": "1.2.4", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 1dceb9c2e7..53764e8d93 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.3", + "version": "1.2.4", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.3" + "@alilc/lowcode-renderer-core": "1.2.4" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 8935c92eef..6c07ea42a0 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.3", + "version": "1.2.4", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-react-renderer": "1.2.3", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-react-renderer": "1.2.4", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 4774ae3689..bc55f80975 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.3", + "version": "1.2.4", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 2ebf14bbc2..efb5fc1e28 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.3", + "version": "1.2.4", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-editor-core": "1.2.3", - "@alilc/lowcode-editor-skeleton": "1.2.3", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", - "@alilc/lowcode-workspace": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-editor-core": "1.2.4", + "@alilc/lowcode-editor-skeleton": "1.2.4", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-workspace": "1.2.4", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index c0b8e203fe..82624356ea 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.3", + "version": "1.2.4", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 00efffb8d3..ac0f36502f 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.3", + "version": "1.2.4", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-types": "1.2.4", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 8c09a93b6c..d3868c3307 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.3", + "version": "1.2.4", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-editor-core": "1.2.3", - "@alilc/lowcode-editor-skeleton": "1.2.3", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-editor-core": "1.2.4", + "@alilc/lowcode-editor-skeleton": "1.2.4", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From b2abb67440e8ed36aef465d2b072292acb27c4c3 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 28 Dec 2023 06:22:34 +0000 Subject: [PATCH 399/469] chore(release): publish 1.2.5 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 323f3fb412..1170309170 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.4", + "version": "1.2.5", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index a681a03bc8..0e6e67e882 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.4", + "version": "1.2.5", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.4", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-editor-core": "1.2.5", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index ba638df961..0875584501 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.4", + "version": "1.2.5", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index e8b42920f7..648ed5be1f 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.4", + "version": "1.2.5", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-editor-core": "1.2.4", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-editor-core": "1.2.5", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 092b7c39b3..4caf32c009 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.4", + "version": "1.2.5", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-editor-core": "1.2.4", - "@alilc/lowcode-editor-skeleton": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-editor-core": "1.2.5", + "@alilc/lowcode-editor-skeleton": "1.2.5", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.4", - "@alilc/lowcode-plugin-outline-pane": "1.2.4", - "@alilc/lowcode-shell": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", - "@alilc/lowcode-workspace": "1.2.4", + "@alilc/lowcode-plugin-designer": "1.2.5", + "@alilc/lowcode-plugin-outline-pane": "1.2.5", + "@alilc/lowcode-shell": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-workspace": "1.2.5", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index bdc73a24a8..f131dc14c3 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.4", + "version": "1.2.5", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 8a3c532e6a..d764f7d9ed 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.4", + "version": "1.2.5", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-editor-core": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-editor-core": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index c2b6424d68..f864356fc8 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.4", + "version": "1.2.5", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index fa66dbb084..8173d6e4e1 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.4", + "version": "1.2.5", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-renderer-core": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 511cfa46dc..f264380ec1 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.4", + "version": "1.2.5", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-rax-renderer": "1.2.4", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-rax-renderer": "1.2.5", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 53764e8d93..2970e93410 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.4", + "version": "1.2.5", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.4" + "@alilc/lowcode-renderer-core": "1.2.5" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 6c07ea42a0..030a197082 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.4", + "version": "1.2.5", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-react-renderer": "1.2.4", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-react-renderer": "1.2.5", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index bc55f80975..fab0d3f133 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.4", + "version": "1.2.5", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index efb5fc1e28..86c4c7d11e 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.4", + "version": "1.2.5", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-editor-core": "1.2.4", - "@alilc/lowcode-editor-skeleton": "1.2.4", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", - "@alilc/lowcode-workspace": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-editor-core": "1.2.5", + "@alilc/lowcode-editor-skeleton": "1.2.5", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-workspace": "1.2.5", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 82624356ea..52a5e03ae0 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.4", + "version": "1.2.5", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index ac0f36502f..976b76341b 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.4", + "version": "1.2.5", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-types": "1.2.5", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index d3868c3307..cbc31f3797 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.4", + "version": "1.2.5", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-editor-core": "1.2.4", - "@alilc/lowcode-editor-skeleton": "1.2.4", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-editor-core": "1.2.5", + "@alilc/lowcode-editor-skeleton": "1.2.5", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 7b85a35b2419f5b2390be0243056ac815e140c0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=81=AA=E5=B0=8F=E9=99=88?= <xiaohuoni@users.noreply.github.com> Date: Tue, 2 Jan 2024 18:15:30 +0800 Subject: [PATCH 400/469] feat: zip publisher support browser (#2744) --- modules/code-generator/README.md | 14 ++++- modules/code-generator/package.json | 2 + .../code-generator/src/publisher/zip/index.ts | 18 ++++--- .../code-generator/src/publisher/zip/utils.ts | 3 +- .../tests/public/publisher/zip/zip.test.ts | 51 +++++++++++++++++-- 5 files changed, 74 insertions(+), 14 deletions(-) diff --git a/modules/code-generator/README.md b/modules/code-generator/README.md index 03ce94b54e..1d67b3aa16 100644 --- a/modules/code-generator/README.md +++ b/modules/code-generator/README.md @@ -94,16 +94,26 @@ await CodeGenerator.init(); 4. 出码 ```js -const result = await CodeGenerator.generateCode({ +const project = await CodeGenerator.generateCode({ solution: 'icejs', // 出码方案 (目前内置有 icejs 和 rax ) schema, // 编排搭建出来的 schema }); -console.log(result); // 出码结果(默认是递归结构描述的,可以传 flattenResult: true 以生成扁平结构的结果) +console.log(project); // 出码结果(默认是递归结构描述的,可以传 flattenResult: true 以生成扁平结构的结果) ``` 注:一般来说在浏览器中出码适合做即时预览功能。 +5. 下载 zip 包 + +```js +// 写入到 zip 包 +await CodeGenerator.publishers.zip().publish({ + project, // 上一步生成的 project + projectSlug: 'your-project-slug', // 项目标识 -- 对应下载 your-project-slug.zip 文件 +}); +``` + ### 5)自定义出码 前端框架灵活多变,默认内置的出码方案很难满足所有人的需求,好在此代码生成器支持非常灵活的插件机制 -- 欢迎参考 ./src/plugins/xxx 来编写您自己的出码插件,然后参考 ./src/solutions/xxx 将各种插件组合成一套适合您的业务场景的出码方案。 diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index 6ff1ecb63f..5c0d91cc08 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -80,6 +80,7 @@ "change-case": "^3.1.0", "commander": "^6.1.0", "debug": "^4.3.2", + "file-saver": "^2.0.5", "fp-ts": "^2.11.9", "fs-extra": "9.x", "glob": "^7.2.0", @@ -109,6 +110,7 @@ "devDependencies": { "@iceworks/spec": "^1.4.2", "@types/babel__traverse": "^7.11.0", + "@types/file-saver": "^2.0.7", "@types/jest": "^27.0.2", "@types/lodash": "^4.14.162", "@types/node": "^14.14.20", diff --git a/modules/code-generator/src/publisher/zip/index.ts b/modules/code-generator/src/publisher/zip/index.ts index cc2f082b27..0ac0b6f67f 100644 --- a/modules/code-generator/src/publisher/zip/index.ts +++ b/modules/code-generator/src/publisher/zip/index.ts @@ -2,9 +2,9 @@ import { ResultDir } from '@alilc/lowcode-types'; import { PublisherFactory, IPublisher, IPublisherFactoryParams, PublisherError } from '../../types'; import { getErrorMessage } from '../../utils/errors'; import { isNodeProcess, writeZipToDisk, generateProjectZip } from './utils'; +import { saveAs } from 'file-saver'; -// export type ZipBuffer = Buffer | Blob; -export type ZipBuffer = Buffer; +export type ZipBuffer = Buffer | Blob; declare type ZipPublisherResponse = string | ZipBuffer; @@ -44,10 +44,16 @@ export const createZipPublisher: PublisherFactory<ZipFactoryParams, ZipPublisher try { const zipContent = await generateProjectZip(projectToPublish); - // If not output path is provided, zip is not written to disk - const projectOutputPath = options.outputPath || outputPath; - if (projectOutputPath && isNodeProcess()) { - await writeZipToDisk(projectOutputPath, zipContent, zipName); + if (isNodeProcess()) { + // If not output path is provided on the node side, zip is not written to disk + const projectOutputPath = options.outputPath || outputPath; + if (projectOutputPath) { + await writeZipToDisk(projectOutputPath, zipContent, zipName); + } + } else { + // the browser end does not require a path + // auto download zip files + saveAs(zipContent as Blob, `${zipName}.zip`); } return { success: true, payload: zipContent }; diff --git a/modules/code-generator/src/publisher/zip/utils.ts b/modules/code-generator/src/publisher/zip/utils.ts index 10e1ad4a68..08d3a12f44 100644 --- a/modules/code-generator/src/publisher/zip/utils.ts +++ b/modules/code-generator/src/publisher/zip/utils.ts @@ -40,8 +40,7 @@ export const writeZipToDisk = ( export const generateProjectZip = async (project: ResultDir): Promise<ZipBuffer> => { let zip = new JSZip(); zip = writeFolderToZip(project, zip, true); - // const zipType = isNodeProcess() ? 'nodebuffer' : 'blob'; - const zipType = 'nodebuffer'; // 目前先只支持 node 调用 + const zipType = isNodeProcess() ? 'nodebuffer' : 'blob'; return zip.generateAsync({ type: zipType }); }; diff --git a/modules/code-generator/tests/public/publisher/zip/zip.test.ts b/modules/code-generator/tests/public/publisher/zip/zip.test.ts index ed37980d03..d51957004a 100644 --- a/modules/code-generator/tests/public/publisher/zip/zip.test.ts +++ b/modules/code-generator/tests/public/publisher/zip/zip.test.ts @@ -1,6 +1,14 @@ import CodeGen from '../../../../src'; +import fileSaver from 'file-saver'; +import * as utils from '../../../../src/publisher/zip/utils'; + +jest.mock('file-saver'); describe('public/publisher/zip/zip', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + it('should works', async () => { const zip = CodeGen.publishers.zip({ outputPath: 'demo-output', @@ -19,15 +27,15 @@ describe('public/publisher/zip/zip', () => { ], }; - expect(zip.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`); + expect(zip.getOutputPath()).toMatchInlineSnapshot('"demo-output"'); - expect(zip.getProject()).toMatchInlineSnapshot(`undefined`); + expect(zip.getProject()).toMatchInlineSnapshot('undefined'); zip.setProject(demoProject); expect(zip.getProject()).toBeTruthy(); - expect(zip.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`); + expect(zip.getOutputPath()).toMatchInlineSnapshot('"demo-output"'); expect(zip.setOutputPath('output')).toBe(undefined); - expect(zip.getOutputPath()).toMatchInlineSnapshot(`"output"`); + expect(zip.getOutputPath()).toMatchInlineSnapshot('"output"'); const publishRes = await zip.publish({ project: demoProject, @@ -41,4 +49,39 @@ describe('public/publisher/zip/zip', () => { const zip = CodeGen.publishers.zip({}); expect(zip.publish()).rejects.toBeTruthy(); }); + + it('should publish the project as a zip file in the browser', async () => { + const zipContent = 'zip content'; + const zipName = 'example-project'; + jest.spyOn(utils, 'isNodeProcess').mockReturnValue(false); + // new Zip 里面也有平台判断,所以这里 mock + jest.spyOn(utils, 'generateProjectZip').mockResolvedValue(zipContent as any); + const spy = jest.spyOn(fileSaver, 'saveAs'); + + const zip = CodeGen.publishers.zip({ + projectSlug: zipName, + }); + + const demoProject = { + name: 'demo', + dirs: [], + files: [ + { + name: 'package', + ext: 'json', + content: '{ "name": "demo", "version": "1.0.0" }', + }, + ], + }; + + zip.setProject(demoProject); + const publishRes = await zip.publish({ + project: demoProject, + }); + + expect(publishRes.success).toBeTruthy(); + expect(spy).toBeCalledWith(zipContent, `${zipName}.zip`); + spy.mockReset(); + spy.mockRestore(); + }); }); From 173978ffd4f8b13f6babcc5c14b2c450bca73eb7 Mon Sep 17 00:00:00 2001 From: wangwei <1021281778@qq.com> Date: Wed, 3 Jan 2024 15:17:40 +0800 Subject: [PATCH 401/469] chore(release): code-gen 1.1.7 --- modules/code-generator/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index 5c0d91cc08..cd114fa067 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-code-generator", - "version": "1.1.6", + "version": "1.1.7", "description": "出码引擎 for LowCode Engine", "license": "MIT", "main": "lib/index.js", From e1f3a11c4197317fd9a520ca014b78905096b46f Mon Sep 17 00:00:00 2001 From: LiuTeiTei <ltt_catchyou@163.com> Date: Thu, 4 Jan 2024 18:20:22 +0800 Subject: [PATCH 402/469] fix: trigger onFilterResultChanged when filtered --- .../src/views/filter-tree.ts | 5 +++++ .../src/views/tree-node.tsx | 16 +++++++++++--- .../src/views/tree-title.tsx | 22 +++++++++++++------ 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/packages/plugin-outline-pane/src/views/filter-tree.ts b/packages/plugin-outline-pane/src/views/filter-tree.ts index 2a07e15c6b..793aa03cc5 100644 --- a/packages/plugin-outline-pane/src/views/filter-tree.ts +++ b/packages/plugin-outline-pane/src/views/filter-tree.ts @@ -77,6 +77,11 @@ export const matchTreeNode = ( return matchTreeNode(childNode, keywords, filterOps); }).find(Boolean); + // 如果命中了子节点,需要将该节点展开 + if (matchChild && treeNode.expandable) { + treeNode.setExpanded(true); + } + treeNode.setFilterReult({ filterWorking: true, matchChild, diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx index be6e6ae2c8..11bd95d12f 100644 --- a/packages/plugin-outline-pane/src/views/tree-node.tsx +++ b/packages/plugin-outline-pane/src/views/tree-node.tsx @@ -34,7 +34,7 @@ class ModalTreeNodeView extends PureComponent<{ } componentDidMount(): void { - const rootTreeNode = this.rootTreeNode; + const { rootTreeNode } = this; rootTreeNode.onExpandableChanged(() => { this.setState({ treeChildren: rootTreeNode.children, @@ -53,7 +53,7 @@ class ModalTreeNodeView extends PureComponent<{ } render() { - const rootTreeNode = this.rootTreeNode; + const { rootTreeNode } = this; const { expanded } = rootTreeNode; const hasVisibleModalNode = !!this.modalNodesManager?.getVisibleModalNode(); @@ -98,6 +98,9 @@ export default class TreeNodeView extends PureComponent<{ conditionFlow: boolean; expandable: boolean; treeChildren: TreeNode[] | null; + filterWorking: boolean; + matchChild: boolean; + matchSelf: boolean; } = { expanded: false, selected: false, @@ -110,6 +113,9 @@ export default class TreeNodeView extends PureComponent<{ conditionFlow: false, expandable: false, treeChildren: [], + filterWorking: false, + matchChild: false, + matchSelf: false, }; eventOffCallbacks: Array<IPublicTypeDisposable | undefined> = []; @@ -154,6 +160,10 @@ export default class TreeNodeView extends PureComponent<{ treeChildren: treeNode.children, }); }); + treeNode.onFilterResultChanged(() => { + const { filterWorking: newFilterWorking, matchChild: newMatchChild, matchSelf: newMatchSelf } = treeNode.filterReult; + this.setState({ filterWorking: newFilterWorking, matchChild: newMatchChild, matchSelf: newMatchSelf }); + }); this.eventOffCallbacks.push( doc?.onDropLocationChanged(() => { this.setState({ @@ -216,7 +226,7 @@ export default class TreeNodeView extends PureComponent<{ let shouldShowModalTreeNode: boolean = this.shouldShowModalTreeNode(); // filter 处理 - const { filterWorking, matchChild, matchSelf } = treeNode.filterReult; + const { filterWorking, matchChild, matchSelf } = this.state; if (!isRootNode && filterWorking && !matchChild && !matchSelf) { // 条件过滤生效时,如果未命中本节点或子节点,则不展示该节点 // 根节点始终展示 diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index c8c0e75b09..f822bd644b 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -29,9 +29,15 @@ export default class TreeTitle extends PureComponent<{ title: string; condition?: boolean; visible?: boolean; + filterWorking: boolean; + keywords: string; + matchSelf: boolean; } = { editing: false, title: '', + filterWorking: false, + keywords: '', + matchSelf: false, }; private lastInput?: HTMLInputElement; @@ -100,6 +106,10 @@ export default class TreeTitle extends PureComponent<{ visible: !hidden, }); }); + treeNode.onFilterResultChanged(() => { + const { filterWorking: newFilterWorking, keywords: newKeywords, matchSelf: newMatchSelf } = treeNode.filterReult; + this.setState({ filterWorking: newFilterWorking, keywords: newKeywords, matchSelf: newMatchSelf }); + }); } deleteClick = () => { const { treeNode } = this.props; @@ -109,7 +119,7 @@ export default class TreeTitle extends PureComponent<{ render() { const { treeNode, isModal } = this.props; const { pluginContext } = treeNode; - const { editing } = this.state; + const { editing, filterWorking, matchSelf, keywords } = this.state; const isCNode = !treeNode.isRoot(); const { node } = treeNode; const { componentMeta } = node; @@ -125,11 +135,9 @@ export default class TreeTitle extends PureComponent<{ marginLeft: -indent, }; } - const { filterWorking, matchSelf, keywords } = treeNode.filterReult; const Extra = pluginContext.extraTitle; const { intlNode, common, config } = pluginContext; - const Tip = common.editorCabin.Tip; - const Title = common.editorCabin.Title; + const { Tip, Title } = common.editorCabin; const couldHide = availableActions.includes('hide'); const couldLock = availableActions.includes('lock'); const couldUnlock = availableActions.includes('unlock'); @@ -253,7 +261,7 @@ class RenameBtn extends PureComponent<{ }> { render() { const { intl, common } = this.props.treeNode.pluginContext; - const Tip = common.editorCabin.Tip; + const { Tip } = common.editorCabin; return ( <div className="tree-node-rename-btn" @@ -274,7 +282,7 @@ class LockBtn extends PureComponent<{ render() { const { treeNode, locked } = this.props; const { intl, common } = this.props.treeNode.pluginContext; - const Tip = common.editorCabin.Tip; + const { Tip } = common.editorCabin; return ( <div className="tree-node-lock-btn" @@ -300,7 +308,7 @@ class HideBtn extends PureComponent<{ render() { const { treeNode, hidden } = this.props; const { intl, common } = treeNode.pluginContext; - const Tip = common.editorCabin.Tip; + const { Tip } = common.editorCabin; return ( <div className="tree-node-hide-btn" From c24c3d8ae59e4ee9cf17c5816f088463aedb5a44 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 5 Jan 2024 10:33:10 +0800 Subject: [PATCH 403/469] feat: add hideComponentAction config --- docs/docs/api/configOptions.md | 6 ++++++ .../builtin-simulator/bem-tools/border-selecting.tsx | 10 +++++++--- packages/editor-core/src/config.ts | 5 +++++ packages/types/src/shell/type/engine-options.ts | 6 ++++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md index aaea28261d..5f6ade710f 100644 --- a/docs/docs/api/configOptions.md +++ b/docs/docs/api/configOptions.md @@ -216,6 +216,12 @@ config.set('enableCondition', false) 是否在只有一个 item 的时候隐藏设置 tabs +#### hideComponentAction + +`@type {boolean}` `@default {false}` + +隐藏设计器辅助层 + #### thisRequiredInJSE `@type {boolean}` `@default {true}` diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx index 4f452727d2..143c67e020 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx @@ -9,7 +9,7 @@ import { ComponentType, } from 'react'; import classNames from 'classnames'; -import { observer, computed, Tip } from '@alilc/lowcode-editor-core'; +import { observer, computed, Tip, engineConfig } from '@alilc/lowcode-editor-core'; import { createIcon, isReactComponent, isActionContentObject } from '@alilc/lowcode-utils'; import { IPublicTypeActionContentObject } from '@alilc/lowcode-types'; import { BuiltinSimulatorHost } from '../host'; @@ -47,14 +47,18 @@ export class BorderSelectingInstance extends Component<{ }); const { hideSelectTools } = observed.node.componentMeta.advanced; + const hideComponentAction = engineConfig.get('hideComponentAction'); if (hideSelectTools) { return null; } return ( - <div className={className} style={style}> - {!dragging && <Toolbar observed={observed} />} + <div + className={className} + style={style} + > + {(!dragging && !hideComponentAction) ? <Toolbar observed={observed} /> : null} </div> ); } diff --git a/packages/editor-core/src/config.ts b/packages/editor-core/src/config.ts index 85e6097801..1c73347b74 100644 --- a/packages/editor-core/src/config.ts +++ b/packages/editor-core/src/config.ts @@ -159,6 +159,11 @@ const VALID_ENGINE_OPTIONS = { type: 'function', description: '应用级设计模式下,窗口为空时展示的占位组件', }, + hideComponentAction: { + type: 'boolean', + description: '是否隐藏设计器辅助层', + default: false, + }, }; const getStrictModeValue = (engineOptions: IPublicTypeEngineOptions, defaultValue: boolean): boolean => { diff --git a/packages/types/src/shell/type/engine-options.ts b/packages/types/src/shell/type/engine-options.ts index f177166530..b570d1990a 100644 --- a/packages/types/src/shell/type/engine-options.ts +++ b/packages/types/src/shell/type/engine-options.ts @@ -177,6 +177,12 @@ export interface IPublicTypeEngineOptions { * 应用级设计模式下,自动打开第一个窗口 */ enableAutoOpenFirstWindow?: boolean; + + /** + * @default false + * 隐藏设计器辅助层 + */ + hideComponentAction?: boolean; } /** From d81eb8d75da665ab9603339bfe78759fe6e2f602 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 5 Jan 2024 10:37:15 +0800 Subject: [PATCH 404/469] style(outline): update selected item style --- packages/plugin-outline-pane/src/views/style.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index 8521883b49..8a38ba749b 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -356,7 +356,7 @@ // 选中节点处理 &.selected { & > .tree-node-title { - background: var(--color-block-background-shallow); + background: var(--color-block-background-light); } & > .tree-node-branches::before { From be0456fb398c731c4492fbca83aebc8ed9e9f3f3 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 5 Jan 2024 11:32:28 +0800 Subject: [PATCH 405/469] feat: add commonUI API --- docs/docs/api/commonUI.md | 118 ++++++++++++++++++ packages/designer/src/component-meta.ts | 8 +- .../designer/src/plugin/plugin-context.ts | 3 + packages/designer/src/plugin/plugin-types.ts | 2 + .../editor-core/src/widgets/title/index.tsx | 10 +- packages/engine/src/engine-core.ts | 5 + packages/shell/src/api/commonUI.ts | 43 +++++++ packages/shell/src/api/index.ts | 3 +- packages/shell/src/index.ts | 2 + packages/types/src/shell/api/commonUI.ts | 48 +++++++ packages/types/src/shell/api/index.ts | 1 + .../types/src/shell/model/plugin-context.ts | 7 ++ packages/types/src/shell/type/tip-config.ts | 12 ++ packages/types/src/shell/type/title-config.ts | 27 +++- .../workspace/src/context/base-context.ts | 4 + 15 files changed, 281 insertions(+), 12 deletions(-) create mode 100644 docs/docs/api/commonUI.md create mode 100644 packages/shell/src/api/commonUI.ts create mode 100644 packages/types/src/shell/api/commonUI.ts diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md new file mode 100644 index 0000000000..9d1f706520 --- /dev/null +++ b/docs/docs/api/commonUI.md @@ -0,0 +1,118 @@ +--- +title: commonUI - UI 组件库 +sidebar_position: 11 +--- + +## 简介 +CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开发的插件,可以保证在不同项目和主题切换中能够保持一致性和兼容性。 + +## 组件列表 + +### Tip + +提示组件 + +| 参数 | 说明 | 类型 | 默认值 | +|-----------|--------------|---------------------------------------|--------| +| className | className | string (optional) | | +| children | tip 的内容 | IPublicTypeI18nData \| ReactNode | | +| direction | tip 的方向 | 'top' \| 'bottom' \| 'left' \| 'right' | | + + +### Title + +标题组件 + +| 参数 | 说明 | 类型 | 默认值 | +|-----------|------------|-----------------------------|--------| +| title | 标题内容 | IPublicTypeTitleContent | | +| className | className | string (optional) | | +| onClick | 点击事件 | () => void (optional) | | + +### 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给我们 \ No newline at end of file diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 00c4956217..1ee1154f18 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -48,13 +48,17 @@ export function buildFilter(rule?: string | string[] | RegExp | IPublicTypeNesti return rule; } if (isRegExp(rule)) { - return (testNode: Node | IPublicTypeNodeSchema) => rule.test(testNode.componentName); + return (testNode: Node | IPublicTypeNodeSchema) => { + return rule.test(testNode.componentName); + }; } const list = ensureAList(rule); if (!list) { return null; } - return (testNode: Node | IPublicTypeNodeSchema) => list.includes(testNode.componentName); + return (testNode: Node | IPublicTypeNodeSchema) => { + return list.includes(testNode.componentName); + }; } export interface IComponentMeta extends IPublicModelComponentMeta<INode> { diff --git a/packages/designer/src/plugin/plugin-context.ts b/packages/designer/src/plugin/plugin-context.ts index 94e296fd1c..7f26a2b4f3 100644 --- a/packages/designer/src/plugin/plugin-context.ts +++ b/packages/designer/src/plugin/plugin-context.ts @@ -19,6 +19,7 @@ import { IPublicApiWorkspace, IPublicEnumPluginRegisterLevel, IPublicModelWindow, + IPublicApiCommonUI, } from '@alilc/lowcode-types'; import { IPluginContextOptions, @@ -45,6 +46,8 @@ export default class PluginContext implements workspace: IPublicApiWorkspace; registerLevel: IPublicEnumPluginRegisterLevel; editorWindow: IPublicModelWindow; + commonUI: IPublicApiCommonUI; + isPluginRegisteredInWorkspace: false; constructor( options: IPluginContextOptions, diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index 6091170f02..d648067a36 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -18,6 +18,7 @@ import { IPublicTypePluginRegisterOptions, IPublicModelWindow, IPublicEnumPluginRegisterLevel, + IPublicApiCommonUI, } from '@alilc/lowcode-types'; import PluginContext from './plugin-context'; @@ -61,6 +62,7 @@ export interface ILowCodePluginContextPrivate { set editorWindow(window: IPublicModelWindow); set registerLevel(level: IPublicEnumPluginRegisterLevel); set isPluginRegisteredInWorkspace(flag: boolean); + set commonUI(commonUI: IPublicApiCommonUI); } export interface ILowCodePluginContextApiAssembler { assembleApis( diff --git a/packages/editor-core/src/widgets/title/index.tsx b/packages/editor-core/src/widgets/title/index.tsx index 88a15ab29b..7df2676f92 100644 --- a/packages/editor-core/src/widgets/title/index.tsx +++ b/packages/editor-core/src/widgets/title/index.tsx @@ -1,7 +1,7 @@ import { Component, isValidElement, ReactNode } from 'react'; import classNames from 'classnames'; import { createIcon, isI18nData, isTitleConfig } from '@alilc/lowcode-utils'; -import { IPublicTypeTitleContent, IPublicTypeI18nData, IPublicTypeTitleConfig } from '@alilc/lowcode-types'; +import { IPublicTypeI18nData, IPublicTypeTitleConfig, IPublicTypeTitleProps } from '@alilc/lowcode-types'; import { intl } from '../../intl'; import { Tip } from '../tip'; import './title.less'; @@ -36,13 +36,7 @@ import './title.less'; return fragments; } -export class Title extends Component<{ - title: IPublicTypeTitleContent; - className?: string; - onClick?: () => void; - match?: boolean; - keywords?: string; -}> { +export class Title extends Component<IPublicTypeTitleProps> { constructor(props: any) { super(props); this.handleClick = this.handleClick.bind(this); diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 3ac4c32a75..9f29046fbe 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -51,6 +51,7 @@ import { Canvas, Workspace, Config, + CommonUI, } from '@alilc/lowcode-shell'; import { isPlainObject } from '@alilc/lowcode-utils'; import './modules/live-editing'; @@ -111,10 +112,12 @@ const innerSetters = new InnerSetters(); const setters = new Setters(innerSetters); const material = new Material(editor); +const commonUI = new CommonUI(); editor.set('project', project); editor.set('setters' as any, setters); editor.set('material', material); editor.set('innerHotkey', innerHotkey); +editor.set('commonUI' as any, commonUI); const config = new Config(engineConfig); const event = new Event(commonEvent, { prefix: 'common' }); const logger = new Logger({ level: 'warn', bizName: 'common' }); @@ -138,6 +141,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.plugins = plugins; context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.workspace = workspace; + context.commonUI = commonUI; context.registerLevel = IPublicEnumPluginRegisterLevel.Default; context.isPluginRegisteredInWorkspace = false; }, @@ -161,6 +165,7 @@ export { common, workspace, canvas, + commonUI, }; // declare this is open-source version export const isOpenSource = true; diff --git a/packages/shell/src/api/commonUI.ts b/packages/shell/src/api/commonUI.ts new file mode 100644 index 0000000000..718b409707 --- /dev/null +++ b/packages/shell/src/api/commonUI.ts @@ -0,0 +1,43 @@ +import { IPublicApiCommonUI } from '@alilc/lowcode-types'; +import { + Tip as InnerTip, + Title as InnerTitle, + } from '@alilc/lowcode-editor-core'; +import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; + +export class CommonUI implements IPublicApiCommonUI { + Balloon = Balloon; + Breadcrumb = Breadcrumb; + Button = Button; + Card = Card; + Checkbox = Checkbox; + DatePicker = DatePicker; + Dialog = Dialog; + Dropdown = Dropdown; + Form = Form; + Icon = Icon; + Input = Input; + Loading = Loading; + Message = Message; + Overlay = Overlay; + Pagination = Pagination; + Radio = Radio; + Search = Search; + Select = Select; + SplitButton = SplitButton; + Step = Step; + Switch = Switch; + Tab = Tab; + Table = Table; + Tree = Tree; + TreeSelect = TreeSelect; + Upload = Upload; + Divider = Divider; + + get Tip() { + return InnerTip; + } + get Title() { + return InnerTitle; + } +} diff --git a/packages/shell/src/api/index.ts b/packages/shell/src/api/index.ts index 4114926e19..3726020de0 100644 --- a/packages/shell/src/api/index.ts +++ b/packages/shell/src/api/index.ts @@ -10,4 +10,5 @@ export * from './simulator-host'; export * from './skeleton'; export * from './canvas'; export * from './workspace'; -export * from './config'; \ No newline at end of file +export * from './config'; +export * from './commonUI'; \ No newline at end of file diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index 6f79c78bcd..ce09ccaaa7 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -28,6 +28,7 @@ import { Workspace, SimulatorHost, Config, + CommonUI, } from './api'; export * from './symbols'; @@ -68,4 +69,5 @@ export { Config, SettingField, SkeletonItem, + CommonUI, }; diff --git a/packages/types/src/shell/api/commonUI.ts b/packages/types/src/shell/api/commonUI.ts new file mode 100644 index 0000000000..3d7bb57bf3 --- /dev/null +++ b/packages/types/src/shell/api/commonUI.ts @@ -0,0 +1,48 @@ +import { IPublicTypeTitleContent } from '../type'; +import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; + +export interface IPublicApiCommonUI { + Balloon: typeof Balloon; + Breadcrumb: typeof Breadcrumb; + Button: typeof Button; + Card: typeof Card; + Checkbox: typeof Checkbox; + DatePicker: typeof DatePicker; + Dialog: typeof Dialog; + Dropdown: typeof Dropdown; + Form: typeof Form; + Icon: typeof Icon; + Input: typeof Input; + Loading: typeof Loading; + Message: typeof Message; + Overlay: typeof Overlay; + Pagination: typeof Pagination; + Radio: typeof Radio; + Search: typeof Search; + Select: typeof Select; + SplitButton: typeof SplitButton; + Step: typeof Step; + Switch: typeof Switch; + Tab: typeof Tab; + Table: typeof Table; + Tree: typeof Tree; + TreeSelect: typeof TreeSelect; + Upload: typeof Upload; + Divider: typeof Divider; + + /** + * Title 组件 + * @experimental unstable API, pay extra caution when trying to use this + */ + get Tip(): React.ComponentClass<{}>; + + /** + * Tip 组件 + * @experimental unstable API, pay extra caution when trying to use this + */ + get Title(): React.ComponentClass<{ + title: IPublicTypeTitleContent | undefined; + match?: boolean; + keywords?: string | null; + }>; +} \ No newline at end of file diff --git a/packages/types/src/shell/api/index.ts b/packages/types/src/shell/api/index.ts index 3d7d765598..79f1b0dc7c 100644 --- a/packages/types/src/shell/api/index.ts +++ b/packages/types/src/shell/api/index.ts @@ -10,3 +10,4 @@ export * from './plugins'; export * from './logger'; export * from './canvas'; export * from './workspace'; +export * from './commonUI'; diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts index 35e7e38af3..45568424de 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -11,6 +11,7 @@ import { IPluginPreferenceMananger, IPublicApiPlugins, IPublicApiWorkspace, + IPublicApiCommonUI, } from '../api'; import { IPublicEnumPluginRegisterLevel } from '../enum'; import { IPublicModelEngineConfig, IPublicModelWindow } from './'; @@ -102,6 +103,12 @@ export interface IPublicModelPluginContext { */ get workspace(): IPublicApiWorkspace; + /** + * commonUI API + * @tutorial https://lowcode-engine.cn/site/docs/api/commonUI + */ + get commonUI(): IPublicApiCommonUI; + /** * 插件注册层级 * @since v1.1.7 diff --git a/packages/types/src/shell/type/tip-config.ts b/packages/types/src/shell/type/tip-config.ts index fa82ab96f1..f8b271c909 100644 --- a/packages/types/src/shell/type/tip-config.ts +++ b/packages/types/src/shell/type/tip-config.ts @@ -2,8 +2,20 @@ import { IPublicTypeI18nData } from '..'; import { ReactNode } from 'react'; export interface IPublicTypeTipConfig { + + /** + * className + */ className?: string; + + /** + * tip 的内容 + */ children?: IPublicTypeI18nData | ReactNode; theme?: string; + + /** + * tip 的方向 + */ direction?: 'top' | 'bottom' | 'left' | 'right'; } diff --git a/packages/types/src/shell/type/title-config.ts b/packages/types/src/shell/type/title-config.ts index 571502bc5e..f8de287599 100644 --- a/packages/types/src/shell/type/title-config.ts +++ b/packages/types/src/shell/type/title-config.ts @@ -1,26 +1,51 @@ import { ReactNode } from 'react'; -import { IPublicTypeI18nData, IPublicTypeIconType, TipContent } from './'; +import { IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeTitleContent, TipContent } from './'; + +export interface IPublicTypeTitleProps { + + /** + * 标题内容 + */ + title: IPublicTypeTitleContent; + + /** + * className + */ + className?: string; + + /** + * 点击事件 + */ + onClick?: () => void; + match?: boolean; + keywords?: string; +} /** * 描述 props 的 setter title */ export interface IPublicTypeTitleConfig { + /** * 文字描述 */ label?: IPublicTypeI18nData | ReactNode; + /** * hover 后的展现内容 */ tip?: TipContent; + /** * 文档链接,暂未实现 */ docUrl?: string; + /** * 图标 */ icon?: IPublicTypeIconType; + /** * CSS 类 */ diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index 78f32079ff..e090d1e374 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -32,6 +32,7 @@ import { Workspace, Window, Canvas, + CommonUI, } from '@alilc/lowcode-shell'; import { IPluginPreferenceMananger, @@ -127,11 +128,13 @@ export class BasicContext implements IBasicContext { const logger = getLogger({ level: 'warn', bizName: 'common' }); const skeleton = new Skeleton(innerSkeleton, 'any', true); const canvas = new Canvas(editor, true); + const commonUI = new CommonUI(); editor.set('setters', setters); editor.set('project', project); editor.set('material', material); editor.set('hotkey', hotkey); editor.set('innerHotkey', innerHotkey); + editor.set('commonUI' as any, commonUI); this.innerSetters = innerSetters; this.innerSkeleton = innerSkeleton; this.skeleton = skeleton; @@ -166,6 +169,7 @@ export class BasicContext implements IBasicContext { context.plugins = plugins; context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.canvas = canvas; + context.commonUI = commonUI; if (editorWindow) { context.editorWindow = new Window(editorWindow); } From e8aebb9aa35605c33aa69debe13a94e337507441 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 5 Jan 2024 03:44:36 +0000 Subject: [PATCH 406/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index ab6edf5cb5..4d6ef0a770 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.17", + "version": "1.2.18", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From ba53d6c69072b5d6225bd93b94eb596cd4e85d1e Mon Sep 17 00:00:00 2001 From: Arun <arun@arun.blog> Date: Thu, 4 Jan 2024 19:46:30 -0800 Subject: [PATCH 407/469] ci: Use GITHUB_OUTPUT envvar instead of set-output command --- .github/workflows/publish docs.yml | 2 +- .github/workflows/publish engine beta.yml | 2 +- .github/workflows/publish engine.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index e85d08f2a9..139b70239f 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -33,7 +33,7 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version id: get_version - run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" + run: echo "version=$(node -p "require('./docs/package.json').version")" >> $GITHUB_OUTPUT comment-pr: needs: publish-docs diff --git a/.github/workflows/publish engine beta.yml b/.github/workflows/publish engine beta.yml index 32c5b4c15b..ed4c374756 100644 --- a/.github/workflows/publish engine beta.yml +++ b/.github/workflows/publish engine beta.yml @@ -27,4 +27,4 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version id: get_version - run: echo "::set-output name=version::$(node -p "require('./package.json').version")" + run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index 6825c66fca..ad4c3963b2 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -26,4 +26,4 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version id: get_version - run: echo "::set-output name=version::$(node -p "require('./package.json').version")" + run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT From 31a031ce4e4cc22c377aa9d1ce961c5df4cad58b Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 5 Jan 2024 15:53:58 +0800 Subject: [PATCH 408/469] feat: removed Rax packages, discontinuing support for Rax --- docs/docs/guide/appendix/npms.md | 2 - docs/docs/guide/appendix/repos.md | 16 +- docs/docs/guide/design/renderer.md | 1 - docs/docs/guide/expand/runtime/renderer.md | 1 - docs/docs/participate/index.md | 10 +- docs/docs/specs/lowcode-spec.md | 1 - package.json | 2 +- .../designer/src/builtin-simulator/host.ts | 37 +- .../src/designer/setting/setting-top-entry.ts | 15 +- packages/editor-core/src/config.ts | 2 +- packages/engine/README-zh_CN.md | 2 +- packages/engine/README.md | 2 +- packages/ignitor/build.json | 3 +- packages/rax-renderer/README.md | 49 -- packages/rax-renderer/build.json | 11 - packages/rax-renderer/demo/index.jsx | 35 - packages/rax-renderer/demo/miniapp/app.js | 1 - packages/rax-renderer/demo/miniapp/app.json | 6 - .../demo/miniapp/pages/index.acss | 0 .../demo/miniapp/pages/index.axml | 1 - .../rax-renderer/demo/miniapp/pages/index.js | 4 - .../demo/miniapp/pages/index.json | 6 - .../demo/wechat-miniprogram/app.js | 1 - .../demo/wechat-miniprogram/app.json | 6 - .../demo/wechat-miniprogram/pages/index.js | 4 - .../demo/wechat-miniprogram/pages/index.json | 6 - .../demo/wechat-miniprogram/pages/index.wxml | 1 - .../demo/wechat-miniprogram/pages/index.wxss | 0 packages/rax-renderer/package.json | 54 -- packages/rax-renderer/src/hoc/compFactory.tsx | 82 --- packages/rax-renderer/src/index.ts | 52 -- packages/rax-renderer/src/renderer/block.tsx | 25 - .../rax-renderer/src/renderer/component.tsx | 37 - packages/rax-renderer/src/renderer/page.tsx | 38 - packages/rax-renderer/tsconfig.json | 26 - packages/rax-simulator-renderer/.babelrc | 9 - .../rax-simulator-renderer/babel.config.js | 1 - packages/rax-simulator-renderer/build.json | 3 - .../rax-simulator-renderer/build.plugin.js | 5 - .../rax-simulator-renderer/build.umd.json | 38 - packages/rax-simulator-renderer/package.json | 55 -- .../UnusualComponent/index.less | 0 .../UnusualComponent/index.tsx | 34 - .../src/builtin-components/leaf.tsx | 251 ------- .../src/builtin-components/renderUtils.ts | 83 --- .../src/builtin-components/slot.tsx | 54 -- packages/rax-simulator-renderer/src/host.ts | 4 - .../rax-simulator-renderer/src/image.d.ts | 2 - packages/rax-simulator-renderer/src/index.ts | 7 - .../src/rax-use-router.js | 288 -------- .../src/renderer-view.tsx | 275 ------- .../rax-simulator-renderer/src/renderer.less | 125 ---- .../rax-simulator-renderer/src/renderer.ts | 690 ------------------ .../src/utils/create-defer.ts | 17 - .../src/utils/find-dom-nodes.ts | 18 - .../src/utils/get-client-rects.ts | 13 - .../src/utils/get-closest-node-instance.ts | 0 .../src/utils/get-device-view.ts | 23 - .../src/utils/is-dom-node.ts | 4 - .../src/utils/loader.ts | 114 --- .../src/utils/script.ts | 54 -- .../rax-simulator-renderer/src/utils/style.ts | 75 -- .../rax-simulator-renderer/src/utils/url.ts | 74 -- packages/renderer-core/src/adapter/index.ts | 15 +- .../tests/adapter/adapter.test.ts | 7 +- .../types/src/shell/type/engine-options.ts | 2 +- scripts/build.sh | 6 - scripts/sync.sh | 2 - 68 files changed, 36 insertions(+), 2851 deletions(-) delete mode 100644 packages/rax-renderer/README.md delete mode 100644 packages/rax-renderer/build.json delete mode 100644 packages/rax-renderer/demo/index.jsx delete mode 100644 packages/rax-renderer/demo/miniapp/app.js delete mode 100644 packages/rax-renderer/demo/miniapp/app.json delete mode 100644 packages/rax-renderer/demo/miniapp/pages/index.acss delete mode 100644 packages/rax-renderer/demo/miniapp/pages/index.axml delete mode 100644 packages/rax-renderer/demo/miniapp/pages/index.js delete mode 100644 packages/rax-renderer/demo/miniapp/pages/index.json delete mode 100644 packages/rax-renderer/demo/wechat-miniprogram/app.js delete mode 100644 packages/rax-renderer/demo/wechat-miniprogram/app.json delete mode 100644 packages/rax-renderer/demo/wechat-miniprogram/pages/index.js delete mode 100644 packages/rax-renderer/demo/wechat-miniprogram/pages/index.json delete mode 100644 packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxml delete mode 100644 packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxss delete mode 100644 packages/rax-renderer/package.json delete mode 100644 packages/rax-renderer/src/hoc/compFactory.tsx delete mode 100644 packages/rax-renderer/src/index.ts delete mode 100644 packages/rax-renderer/src/renderer/block.tsx delete mode 100644 packages/rax-renderer/src/renderer/component.tsx delete mode 100644 packages/rax-renderer/src/renderer/page.tsx delete mode 100644 packages/rax-renderer/tsconfig.json delete mode 100644 packages/rax-simulator-renderer/.babelrc delete mode 100644 packages/rax-simulator-renderer/babel.config.js delete mode 100644 packages/rax-simulator-renderer/build.json delete mode 100644 packages/rax-simulator-renderer/build.plugin.js delete mode 100644 packages/rax-simulator-renderer/build.umd.json delete mode 100644 packages/rax-simulator-renderer/package.json delete mode 100644 packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.less delete mode 100644 packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.tsx delete mode 100644 packages/rax-simulator-renderer/src/builtin-components/leaf.tsx delete mode 100644 packages/rax-simulator-renderer/src/builtin-components/renderUtils.ts delete mode 100644 packages/rax-simulator-renderer/src/builtin-components/slot.tsx delete mode 100644 packages/rax-simulator-renderer/src/host.ts delete mode 100644 packages/rax-simulator-renderer/src/image.d.ts delete mode 100644 packages/rax-simulator-renderer/src/index.ts delete mode 100644 packages/rax-simulator-renderer/src/rax-use-router.js delete mode 100644 packages/rax-simulator-renderer/src/renderer-view.tsx delete mode 100644 packages/rax-simulator-renderer/src/renderer.less delete mode 100644 packages/rax-simulator-renderer/src/renderer.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/create-defer.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/find-dom-nodes.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/get-client-rects.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/get-closest-node-instance.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/get-device-view.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/is-dom-node.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/loader.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/script.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/style.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/url.ts diff --git a/docs/docs/guide/appendix/npms.md b/docs/docs/guide/appendix/npms.md index 93980f32ce..b0292c2739 100644 --- a/docs/docs/guide/appendix/npms.md +++ b/docs/docs/guide/appendix/npms.md @@ -12,8 +12,6 @@ sidebar_position: 3 | @alilc/lowcode-engine | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/engine | | @alilc/lowcode-plugin-designer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/plugin-designer | | @alilc/lowcode-plugin-outline-pane | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/plugin-outline-pane | -| @alilc/lowcode-rax-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/rax-renderer | -| @alilc/lowcode-rax-simulator-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/rax-simulator-renderer | | @alilc/lowcode-react-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/react-renderer | | @alilc/lowcode-react-simulator-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/react-simulator-renderer | | @alilc/lowcode-renderer-core | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/renderer-core | diff --git a/docs/docs/guide/appendix/repos.md b/docs/docs/guide/appendix/repos.md index 4fbfdc12cb..87852258d2 100644 --- a/docs/docs/guide/appendix/repos.md +++ b/docs/docs/guide/appendix/repos.md @@ -15,15 +15,13 @@ sidebar_position: 2 5. ignitor 6. plugin-designer 7. plugin-outline-pane -8. rax-renderer -9. rax-simulator-renderer -10. react-renderer -11. react-simulator-renderer -12. renderer-core -13. types -14. utils -15. material-parser -16. code-generator +8. react-renderer +9. react-simulator-renderer +10. renderer-core +11. types +12. utils +13. material-parser +14. code-generator ## 2. 引擎官方扩展包 包含了常用的设置器(setter)、跟 setter 绑定的插件等 diff --git a/docs/docs/guide/design/renderer.md b/docs/docs/guide/design/renderer.md index 4c3021b54e..4a8c43f329 100644 --- a/docs/docs/guide/design/renderer.md +++ b/docs/docs/guide/design/renderer.md @@ -11,7 +11,6 @@ sidebar_position: 4 ## npm 包与仓库信息 - React 框架渲染 npm 包:@alilc/lowcode-react-renderer -- Rax 框架渲染 npm 包:@alilc/lowcode-rax-renderer - 仓库:[https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) 下的 - packages/renderer-core - packages/react-renderer diff --git a/docs/docs/guide/expand/runtime/renderer.md b/docs/docs/guide/expand/runtime/renderer.md index 71eb755980..4e6d914bbf 100644 --- a/docs/docs/guide/expand/runtime/renderer.md +++ b/docs/docs/guide/expand/runtime/renderer.md @@ -40,7 +40,6 @@ ReactDOM.render(( ), document.getElementById('root')); ``` -- rax-renderer:npm 包替换为 @alilc/lowcode-rax-renderer #### ### 项目使用示例 > [设计器 demo](https://lowcode-engine.cn/demo/demo-general/index.html) diff --git a/docs/docs/participate/index.md b/docs/docs/participate/index.md index 4540fa640d..e09f2ddad2 100644 --- a/docs/docs/participate/index.md +++ b/docs/docs/participate/index.md @@ -47,15 +47,7 @@ npm install && npm run setup [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", "http://localhost:5555/css/ReactSimulatorRenderer.css" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/RaxSimulatorRenderer.js" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/RaxSimulatorRenderer.css" - ], + ] ] } ``` diff --git a/docs/docs/specs/lowcode-spec.md b/docs/docs/specs/lowcode-spec.md index 59ff85586c..c277214106 100644 --- a/docs/docs/specs/lowcode-spec.md +++ b/docs/docs/specs/lowcode-spec.md @@ -499,7 +499,6 @@ try { - 说明:组件即将从 DOM 中移除 - componentDidCatch(error, info) - 说明:组件捕获到异常 -- Rax:目前没有使用生命周期,使用 hooks 替代生命周期; 该对象由一系列 key-value 组成,key 为生命周期方法名,value 为 JSFunction 的描述,详见下方示例: diff --git a/package.json b/package.json index caabbeeb13..047b287b98 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "yarn": "^1.22.17", "rimraf": "^3.0.2", "@types/react-router": "5.1.18", - "@alilc/build-plugin-lce": "^0.0.3", + "@alilc/build-plugin-lce": "^0.0.4", "babel-jest": "^26.5.2", "@alilc/lowcode-test-mate": "^1.0.1" }, diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index eb855e4498..6efe6a68b5 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -39,6 +39,7 @@ import { isDragAnyObject, isDragNodeObject, isLocationData, + Logger, } from '@alilc/lowcode-utils'; import { isShaken, @@ -72,6 +73,8 @@ import { IScroller } from '../designer/scroller'; import { isElementNode, isDOMNodeVisible } from '../utils/misc'; import { debounce } from 'lodash'; +const logger = new Logger({ level: 'warn', bizName: 'designer' }); + export type LibraryItem = IPublicTypePackage & { package: string; library: string; @@ -122,21 +125,6 @@ const defaultSimulatorUrl = (() => { return urls; })(); -const defaultRaxSimulatorUrl = (() => { - const publicPath = getPublicPath(); - let urls; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_, prefix = '', dev] = /^(.+?)(\/js)?\/?$/.exec(publicPath) || []; - if (dev) { - urls = [`${prefix}/css/rax-simulator-renderer.css`, `${prefix}/js/rax-simulator-renderer.js`]; - } else if (process.env.NODE_ENV === 'production') { - urls = [`${prefix}/rax-simulator-renderer.css`, `${prefix}/rax-simulator-renderer.js`]; - } else { - urls = [`${prefix}/rax-simulator-renderer.css`, `${prefix}/rax-simulator-renderer.js`]; - } - return urls; -})(); - const defaultEnvironment = [ // https://g.alicdn.com/mylib/??react/16.11.0/umd/react.production.min.js,react-dom/16.8.6/umd/react-dom.production.min.js,prop-types/15.7.2/prop-types.min.js assetItem( @@ -151,17 +139,6 @@ const defaultEnvironment = [ ), ]; -const defaultRaxEnvironment = [ - assetItem( - AssetType.JSText, - 'window.Rax=parent.Rax;window.React=parent.React;window.ReactDOM=parent.ReactDOM;window.VisualEngineUtils=parent.VisualEngineUtils;window.VisualEngine=parent.VisualEngine', - ), - assetItem( - AssetType.JSText, - 'window.PropTypes=parent.PropTypes;React.PropTypes=parent.PropTypes; window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;', - ), -]; - export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProps> { readonly isSimulator = true; @@ -467,11 +444,15 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp const libraryAsset: AssetList = this.buildLibrary(); + if (this.renderEnv === 'rax') { + logger.error('After LowcodeEngine v1.3.0, Rax is no longer supported.'); + } + const vendors = [ // required & use once assetBundle( this.get('environment') || - (this.renderEnv === 'rax' ? defaultRaxEnvironment : defaultEnvironment), + defaultEnvironment, AssetLevel.Environment, ), // required & use once @@ -484,7 +465,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp // required & use once assetBundle( this.get('simulatorUrl') || - (this.renderEnv === 'rax' ? defaultRaxSimulatorUrl : defaultSimulatorUrl), + defaultSimulatorUrl, AssetLevel.Runtime, ), ]; diff --git a/packages/designer/src/designer/setting/setting-top-entry.ts b/packages/designer/src/designer/setting/setting-top-entry.ts index f89ff8a62b..85be74b7f6 100644 --- a/packages/designer/src/designer/setting/setting-top-entry.ts +++ b/packages/designer/src/designer/setting/setting-top-entry.ts @@ -1,4 +1,4 @@ -import { IPublicTypeCustomView, IPublicModelEditor, IPublicModelSettingTopEntry } from '@alilc/lowcode-types'; +import { IPublicTypeCustomView, IPublicModelEditor, IPublicModelSettingTopEntry, IPublicApiSetters } from '@alilc/lowcode-types'; import { isCustomView } from '@alilc/lowcode-utils'; import { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { ISettingEntry } from './setting-entry-type'; @@ -6,7 +6,6 @@ import { ISettingField, SettingField } from './setting-field'; import { INode } from '../../document'; import type { IComponentMeta } from '../../component-meta'; import { IDesigner } from '../designer'; -import { Setters } from '@alilc/lowcode-shell'; function generateSessionId(nodes: INode[]) { return nodes @@ -19,18 +18,18 @@ export interface ISettingTopEntry extends ISettingEntry, IPublicModelSettingTopE INode, ISettingField > { - purge(): void; - - items: Array<ISettingField | IPublicTypeCustomView>; - readonly top: ISettingTopEntry; readonly parent: ISettingTopEntry; readonly path: never[]; + items: Array<ISettingField | IPublicTypeCustomView>; + componentMeta: IComponentMeta | null; + purge(): void; + getExtraPropValue(propName: string): void; setExtraPropValue(propName: string, value: any): void; @@ -92,7 +91,7 @@ export class SettingTopEntry implements ISettingTopEntry { readonly designer: IDesigner | undefined; - readonly setters: Setters; + readonly setters: IPublicApiSetters; disposeFunctions: any[] = []; @@ -103,7 +102,7 @@ export class SettingTopEntry implements ISettingTopEntry { this.id = generateSessionId(nodes); this.first = nodes[0]; this.designer = this.first.document?.designer; - this.setters = editor.get('setters') as Setters; + this.setters = editor.get('setters') as IPublicApiSetters; // setups this.setupComponentMeta(); diff --git a/packages/editor-core/src/config.ts b/packages/editor-core/src/config.ts index 1c73347b74..a5da74742d 100644 --- a/packages/editor-core/src/config.ts +++ b/packages/editor-core/src/config.ts @@ -44,7 +44,7 @@ const VALID_ENGINE_OPTIONS = { }, renderEnv: { type: 'string', - enum: ['react', 'rax', 'any string value'], + enum: ['react', 'any string value'], default: 'react', description: '渲染器类型', }, diff --git a/packages/engine/README-zh_CN.md b/packages/engine/README-zh_CN.md index c99e98cf6c..5442aa58bd 100644 --- a/packages/engine/README-zh_CN.md +++ b/packages/engine/README-zh_CN.md @@ -126,7 +126,7 @@ https://cdn.jsdelivr.net/npm/@alilc/lowcode-react-simulator-renderer@1.0.18/dist ``` #### 方式 5:使用自有 cdn -将源码中 packages/engine/dist 和 packages/(react|rax)-simulator-renderer/dist 下的文件传至你的 cdn 提供商 +将源码中 packages/engine/dist 和 packages/react-simulator-renderer/dist 下的文件传至你的 cdn 提供商 ## 🔗 相关链接 diff --git a/packages/engine/README.md b/packages/engine/README.md index 52bce86163..ae4e7fd43b 100644 --- a/packages/engine/README.md +++ b/packages/engine/README.md @@ -126,7 +126,7 @@ https://cdn.jsdelivr.net/npm/@alilc/lowcode-react-simulator-renderer@1.0.18/dist ``` #### Method 5: Use your own cdn -Pass the files under packages/engine/dist and packages/(react|rax)-simulator-renderer/dist in the source code to your cdn provider +Pass the files under packages/engine/dist and packages/react-simulator-renderer/dist in the source code to your cdn provider ## 🔗 Related Links diff --git a/packages/ignitor/build.json b/packages/ignitor/build.json index 218373247c..f1956cf527 100644 --- a/packages/ignitor/build.json +++ b/packages/ignitor/build.json @@ -1,8 +1,7 @@ { "entry": { "AliLowCodeEngine": "../engine/src/index.ts", - "ReactSimulatorRenderer": "../react-simulator-renderer/src/index.ts", - "RaxSimulatorRenderer": "../rax-simulator-renderer/src/index.ts" + "ReactSimulatorRenderer": "../react-simulator-renderer/src/index.ts" }, "vendor": false, "devServer": { diff --git a/packages/rax-renderer/README.md b/packages/rax-renderer/README.md deleted file mode 100644 index 7b430de630..0000000000 --- a/packages/rax-renderer/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Rax Renderer - -Rax 渲染模块。 - -## 安装 - -``` -$ npm install @alilc/lowcode-rax-renderer --save -``` - -## 使用 - -```js -import { createElement, render } from 'rax'; -import DriverUniversal from 'driver-universal'; -import RaxRenderer from '@ali/lowcode-rax-renderer'; - -const components = { - View, - Text -}; - -const schema = { - componentName: 'Page', - fileName: 'home', - children: [ - { - componentName: 'View', - children: [ - { - componentName: 'Text', - props: { - type: 'primary' - }, - children: ['Welcome to Your Rax App'] - } - ] - } - ] -}; - -render( - <RaxRenderer - schema={schema} - components={components} - />, - document.getElementById('root'), { driver: DriverUniversal } -); -``` diff --git a/packages/rax-renderer/build.json b/packages/rax-renderer/build.json deleted file mode 100644 index 3edf143801..0000000000 --- a/packages/rax-renderer/build.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "plugins": [ - [ - "build-plugin-rax-component", - { - "type": "rax", - "targets": ["web"] - } - ] - ] -} diff --git a/packages/rax-renderer/demo/index.jsx b/packages/rax-renderer/demo/index.jsx deleted file mode 100644 index cfcae2a201..0000000000 --- a/packages/rax-renderer/demo/index.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import { createElement, render } from 'rax'; -import DriverUniversal from 'driver-universal'; -import View from 'rax-view'; -import Text from 'rax-text'; -import { Engine } from '../src/index'; - -const components = { - View, - Text, -}; - -const schema = { - componentName: 'Page', - fileName: 'home', - props: {}, - children: [ - { - componentName: 'View', - props: {}, - children: [ - { - componentName: 'Text', - props: { - type: 'primary', - }, - children: ['Welcome to Your Rax App!'], - }, - ], - }, - ], -}; - -render(<Engine schema={schema} components={components} />, document.getElementById('root'), { - driver: DriverUniversal, -}); diff --git a/packages/rax-renderer/demo/miniapp/app.js b/packages/rax-renderer/demo/miniapp/app.js deleted file mode 100644 index 3482935519..0000000000 --- a/packages/rax-renderer/demo/miniapp/app.js +++ /dev/null @@ -1 +0,0 @@ -App({}); diff --git a/packages/rax-renderer/demo/miniapp/app.json b/packages/rax-renderer/demo/miniapp/app.json deleted file mode 100644 index 94127c774c..0000000000 --- a/packages/rax-renderer/demo/miniapp/app.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "pages": ["pages/index"], - "window": { - "defaultTitle": "demo" - } -} diff --git a/packages/rax-renderer/demo/miniapp/pages/index.acss b/packages/rax-renderer/demo/miniapp/pages/index.acss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/rax-renderer/demo/miniapp/pages/index.axml b/packages/rax-renderer/demo/miniapp/pages/index.axml deleted file mode 100644 index 41b536b4ce..0000000000 --- a/packages/rax-renderer/demo/miniapp/pages/index.axml +++ /dev/null @@ -1 +0,0 @@ -<my-component></my-component> diff --git a/packages/rax-renderer/demo/miniapp/pages/index.js b/packages/rax-renderer/demo/miniapp/pages/index.js deleted file mode 100644 index 687d87e197..0000000000 --- a/packages/rax-renderer/demo/miniapp/pages/index.js +++ /dev/null @@ -1,4 +0,0 @@ -Page({ - onLoad() {}, - onShow() {}, -}); diff --git a/packages/rax-renderer/demo/miniapp/pages/index.json b/packages/rax-renderer/demo/miniapp/pages/index.json deleted file mode 100644 index 89b15c54ca..0000000000 --- a/packages/rax-renderer/demo/miniapp/pages/index.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "defaultTitle": "Miniapp Rax Text demo", - "usingComponents": { - "my-component": "../components/Target/index" - } -} diff --git a/packages/rax-renderer/demo/wechat-miniprogram/app.js b/packages/rax-renderer/demo/wechat-miniprogram/app.js deleted file mode 100644 index 3482935519..0000000000 --- a/packages/rax-renderer/demo/wechat-miniprogram/app.js +++ /dev/null @@ -1 +0,0 @@ -App({}); diff --git a/packages/rax-renderer/demo/wechat-miniprogram/app.json b/packages/rax-renderer/demo/wechat-miniprogram/app.json deleted file mode 100644 index be00ced601..0000000000 --- a/packages/rax-renderer/demo/wechat-miniprogram/app.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "pages": ["pages/index"], - "window": { - "title": "demo" - } -} diff --git a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.js b/packages/rax-renderer/demo/wechat-miniprogram/pages/index.js deleted file mode 100644 index 687d87e197..0000000000 --- a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.js +++ /dev/null @@ -1,4 +0,0 @@ -Page({ - onLoad() {}, - onShow() {}, -}); diff --git a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.json b/packages/rax-renderer/demo/wechat-miniprogram/pages/index.json deleted file mode 100644 index 9448c84eaf..0000000000 --- a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "title": "Wechat MiniProgram Rax Text demo", - "usingComponents": { - "my-component": "../components/Target/index" - } -} diff --git a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxml b/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxml deleted file mode 100644 index 41b536b4ce..0000000000 --- a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxml +++ /dev/null @@ -1 +0,0 @@ -<my-component></my-component> diff --git a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxss b/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json deleted file mode 100644 index 8173d6e4e1..0000000000 --- a/packages/rax-renderer/package.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.5", - "description": "Rax renderer for Ali lowCode engine", - "main": "lib/index.js", - "module": "es/index.js", - "miniappConfig": { - "main": "lib/miniapp/index", - "main:wechat": "lib/wechat-miniprogram/index" - }, - "files": [ - "dist", - "es", - "lib" - ], - "keywords": [ - "low-code", - "lowcode", - "Rax" - ], - "engines": { - "npm": ">=3.0.0" - }, - "peerDependencies": { - "prop-types": "^15.7.2", - "rax": "^1.1.0" - }, - "scripts": { - "start": "build-scripts start", - "build": "build-scripts build" - }, - "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", - "rax-find-dom-node": "^1.0.1" - }, - "devDependencies": { - "@alib/build-scripts": "^0.1.0", - "build-plugin-rax-component": "^0.2.11", - "driver-universal": "^3.1.3" - }, - "publishConfig": { - "access": "public", - "registry": "https://registry.npmjs.org/" - }, - "repository": { - "type": "http", - "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/rax-renderer" - }, - "license": "MIT", - "homepage": "https://github.com/alibaba/lowcode-engine/#readme", - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", - "bugs": "https://github.com/alibaba/lowcode-engine/issues" -} diff --git a/packages/rax-renderer/src/hoc/compFactory.tsx b/packages/rax-renderer/src/hoc/compFactory.tsx deleted file mode 100644 index 1c821ab6d9..0000000000 --- a/packages/rax-renderer/src/hoc/compFactory.tsx +++ /dev/null @@ -1,82 +0,0 @@ -// @ts-nocheck - -import { Component, forwardRef } from 'rax'; -import PropTypes from 'prop-types'; -import { AppHelper } from '@alilc/lowcode-utils'; -import { utils, contextFactory } from '@alilc/lowcode-renderer-core'; -import componentRendererFactory from '../renderer/component'; -import blockRendererFactory from '../renderer/block'; - -const { forEach, isFileSchema } = utils; - -export default function compFactory(schema, components = {}, componentsMap = {}, config = {}) { - // 自定义组件需要有自己独立的appHelper - const appHelper = new AppHelper(config); - const CompRenderer = componentRendererFactory(); - const BlockRenderer = blockRendererFactory(); - const AppContext = contextFactory(); - - class LNCompView extends Component { - static displayName = 'LceCompFactory'; - - static version = config.version || '0.0.0'; - - static contextType = AppContext; - - static propTypes = { - forwardedRef: PropTypes.func, - }; - - render() { - if (!schema || schema.componentName !== 'Component' || !isFileSchema(schema)) { - console.warn('自定义组件模型结构异常!'); - return null; - } - const { forwardedRef, ...otherProps } = this.props; - // 低代码组件透传应用上下文 - const ctx = ['utils', 'constants', 'history', 'location', 'match']; - ctx.forEach(key => { - if (!appHelper[key] && this.context?.appHelper && this.context?.appHelper[key]) { - appHelper.set(key, this.context.appHelper[key]); - } - }); - // 支持通过context透传国际化配置 - const localeProps = {}; - const { locale, messages } = this.context; - if (locale && messages && messages[schema.fileName]) { - localeProps.locale = locale; - localeProps.messages = messages[schema.fileName]; - } - const props = { - ...schema.defaultProps, - ...localeProps, - ...otherProps, - __schema: schema, - ref: forwardedRef, - }; - - return ( - <AppContext.Consumer> - {context => { - this.context = context; - return ( - <CompRenderer - {...props} - __appHelper={appHelper} - __components={{ ...components, Component: CompRenderer, Block: BlockRenderer }} - __componentsMap={componentsMap} - /> - ); - }} - </AppContext.Consumer> - ); - } - } - - const ResComp = forwardRef((props, ref) => <LNCompView {...props} forwardedRef={ref} />); - forEach(schema.static, (val, key) => { - ResComp[key] = val; - }); - ResComp.version = config.version || '0.0.0'; - return ResComp; -} diff --git a/packages/rax-renderer/src/index.ts b/packages/rax-renderer/src/index.ts deleted file mode 100644 index 1947aa5aec..0000000000 --- a/packages/rax-renderer/src/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Component, PureComponent, createElement, createContext, forwardRef } from 'rax'; -import findDOMNode from 'rax-find-dom-node'; -import { - adapter, - addonRendererFactory, - tempRendererFactory, - rendererFactory, -} from '@alilc/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(), -}); - -function factory() { - const Renderer = rendererFactory(); - return class extends Renderer { - constructor(props: any, context: any) { - super(props, context); - } - - isValidComponent(obj: any) { - return obj?.prototype?.setState || obj?.prototype instanceof Component; - } - }; -} - -const RaxRenderer: any = factory(); -const Engine: any = RaxRenderer; - -export { - Engine, - CompFactory, -}; - -export default RaxRenderer; diff --git a/packages/rax-renderer/src/renderer/block.tsx b/packages/rax-renderer/src/renderer/block.tsx deleted file mode 100644 index 8fa4a27316..0000000000 --- a/packages/rax-renderer/src/renderer/block.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { blockRendererFactory, types } from '@alilc/lowcode-renderer-core'; - -const raxBlockRendererFactory: () => any = () => { - const OriginBlock = blockRendererFactory(); - return class BlockRenderer extends OriginBlock { - render() { - // @ts-ignore - const that: types.IRenderer = this; - const { __schema, __components } = that.props; - if (that.__checkSchema(__schema)) { - return '区块 schema 结构异常!'; - } - that.__debug(`render - ${__schema.fileName}`); - - const children = ((context) => { - that.context = context; - that.__generateCtx({}); - that.__render(); - return that.__renderComp((__components as any)?.Block, { blockContext: that }); - }); - return that.__renderContextConsumer(children); - } - }; -}; -export default raxBlockRendererFactory; diff --git a/packages/rax-renderer/src/renderer/component.tsx b/packages/rax-renderer/src/renderer/component.tsx deleted file mode 100644 index 9943b3c2f1..0000000000 --- a/packages/rax-renderer/src/renderer/component.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { componentRendererFactory, types } from '@alilc/lowcode-renderer-core'; - -const raxComponentRendererFactory: () => any = () => { - const OriginComponent = componentRendererFactory(); - return class ComponentRenderer extends OriginComponent { - render() { - // @ts-ignore - const that: types.IRenderer = this; - const { __schema, __components } = that.props; - if (that.__checkSchema(__schema)) { - return '自定义组件 schema 结构异常!'; - } - that.__debug(`render - ${__schema.fileName}`); - - const { noContainer } = that.__parseData(__schema.props); - - const children = ((context) => { - that.context = context; - that.__generateCtx({ component: that }); - that.__render(); - // 传 null,使用内置的 div 来渲染,解决在页面中渲染 vc-component 报错的问题 - return that.__renderComp(null, { - compContext: that, - blockContext: that, - }); - }); - const content = that.__renderContextConsumer(children); - - if (noContainer) { - return content; - } - - return that.__renderContent(content); - } - }; -}; -export default raxComponentRendererFactory; diff --git a/packages/rax-renderer/src/renderer/page.tsx b/packages/rax-renderer/src/renderer/page.tsx deleted file mode 100644 index f6ebd3f7cf..0000000000 --- a/packages/rax-renderer/src/renderer/page.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { pageRendererFactory, types } from '@alilc/lowcode-renderer-core'; - -const raxPageRendererFactory: () => any = () => { - const OriginPage = pageRendererFactory(); - return class PageRenderer extends OriginPage { - async componentDidUpdate() { - // @ts-ignore - super.componentDidUpdate(...arguments); - } - - render() { - // @ts-ignore - const that: types.IRenderer = this; - const { __schema, __components } = that.props; - if (that.__checkSchema(__schema)) { - return '页面 schema 结构异常!'; - } - that.__debug(`render - ${__schema?.fileName}`); - - const { Page } = __components as any; - if (Page) { - const children = ((context) => { - that.context = context; - that.__render(); - return that.__renderComp(Page, { pageContext: that }); - }); - return that.__renderContextConsumer(children); - } - - return that.__renderContent(that.__renderContextConsumer((context) => { - that.context = context; - return that.__renderContextProvider({ pageContext: that }); - })); - } - }; -}; - -export default raxPageRendererFactory; \ No newline at end of file diff --git a/packages/rax-renderer/tsconfig.json b/packages/rax-renderer/tsconfig.json deleted file mode 100644 index 7e264d1f05..0000000000 --- a/packages/rax-renderer/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "lib": ["es2015", "dom"], - "target": "esnext", - "module": "esnext", - "moduleResolution": "node", - "strict": false, - "strictPropertyInitialization": false, - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "jsx": "react", - "jsxFactory": "createElement", - "importHelpers": true, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "sourceMap": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "outDir": "lib" - }, - "exclude": ["test", "lib", "es", "node_modules"], - "include": [ - "src" - ] -} diff --git a/packages/rax-simulator-renderer/.babelrc b/packages/rax-simulator-renderer/.babelrc deleted file mode 100644 index e0e2e5f343..0000000000 --- a/packages/rax-simulator-renderer/.babelrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "plugins": [ - ["@babel/plugin-transform-react-jsx", { - "pragma": "createElement", // default pragma is React.createElement - "pragmaFrag": "createFragment", // default is React.Fragment - "throwIfNamespace": false // defaults to true - }] - ] -} diff --git a/packages/rax-simulator-renderer/babel.config.js b/packages/rax-simulator-renderer/babel.config.js deleted file mode 100644 index c5986f2bc0..0000000000 --- a/packages/rax-simulator-renderer/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../babel.config'); \ No newline at end of file diff --git a/packages/rax-simulator-renderer/build.json b/packages/rax-simulator-renderer/build.json deleted file mode 100644 index e7ae1dcf7a..0000000000 --- a/packages/rax-simulator-renderer/build.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "plugins": ["@alilc/build-plugin-lce", "./build.plugin.js"] -} diff --git a/packages/rax-simulator-renderer/build.plugin.js b/packages/rax-simulator-renderer/build.plugin.js deleted file mode 100644 index d613f1f56a..0000000000 --- a/packages/rax-simulator-renderer/build.plugin.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = ({ onGetWebpackConfig }) => { - onGetWebpackConfig((config) => { - config.performance.hints(false); - }); -}; diff --git a/packages/rax-simulator-renderer/build.umd.json b/packages/rax-simulator-renderer/build.umd.json deleted file mode 100644 index 833c92b246..0000000000 --- a/packages/rax-simulator-renderer/build.umd.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "entry": { - "rax-simulator-renderer": "src/index" - }, - "sourceMap": true, - "library": "___RaxSimulatorRenderer___", - "libraryTarget": "umd", - "externals": { - "react": "var window.React", - "react-dom": "var window.ReactDOM", - "prop-types": "var window.PropTypes", - "@alifd/next": "var Next", - "@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt", - "rax": "var window.Rax", - "moment": "var moment", - "lodash": "var _" - }, - "polyfill": false, - "outputDir": "dist", - "vendor": false, - "ignoreHtmlTemplate": true, - "plugins": [ - "build-plugin-react-app", - [ - "build-plugin-fusion", - { - "externalNext": "umd" - } - ], - [ - "build-plugin-moment-locales", - { - "locales": ["zh-cn"] - } - ], - "./build.plugin.js" - ] -} diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json deleted file mode 100644 index f264380ec1..0000000000 --- a/packages/rax-simulator-renderer/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.5", - "description": "rax simulator renderer for alibaba lowcode designer", - "main": "lib/index.js", - "module": "es/index.js", - "license": "MIT", - "files": [ - "dist" - ], - "scripts": { - "build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build", - "build:umd": "build-scripts build --config build.umd.json" - }, - "dependencies": { - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-rax-renderer": "1.2.5", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", - "classnames": "^2.2.6", - "driver-universal": "^3.1.3", - "history": "^5.0.0", - "lodash": "^4.17.19", - "mobx": "^6.3.0", - "mobx-react": "^7.2.0", - "path-to-regexp": "3.2.0", - "rax-find-dom-node": "^1.0.0", - "react": "^16", - "react-dom": "^16.7.0" - }, - "devDependencies": { - "@alib/build-scripts": "^0.1.18", - "@babel/plugin-transform-react-jsx": "^7.10.4", - "@types/classnames": "^2.2.7", - "@types/node": "^13.7.1", - "@types/rax": "^1.0.0", - "@types/react": "^16", - "@types/react-dom": "^16", - "build-plugin-rax-component": "^0.2.11" - }, - "peerDependencies": { - "rax": "^1.1.0" - }, - "publishConfig": { - "access": "public", - "registry": "https://registry.npmjs.org/" - }, - "repository": { - "type": "http", - "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/rax-simulator-renderer" - }, - "homepage": "https://github.com/alibaba/lowcode-engine/#readme", - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", - "bugs": "https://github.com/alibaba/lowcode-engine/issues" -} diff --git a/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.less b/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.less deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.tsx b/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.tsx deleted file mode 100644 index 6608942c4b..0000000000 --- a/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Component } from 'rax'; -import lg from '@ali/vu-logger'; - -import './index.less'; - -export class UnknownComponent extends Component { - props: { - _componentName: string; - }; - - render() { - lg.log('ERROR_NO_COMPONENT_VIEW'); - lg.error('Error component information:', this.props); - return <div className="engine-unknow-component">组件 {this.props._componentName} 无视图,请打开控制台排查</div>; - } -} - -export class FaultComponent extends Component { - props: { - _componentName: string; - }; - - render() { - return <div className="engine-fault-component">组件 {this.props._componentName} 渲染错误,请打开控制台排查</div>; - } -} - -export class HiddenComponent extends Component { - render() { - return <div className="engine-hidden-component">在本页面不显示</div>; - } -} - -export default { FaultComponent, HiddenComponent, UnknownComponent }; diff --git a/packages/rax-simulator-renderer/src/builtin-components/leaf.tsx b/packages/rax-simulator-renderer/src/builtin-components/leaf.tsx deleted file mode 100644 index 5276b0018d..0000000000 --- a/packages/rax-simulator-renderer/src/builtin-components/leaf.tsx +++ /dev/null @@ -1,251 +0,0 @@ -import { Component } from 'rax'; - -class Leaf extends Component { - static displayName = 'Leaf'; - - static componentMetadata = { - componentName: 'Leaf', - configure: { - props: [{ - name: 'children', - setter: 'StringSetter', - }], - // events/className/style/general/directives - supports: false, - }, - }; - - render() { - const { children } = this.props; - return children; - } -} - -export default Leaf; - -// import { Component, createElement } from 'rax'; -// import findDOMNode from 'rax-find-dom-node'; -// import { each, get, omit } from 'lodash'; -// import { getView, setNativeNode, createNodeStyleSheet } from '../renderUtils'; - -// import { FaultComponent, HiddenComponent, UnknownComponent } from '../UnusualComponent'; - -// export interface ILeaf { -// leaf: any; -// } -// export default class Leaf extends Component<ILeaf, {}> { -// static displayName = 'Leaf'; - -// state = { -// hasError: false, -// }; - -// willDetach: any[]; - -// styleSheet: any; - -// context: any; -// refs: any; - -// componentWillMount() { -// const { leaf } = this.props; -// this.willDetach = [ -// leaf.onPropsChange(() => { -// // 强制刷新 -// this.setState(this.state); -// }), -// leaf.onChildrenChange(() => { -// // 强制刷新 -// this.setState(this.state); -// }), -// leaf.onStatusChange((status: { dropping: boolean }, field: string) => { -// // console.log({...status}, field) -// if (status.dropping !== false) { -// // 当 dropping 为 Insertion 对象时,强制渲染会出错,原因待查 -// return; -// } -// if (field === 'dragging' || field === 'dropping' || field === 'pseudo' || field === 'visibility') { -// // 强制刷新 -// this.setState(this.state); -// } -// }), -// ]; - -// /** -// * while props replaced -// * bind the new event on it -// */ -// leaf.onPropsReplace(() => { -// this.willDetach[0](); -// this.willDetach[0] = leaf.onPropsChange(() => { -// // 强制刷新 -// this.setState(this.state); -// }); -// }); -// } - -// componentDidMount() { -// this.modifyDOM(); -// } - -// shouldComponentUpdate() { -// // forceUpdate 的替代方案 -// return true; -// // const pageCanRefresh = this.leaf.getPage().canRefresh(); -// // if (pageCanRefresh) { -// // return pageCanRefresh; -// // } -// // const getExtProps = obj => { -// // const { leaf, ...props } = obj; -// // return props; -// // }; -// // return !shallowEqual(getExtProps(this.props), getExtProps(nextProps)); -// } - -// componentDidUpdate() { -// this.modifyDOM(); -// } - -// componentWillUnmount() { -// if (this.willDetach) { -// this.willDetach.forEach((off) => off()); -// } -// setNativeNode(this.props.leaf, null); -// } - -// componentDidCatch() { -// this.setState({ hasError: true }, () => { -// console.log('error'); -// }); -// } - -// modifyDOM() { -// const shell = findDOMNode(this); -// const { leaf } = this.props; -// // 与 React 不同,rax 的 findDOMNode 找不到节点时, -// // shell 会是 <!-- empty -->,而不是 null, -// // 所以这里进行是否为注释的判断 -// if (shell && shell.nodeType !== window.Node.COMMENT_NODE) { -// setNativeNode(leaf, shell); -// if (leaf.getStatus('dragging')) { -// get(shell, 'classList').add('engine-dragging'); -// } else { -// get(shell, 'classList').remove('engine-dragging'); -// } -// each(get(shell, 'classList'), (cls) => { -// if (cls.substring(0, 8) === '-pseudo-') { -// get(shell, 'classList').remove(cls); -// } -// }); -// const pseudo = leaf.getStatus('pseudo'); -// if (pseudo) { -// get(shell, 'classList').add(`-pseudo-${pseudo}`); -// } -// } else { -// setNativeNode(leaf, null); -// } -// } - -// render() { -// const props = omit(this.props, ['leaf']); -// const { leaf } = this.props; -// const componentName = leaf.getComponentName(); - -// const View = getView(componentName); - -// const newProps = { -// _componentName: componentName, -// }; - -// if (!View) { -// return createElement(UnknownComponent, { -// // _componentName: componentName, -// ...newProps, -// }); -// } - -// let staticProps = { -// ...leaf.getStaticProps(false), -// ...props, -// _componentName: componentName, -// _leaf: leaf, -// componentId: leaf.getId(), -// }; - -// if (!leaf.isVisibleInPane()) { -// return null; -// } - -// if (!leaf.isVisible()) { -// return createElement(HiddenComponent, { -// ...staticProps, -// }); -// } - -// if (this.state.hasError) { -// return createElement(FaultComponent, { -// // _componentName: componentName, -// ...newProps, -// }); -// } - -// if (this.styleSheet) { -// this.styleSheet.parentNode.removeChild(this.styleSheet); -// } - -// this.styleSheet = createNodeStyleSheet(staticProps); - -// if (leaf.ableToModifyChildren()) { -// const children = leaf -// .getChildren() -// .filter((child: any) => child.getComponentName() !== 'Slot') -// .map((child: any) => -// createElement(Leaf, { -// key: child.getId(), -// leaf: child, -// }), -// ); -// // const insertion = leaf.getStatus('dropping'); -// // InsertionGhost 都是React节点,用Rax渲染会报错,后面这些节点需要通过Rax组件来实现 -// // if (children.length < 1 && insertion && insertion.getIndex() !== null) { - -// // //children = []; -// // children = [<InsertionGhost key="insertion" />]; -// // } else if (insertion && insertion.isNearEdge()) { -// // if (insertion.isNearAfter()) { -// // children.push(<InsertionGhost key="insertion" />); -// // } else { -// // children.unshift(<InsertionGhost key="insertion" />); -// // } -// // } -// staticProps = { -// ...staticProps, -// ...this.processSlots(this.props.leaf.getChildren()), -// }; - -// return createElement( -// View, -// { -// ...staticProps, -// }, -// children, -// ); -// } - -// return createElement(View, { -// ...staticProps, -// }); -// } - -// processSlots(children: Rax.RaxNodeArray) { -// const slots: any = {}; -// children && -// children.length && -// children.forEach((child: any) => { -// if (child.getComponentName() === 'Slot') { -// slots[child.getPropValue('slotName')] = <Leaf key={child.getId()} leaf={child} />; -// } -// }); -// return slots; -// } -// } diff --git a/packages/rax-simulator-renderer/src/builtin-components/renderUtils.ts b/packages/rax-simulator-renderer/src/builtin-components/renderUtils.ts deleted file mode 100644 index 10f8438fb2..0000000000 --- a/packages/rax-simulator-renderer/src/builtin-components/renderUtils.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { isObject } from 'lodash'; -import { css } from '@alilc/lowcode-utils'; - -const { toCss } = css; -const engine = (window as any).VisualEngine; -const { Trunk, Viewport } = engine; - -export const NativeNodeCache: any = {}; - -function ucfirst(s: string) { - return s.charAt(0).toUpperCase() + s.substring(1); -} - -export function shallowEqual(obj: { [key: string]: string }, tObj: { [key: string]: string }) { - for (const i in obj) { - if (Object.prototype.hasOwnProperty.call(obj, i) && obj[i] !== tObj[i]) { - return false; - } - } - return true; -} - -export function createNodeStyleSheet(props: any) { - if (props && props.fieldId) { - let styleProp = props.__style__; - - if (isObject(styleProp)) { - styleProp = toCss(styleProp); - } - - if (typeof styleProp === 'string') { - const s = document.createElement('style'); - const cssId = `_style_pesudo_${ props.fieldId}`; - const cssClass = `_css_pesudo_${ props.fieldId}`; - - props.className = cssClass; - s.setAttribute('type', 'text/css'); - s.setAttribute('id', cssId); - document.getElementsByTagName('head')[0].appendChild(s); - - s.appendChild( - document.createTextNode( - styleProp - .replace(/(\d+)rpx/g, (a, b) => { - return `${b / 2}px`; - }) - .replace(/:root/g, `.${ cssClass}`), - ), - ); - return s; - } - } -} - -export function setNativeNode(leaf: any, node: Rax.RaxNode) { - const id = leaf.getId(); - if (NativeNodeCache[id] === node) { - return; - } - NativeNodeCache[id] = node; - leaf.mountChange(); -} - -export function getView(componentName: string) { - // let view = new Trunk().getPrototypeView(componentName); - let view = Trunk.getPrototypeView(componentName); - if (!view) { - return null; - } - const viewport = Viewport.getViewport(); - if (viewport) { - const [mode, device] = viewport.split('-', 2).map(ucfirst); - if (view.hasOwnProperty(device)) { - view = view[device]; - } - - if (view.hasOwnProperty(mode)) { - view = view[mode]; - } - } - - return view; -} diff --git a/packages/rax-simulator-renderer/src/builtin-components/slot.tsx b/packages/rax-simulator-renderer/src/builtin-components/slot.tsx deleted file mode 100644 index 3a77491bc0..0000000000 --- a/packages/rax-simulator-renderer/src/builtin-components/slot.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Component } from 'rax'; - -class Slot extends Component { - static displayName = 'Slot'; - - static componentMetadata = { - componentName: 'Slot', - configure: { - props: [{ - name: '___title', - title: { - type: 'i18n', - 'en-US': 'Slot Title', - 'zh-CN': '插槽标题', - }, - setter: 'StringSetter', - defaultValue: '插槽容器', - }, { - name: '___params', - title: { - type: 'i18n', - 'en-US': 'Slot Params', - 'zh-CN': '插槽入参', - }, - setter: { - componentName: 'ArraySetter', - props: { - itemSetter: { - componentName: 'StringSetter', - props: { - placeholder: { - type: 'i18n', - 'zh-CN': '参数名称', - 'en-US': 'Argument Name', - }, - }, - }, - }, - }, - }], - // events/className/style/general/directives - supports: false, - }, - }; - - render() { - const { children } = this.props; - return ( - <div className="lc-container">{children}</div> - ); - } -} - -export default Slot; diff --git a/packages/rax-simulator-renderer/src/host.ts b/packages/rax-simulator-renderer/src/host.ts deleted file mode 100644 index c5cf2e3e1c..0000000000 --- a/packages/rax-simulator-renderer/src/host.ts +++ /dev/null @@ -1,4 +0,0 @@ -// NOTE: 仅做类型标注,切勿做其它用途 -import { BuiltinSimulatorHost } from '@alilc/lowcode-designer'; - -export const host: BuiltinSimulatorHost = (window as any).LCSimulatorHost; diff --git a/packages/rax-simulator-renderer/src/image.d.ts b/packages/rax-simulator-renderer/src/image.d.ts deleted file mode 100644 index 7ed4ad925c..0000000000 --- a/packages/rax-simulator-renderer/src/image.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare module 'rax-find-dom-node'; -declare module '@alilc/lowcode-rax-renderer/lib/index'; diff --git a/packages/rax-simulator-renderer/src/index.ts b/packages/rax-simulator-renderer/src/index.ts deleted file mode 100644 index 3a88726657..0000000000 --- a/packages/rax-simulator-renderer/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import renderer from './renderer'; - -if (typeof window !== 'undefined') { - (window as any).SimulatorRenderer = renderer; -} - -export default renderer; diff --git a/packages/rax-simulator-renderer/src/rax-use-router.js b/packages/rax-simulator-renderer/src/rax-use-router.js deleted file mode 100644 index 9a399a9478..0000000000 --- a/packages/rax-simulator-renderer/src/rax-use-router.js +++ /dev/null @@ -1,288 +0,0 @@ -// Inspired by react-router and universal-router -import { useState, useEffect, useLayoutEffect, createElement } from 'rax'; -import pathToRegexp from 'path-to-regexp'; - -const cache = {}; -function decodeParam(val) { - try { - return decodeURIComponent(val); - } catch (err) { - return val; - } -} - -function matchPath(route, pathname, parentParams) { - let { path, routes, exact: end = true, strict = false, sensitive = false } = route; - // If not has path or has routes that should do not exact match - if (path == null || routes) { - end = false; - } - - // Default path is empty - path = path || ''; - - const regexpCacheKey = `${path}|${end}|${strict}|${sensitive}`; - const keysCacheKey = `${regexpCacheKey }|`; - - let regexp = cache[regexpCacheKey]; - const keys = cache[keysCacheKey] || []; - - if (!regexp) { - regexp = pathToRegexp(path, keys, { - end, - strict, - sensitive, - }); - cache[regexpCacheKey] = regexp; - cache[keysCacheKey] = keys; - } - - const result = regexp.exec(pathname); - if (!result) { - return null; - } - - const url = result[0]; - const params = { ...parentParams, history: router.history, location: router.history.location }; - - for (let i = 1; i < result.length; i++) { - const key = keys[i - 1]; - const prop = key.name; - const value = result[i]; - if (value !== undefined || !Object.prototype.hasOwnProperty.call(params, prop)) { - if (key.repeat) { - params[prop] = value ? value.split(key.delimiter).map(decodeParam) : []; - } else { - params[prop] = value ? decodeParam(value) : value; - } - } - } - - return { - path: !end && url.charAt(url.length - 1) === '/' ? url.slice(1) : url, - params, - }; -} - -function matchRoute(route, baseUrl, pathname, parentParams) { - let matched; - let childMatches; - let childIndex = 0; - - return { - next() { - if (!matched) { - matched = matchPath(route, pathname, parentParams); - - if (matched) { - return { - done: false, - $: { - route, - baseUrl, - path: matched.path, - params: matched.params, - }, - }; - } - } - - if (matched && route.routes) { - while (childIndex < route.routes.length) { - if (!childMatches) { - const childRoute = route.routes[childIndex]; - childRoute.parent = route; - - childMatches = matchRoute( - childRoute, - baseUrl + matched.path, - pathname.slice(matched.path.length), - matched.params, - ); - } - - const childMatch = childMatches.next(); - if (!childMatch.done) { - return { - done: false, - $: childMatch.$, - }; - } - - childMatches = null; - childIndex++; - } - } - - return { done: true }; - }, - }; -} - -let _initialized = false; -let _routerConfig = null; -const router = { - history: null, - handles: [], - errorHandler() { }, - addHandle(handle) { - return router.handles.push(handle); - }, - removeHandle(handleId) { - router.handles[handleId - 1] = null; - }, - triggerHandles(component) { - router.handles.forEach((handle) => { - handle && handle(component); - }); - }, - match(fullpath) { - if (fullpath == null) return; - - router.fullpath = fullpath; - - const parent = router.root; - const matched = matchRoute( - parent, - parent.path, - fullpath, - ); - - function next(parent) { - const current = matched.next(); - - if (current.done) { - const error = new Error(`No match for ${fullpath}`); - return router.errorHandler(error, router.history.location); - } - - let { component } = current.$.route; - if (typeof component === 'function') { - component = component(current.$.params, router.history.location); - } - if (component instanceof Promise) { - // Lazy loading component by import('./Foo') - return component.then((component) => { - // Check current fullpath avoid router has changed before lazy loading complete - if (fullpath === router.fullpath) { - router.triggerHandles(component); - } - }); - } else if (component != null) { - router.triggerHandles(component); - return component; - } else { - return next(parent); - } - } - - return next(parent); - }, -}; - -function matchLocation({ pathname }) { - router.match(pathname); -} - - -function getInitialComponent(routerConfig) { - let InitialComponent = []; - - if (_routerConfig === null) { - if (process.env.NODE_ENV !== 'production') { - if (!routerConfig) { - throw new Error('Error: useRouter should have routerConfig, see: https://www.npmjs.com/package/rax-use-router.'); - } - if (!routerConfig.history || !routerConfig.routes) { - throw new Error('Error: routerConfig should contain history and routes, see: https://www.npmjs.com/package/rax-use-router.'); - } - } - _routerConfig = routerConfig; - } - if (_routerConfig.InitialComponent) { - InitialComponent = _routerConfig.InitialComponent; - } - router.history = _routerConfig.history; - - return InitialComponent; -} - -let unlisten = null; -let handleId = null; -let pathes = ''; -export function useRouter(routerConfig) { - const [component, setComponent] = useState(getInitialComponent(routerConfig)); - - let newPathes = ''; - if (routerConfig) { - _routerConfig = routerConfig; - const { routes } = _routerConfig; - router.root = Array.isArray(routes) ? { routes } : routes; - if (Array.isArray(routes)) { - newPathes = routes.map(it => it.path).join(','); - } else { - newPathes = routes.path; - } - } - if (_initialized && _routerConfig.history) { - if (newPathes !== pathes) { - matchLocation(_routerConfig.history.location); - pathes = newPathes; - } - } - - useLayoutEffect(() => { - if (unlisten) { - unlisten(); - unlisten = null; - } - - if (handleId) { - router.removeHandle(handleId); - handleId = null; - } - - const { history } = _routerConfig; - const { routes } = _routerConfig; - - router.root = Array.isArray(routes) ? { routes } : routes; - - handleId = router.addHandle((component) => { - setComponent(component); - }); - - // Init path match - if (_initialized || !_routerConfig.InitialComponent) { - matchLocation(history.location); - pathes = newPathes; - } - - unlisten = history.listen(({ location }) => { - matchLocation(location); - pathes = newPathes; - }); - - _initialized = true; - - return () => { - pathes = ''; - router.removeHandle(handleId); - handleId = null; - unlisten(); - unlisten = null; - }; - }, []); - - return { component }; -} - -export function withRouter(Component) { - function Wrapper(props) { - const { history } = router; - return createElement(Component, { ...props, history, location: history.location }); - } - - Wrapper.displayName = `withRouter(${ Component.displayName || Component.name })`; - Wrapper.WrappedComponent = Component; - return Wrapper; -} diff --git a/packages/rax-simulator-renderer/src/renderer-view.tsx b/packages/rax-simulator-renderer/src/renderer-view.tsx deleted file mode 100644 index bc39cddea0..0000000000 --- a/packages/rax-simulator-renderer/src/renderer-view.tsx +++ /dev/null @@ -1,275 +0,0 @@ -import RaxRenderer from '@alilc/lowcode-rax-renderer'; -import { History } from 'history'; -import { Component, createElement, Fragment } from 'rax'; -import { useRouter } from './rax-use-router'; -import { DocumentInstance, SimulatorRendererContainer } from './renderer'; -import './renderer.less'; -import { uniqueId } from '@alilc/lowcode-utils'; -import { GlobalEvent } from '@alilc/lowcode-types'; -import { host } from './host'; - -// patch cloneElement avoid lost keyProps -const originCloneElement = (window as any).Rax.cloneElement; -(window as any).Rax.cloneElement = (child: any, { _leaf, ...props }: any = {}, ...rest: any[]) => { - if (child.ref && props.ref) { - const dRef = props.ref; - const cRef = child.ref; - props.ref = (x: any) => { - if (cRef) { - if (typeof cRef === 'function') { - cRef(x); - } else { - try { - cRef.current = x; - } catch (e) { - console.error(e); - } - } - } - if (dRef) { - if (typeof dRef === 'function') { - dRef(x); - } else { - try { - dRef.current = x; - } catch (e) { - console.error(e); - } - } - } - }; - } - return originCloneElement(child, props, ...rest); -}; - -export default class SimulatorRendererView extends Component<{ rendererContainer: SimulatorRendererContainer }> { - private unlisten: any; - - componentDidMount() { - const { rendererContainer } = this.props; - this.unlisten = rendererContainer.onLayoutChange(() => { - this.forceUpdate(); - }); - } - - componentWillUnmount() { - if (this.unlisten) { - this.unlisten(); - } - } - - render() { - const { rendererContainer } = this.props; - return ( - <Layout rendererContainer={rendererContainer}> - <Routes rendererContainer={rendererContainer} history={rendererContainer.history} /> - </Layout> - ); - } -} - -export const Routes = (props: { - rendererContainer: SimulatorRendererContainer; - history: History; -}) => { - const { rendererContainer, history } = props; - const { documentInstances } = rendererContainer; - - const routes = { - history, - routes: documentInstances.map(instance => { - return { - path: instance.path, - component: (props: any) => <Renderer key={instance.id} rendererContainer={rendererContainer} documentInstance={instance} {...props} />, - }; - }), - }; - const { component } = useRouter(routes); - return component; -}; - -function ucfirst(s: string) { - return s.charAt(0).toUpperCase() + s.substring(1); -} -function getDeviceView(view: any, device: string, mode: string) { - if (!view || typeof view === 'string') { - return view; - } - - // compatible vision Mobile | Preview - device = ucfirst(device); - if (device === 'Mobile' && view.hasOwnProperty(device)) { - view = view[device]; - } - mode = ucfirst(mode); - if (mode === 'Preview' && view.hasOwnProperty(mode)) { - view = view[mode]; - } - return view; -} - -class Layout extends Component<{ rendererContainer: SimulatorRendererContainer }> { - constructor(props: any) { - super(props); - this.props.rendererContainer.onReRender(() => { - this.forceUpdate(); - }); - } - - render() { - const { rendererContainer, children } = this.props; - const { layout } = rendererContainer; - - if (layout) { - const { Component, props, componentName } = layout; - if (Component) { - return <Component props={props}>{children}</Component>; - } - if (componentName && rendererContainer.getComponent(componentName)) { - return createElement( - rendererContainer.getComponent(componentName), - { - ...props, - rendererContainer, - }, - [children], - ); - } - } - - return <Fragment>{children}</Fragment>; - } -} - -class Renderer extends Component<{ - rendererContainer: SimulatorRendererContainer; - documentInstance: DocumentInstance; -}> { - private unlisten: any; - private key: string; - private startTime: number | null = null; - - componentWillMount() { - this.key = uniqueId('renderer'); - } - - componentDidMount() { - const { documentInstance } = this.props; - this.unlisten = documentInstance.onReRender((params) => { - if (params && params.shouldRemount) { - this.key = uniqueId('renderer'); - } - this.forceUpdate(); - }); - } - - componentWillUnmount() { - if (this.unlisten) { - this.unlisten(); - } - } - shouldComponentUpdate() { - return false; - } - - componentDidUpdate() { - if (this.startTime) { - const time = Date.now() - this.startTime; - const nodeCount = host.designer.currentDocument?.getNodeCount?.(); - host.designer.editor?.eventBus.emit(GlobalEvent.Node.Rerender, { - componentName: 'Renderer', - type: 'All', - time, - nodeCount, - }); - } - } - - schemaChangedSymbol = false; - - getSchemaChangedSymbol = () => { - return this.schemaChangedSymbol; - }; - - setSchemaChangedSymbol = (symbol: boolean) => { - this.schemaChangedSymbol = symbol; - }; - - render() { - const { documentInstance } = this.props; - const { container, document } = documentInstance; - const { designMode, device } = container; - const { rendererContainer: renderer } = this.props; - this.startTime = Date.now(); - this.schemaChangedSymbol = false; - - return ( - <RaxRenderer - schema={documentInstance.schema} - components={renderer.components} - appHelper={renderer.context} - context={renderer.context} - device={device} - designMode={renderer.designMode} - key={this.key} - __host={host} - __container={container} - suspended={documentInstance.suspended} - self={documentInstance.scope} - onCompGetRef={(schema: any, ref: any) => { - documentInstance.mountInstance(schema.id, ref); - }} - thisRequiredInJSE={host.thisRequiredInJSE} - documentId={document.id} - getNode={(id: string) => documentInstance.getNode(id) as any} - rendererName="PageRenderer" - customCreateElement={(Component: any, props: any, children: any) => { - const { __id, ...viewProps } = props; - viewProps.componentId = __id; - const leaf = documentInstance.getNode(__id); - viewProps._leaf = leaf; - viewProps._componentName = leaf?.componentName; - // 如果是容器 && 无children && 高宽为空 增加一个占位容器,方便拖动 - if ( - !viewProps.dataSource && - leaf?.isContainer() && - (children == null || (Array.isArray(children) && !children.length)) && - (!viewProps.style || Object.keys(viewProps.style).length === 0) - ) { - children = ( - <div className="lc-container-placeholder" style={viewProps.placeholderStyle}> - {viewProps.placeholder || '拖拽组件或模板到这里'} - </div> - ); - } - - // if (viewProps._componentName === 'Menu') { - // Object.assign(viewProps, { - // _componentName: 'Menu', - // className: '_css_pesudo_menu_kbrzyh0f', - // context: { VE: (window as any).VisualLowCodeRenderer }, - // direction: undefined, - // events: { ignored: true }, - // fieldId: 'menu_kbrzyh0f', - // footer: '', - // header: '', - // mode: 'inline', - // onItemClick: { ignored: true }, - // onSelect: { ignored: true }, - // popupAlign: 'follow', - // selectMode: false, - // triggerType: 'click', - // }); - // console.info('menuprops', viewProps); - // } - - return createElement( - getDeviceView(Component, device, designMode), - viewProps, - leaf?.isContainer() ? (children == null ? [] : Array.isArray(children) ? children : [children]) : children, - ); - }} - /> - ); - } -} diff --git a/packages/rax-simulator-renderer/src/renderer.less b/packages/rax-simulator-renderer/src/renderer.less deleted file mode 100644 index b71dde9896..0000000000 --- a/packages/rax-simulator-renderer/src/renderer.less +++ /dev/null @@ -1,125 +0,0 @@ -body, html { - display: block; - background: white; - padding: 0; - margin: 0; -} - -html.engine-cursor-move, html.engine-cursor-move * { - cursor: grabbing !important; -} - -html.engine-cursor-copy, html.engine-cursor-copy * { - cursor: copy !important; -} - -html.engine-cursor-ew-resize, html.engine-cursor-ew-resize * { - cursor: ew-resize !important; -} - -::-webkit-scrollbar { - display: none; -} - -.lc-container { - &:empty { - background: #f2f3f5; - color: #a7b1bd; - outline: 1px dashed rgba(31, 56, 88, 0.2); - outline-offset: -1px !important; - height: 66px; - max-height: 100%; - min-width: 140px; - text-align: center; - overflow: hidden; - display: flex; - align-items: center; - &:before { - content: '\62D6\62FD\7EC4\4EF6\6216\6A21\677F\5230\8FD9\91CC'; - font-size: 14px; - z-index: 1; - width: 100%; - white-space: nowrap; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - } - } -} - -.engine-empty { - background: #f2f3f5; - color: #a7b1bd; - outline: 1px dashed rgba(31, 56, 88, 0.2); - outline-offset: -1px !important; - height: 66px; - max-height: 100%; - min-width: 140px; - text-align: center; - overflow: hidden; - display: flex; - align-items: center; -} - -.engine-empty:before { - content: '\62D6\62FD\7EC4\4EF6\6216\6A21\677F\5230\8FD9\91CC'; - font-size: 14px; - z-index: 1; - width: 100%; - white-space: nowrap; - height: 100%; - display: flex; - align-items: center; - justify-content: center; -} - -.lc-container-placeholder { - min-height: 60px; - height: 100%; - width: 100%; - background-color: rgb(240, 240, 240); - border: 1px dotted; - color: rgb(167, 177, 189); - display: flex; - align-items: center; - justify-content: center; - font-size: 14px; -} - -body.engine-document { - &:after, &:before { - content: ""; - display: table; - } - &:after { - clear: both; - } - - /* - .next-input-group, - .next-checkbox-group,.next-date-picker,.next-input,.next-month-picker, - .next-number-picker,.next-radio-group,.next-range,.next-range-picker, - .next-rating,.next-select,.next-switch,.next-time-picker,.next-upload, - .next-year-picker, - .next-breadcrumb-item,.next-calendar-header,.next-calendar-table { - pointer-events: none !important; - } */ -} - -.engine-live-editing { - cursor: text; - outline: none; - box-shadow: 0 0 0 2px rgb(102, 188, 92); - user-select: text; -} - -/* stylelint-disable-next-line selector-max-id */ -#app { - height: 100vh; -} - - -.luna-page { - height: 100%; -} diff --git a/packages/rax-simulator-renderer/src/renderer.ts b/packages/rax-simulator-renderer/src/renderer.ts deleted file mode 100644 index 64ec2d2c69..0000000000 --- a/packages/rax-simulator-renderer/src/renderer.ts +++ /dev/null @@ -1,690 +0,0 @@ -import { BuiltinSimulatorRenderer, Component, IBaseNode, IDocumentModel } from '@alilc/lowcode-designer'; -import { IPublicTypeComponentSchema, IPublicTypeNodeSchema, IPublicTypeNpmInfo, IPublicEnumTransformStage, IPublicTypeNodeInstance, IPublicTypeProjectSchema } from '@alilc/lowcode-types'; -import { Asset, compatibleLegaoSchema, cursor, isElement, isESModule, isLowcodeProjectSchema, isComponentSchema, isPlainObject, isReactComponent, setNativeSelection } from '@alilc/lowcode-utils'; -import LowCodeRenderer from '@alilc/lowcode-rax-renderer'; -import { computed, observable as obx, makeObservable, configure } from 'mobx'; -import DriverUniversal from 'driver-universal'; -import { createMemoryHistory, MemoryHistory } from 'history'; -// @ts-ignore -import Rax, { ComponentType, createElement, render as raxRender, shared } from 'rax'; -import Leaf from './builtin-components/leaf'; -import Slot from './builtin-components/slot'; -import { host } from './host'; -import SimulatorRendererView from './renderer-view'; -import { raxFindDOMNodes } from './utils/find-dom-nodes'; -import { getClientRects } from './utils/get-client-rects'; -import loader from './utils/loader'; -import { parseQuery, withQueryParams } from './utils/url'; -import { IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; - -configure({ enforceActions: 'never' }); -const { Instance } = shared; - -export interface LibraryMap { - [key: string]: string; -} - -const SYMBOL_VNID = Symbol('_LCNodeId'); -const SYMBOL_VDID = Symbol('_LCDocId'); - -const INTERNAL = '_internal'; - -function accessLibrary(library: string | object) { - if (typeof library !== 'string') { - return library; - } - - return (window as any)[library]; -} - -// Slot/Leaf and Fragment|FunctionComponent polyfill(ref) - -const builtinComponents = { - Slot, - Leaf, -}; - -function buildComponents( - libraryMap: LibraryMap, - componentsMap: { [componentName: string]: IPublicTypeNpmInfo | ComponentType<any> | IPublicTypeComponentSchema }, - createComponent: (schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>) => Component | null, -) { - const components: any = { - ...builtinComponents, - }; - Object.keys(componentsMap).forEach((componentName) => { - let component = componentsMap[componentName]; - if (component && (isLowcodeProjectSchema(component) || isComponentSchema(component))) { - if (isComponentSchema(component)) { - components[componentName] = createComponent({ - version: '', - componentsMap: [], - componentsTree: [component], - }); - } else { - components[componentName] = createComponent(component); - } - } else if (isReactComponent(component)) { - components[componentName] = component; - } else { - component = findComponent(libraryMap, componentName, component as IPublicTypeNpmInfo); - if (component) { - components[componentName] = component; - } - } - }); - return components; -} - -let REACT_KEY = ''; -function cacheReactKey(el: Element): Element { - if (REACT_KEY !== '') { - return el; - } - // react17 采用 __reactFiber 开头 - REACT_KEY = Object.keys(el).find( - (key) => key.startsWith('__reactInternalInstance$') || key.startsWith('__reactFiber$'), - ) || ''; - if (!REACT_KEY && (el as HTMLElement).parentElement) { - return cacheReactKey((el as HTMLElement).parentElement!); - } - return el; -} - -function checkInstanceMounted(instance: any): boolean { - if (isElement(instance)) { - return instance.parentElement != null; - } - return true; -} - -function isValidDesignModeRaxComponentInstance( - raxComponentInst: any, -): raxComponentInst is { - props: { - _leaf: Exclude<IPublicTypeNodeInstance<any>['node'], null | undefined>; - }; -} { - const leaf = raxComponentInst?.props?._leaf; - return leaf && typeof leaf === 'object' && leaf.isNode; -} - -export class DocumentInstance { - private instancesMap = new Map<string, any[]>(); - - private emitter: IEventBus = createModuleEventBus('DocumentInstance'); - - get schema(): any { - return this.document.export(IPublicEnumTransformStage.Render); - } - - constructor(readonly container: SimulatorRendererContainer, readonly document: IDocumentModel) { - makeObservable(this); - } - - @computed get suspended(): any { - return false; - } - - @computed get scope(): any { - return null; - } - - get path(): string { - return `/${ this.document.fileName}`; - } - - get id() { - return this.document.id; - } - - private unmountIntance(id: string, instance: any) { - const instances = this.instancesMap.get(id); - if (instances) { - const i = instances.indexOf(instance); - if (i > -1) { - instances.splice(i, 1); - host.setInstance(this.document.id, id, instances); - } - } - } - - refresh() { - this.emitter.emit('rerender', { shouldRemount: true }); - } - - onReRender(fn: () => void) { - this.emitter.on('rerender', fn); - return () => { - this.emitter.removeListener('renderer', fn); - }; - } - - mountInstance(id: string, instance: any) { - const docId = this.document.id; - const { instancesMap } = this; - if (instance == null) { - let instances = this.instancesMap.get(id); - if (instances) { - instances = instances.filter(checkInstanceMounted); - if (instances.length > 0) { - instancesMap.set(id, instances); - host.setInstance(this.document.id, id, instances); - } else { - instancesMap.delete(id); - host.setInstance(this.document.id, id, null); - } - } - return; - } - const unmountIntance = this.unmountIntance.bind(this); - const origId = (instance as any)[SYMBOL_VNID]; - if (origId && origId !== id) { - // 另外一个节点的 instance 在此被复用了,需要从原来地方卸载 - unmountIntance(origId, instance); - } - if (isElement(instance)) { - cacheReactKey(instance); - } else if (origId !== id) { - // 涵盖 origId == null || origId !== id 的情况 - let origUnmount: any = instance.componentWillUnmount; - if (origUnmount && origUnmount.origUnmount) { - origUnmount = origUnmount.origUnmount; - } - // hack! delete instance from map - const newUnmount = function (this: any) { - unmountIntance(id, instance); - origUnmount && origUnmount.call(this); - }; - (newUnmount as any).origUnmount = origUnmount; - instance.componentWillUnmount = newUnmount; - } - - (instance as any)[SYMBOL_VNID] = id; - (instance as any)[SYMBOL_VDID] = docId; - let instances = this.instancesMap.get(id); - if (instances) { - const l = instances.length; - instances = instances.filter(checkInstanceMounted); - let updated = instances.length !== l; - if (!instances.includes(instance)) { - instances.push(instance); - updated = true; - } - if (!updated) { - return; - } - } else { - instances = [instance]; - } - instancesMap.set(id, instances); - host.setInstance(this.document.id, id, instances); - } - - mountContext(docId: string, id: string, ctx: object) { - // this.ctxMap.set(id, ctx); - } - - getComponentInstances(id: string): any[] | null { - return this.instancesMap.get(id) || null; - } - - getNode(id: string): IBaseNode<IPublicTypeNodeSchema> | null { - return this.document.getNode(id); - } -} - -export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { - readonly isSimulatorRenderer = true; - private dispose?: () => void; - readonly history: MemoryHistory; - - private emitter: IEventBus = createModuleEventBus('SimulatorRendererContainer'); - - @obx.ref private _documentInstances: DocumentInstance[] = []; - get documentInstances() { - return this._documentInstances; - } - - get currentDocumentInstance() { - return this._documentInstances.find((item) => item.id === host.project.currentDocument?.id); - } - - constructor() { - this.dispose = host.connect(this, () => { - // sync layout config - this._layout = host.project.get('config').layout; - // todo: split with others, not all should recompute - if (this._libraryMap !== host.libraryMap || this._componentsMap !== host.designer.componentsMap) { - this._libraryMap = host.libraryMap || {}; - this._componentsMap = host.designer.componentsMap; - this.buildComponents(); - } - - // sync designMode - this._designMode = host.designMode; - - this._locale = host.locale; - - // sync requestHandlersMap - this._requestHandlersMap = host.requestHandlersMap; - - // sync device - this._device = host.device; - - this.emitter.emit('layoutChange'); - }); - const documentInstanceMap = new Map<string, DocumentInstance>(); - let initialEntry = '/'; - let firstRun = true; - host.autorun(() => { - this._documentInstances = host.project.documents.map((doc) => { - let inst = documentInstanceMap.get(doc.id); - if (!inst) { - inst = new DocumentInstance(this, doc); - documentInstanceMap.set(doc.id, inst); - } - return inst; - }); - - const path = host.project.currentDocument ? documentInstanceMap.get(host.project.currentDocument.id)!.path : '/'; - if (firstRun) { - initialEntry = path; - firstRun = false; - } else { - if (this.history.location.pathname !== path) { - this.history.replace(path); - } - this.emitter.emit('layoutChange'); - } - }); - const history = createMemoryHistory({ - initialEntries: [initialEntry], - }); - this.history = history; - history.listen(({ location }) => { - host.project.open(location.pathname.slice(1)); - }); - host.componentsConsumer.consume(async (componentsAsset) => { - if (componentsAsset) { - await this.load(componentsAsset); - this.buildComponents(); - } - }); - this._appContext = { - utils: { - router: { - push(path: string, params?: object) { - history.push(withQueryParams(path, params)); - }, - replace(path: string, params?: object) { - history.replace(withQueryParams(path, params)); - }, - back() { - history.back(); - }, - }, - legaoBuiltins: { - getUrlParams() { - const { search } = history.location; - return parseQuery(search); - }, - }, - }, - constants: {}, - requestHandlersMap: this._requestHandlersMap, - }; - host.injectionConsumer.consume((data) => { - // sync utils, i18n, contants,... config - }); - } - - @obx private _layout: any = null; - @computed get layout(): any { - // TODO: parse layout Component - return this._layout; - } - set layout(value: any) { - this._layout = value; - } - - private _libraryMap: { [key: string]: string } = {}; - private buildComponents() { - // TODO: remove this.createComponent - this._components = buildComponents(this._libraryMap, this._componentsMap, this.createComponent.bind(this)); - } - @obx.ref private _components: Record<string, React.FC | React.ComponentClass> | null = {}; - @computed get components(): Record<string, React.FC | React.ComponentClass> { - // 根据 device 选择不同组件,进行响应式 - // 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl - return this._components || {}; - } - // context from: utils、constants、history、location、match - @obx.ref private _appContext = {}; - @computed get context(): any { - return this._appContext; - } - @obx.ref private _designMode: string = 'design'; - @computed get designMode(): any { - return this._designMode; - } - @obx.ref private _device: string = 'default'; - @computed get device() { - return this._device; - } - @obx.ref private _locale: string | undefined = undefined; - @computed get locale() { - return this._locale; - } - @obx.ref private _requestHandlersMap = null; - @computed get requestHandlersMap(): any { - return this._requestHandlersMap; - } - @obx.ref private _componentsMap = {}; - @computed get componentsMap(): any { - return this._componentsMap; - } - - /** - * 加载资源 - */ - load(asset: Asset): Promise<any> { - return loader.load(asset); - } - - async loadAsyncLibrary(asyncLibraryMap: Record<string, any>) { - } - - getComponent(componentName: string) { - const paths = componentName.split('.'); - const subs: string[] = []; - - while (true) { - const component = this._components?.[componentName]; - if (component) { - return getSubComponent(component, subs); - } - - const sub = paths.pop(); - if (!sub) { - return null; - } - subs.unshift(sub); - componentName = paths.join('.'); - } - } - - getNodeInstance(dom: HTMLElement): IPublicTypeNodeInstance<any> | null { - const INTERNAL = '_internal'; - let instance: any = dom; - if (!isElement(instance)) { - return { - docId: instance.props._leaf.document.id, - nodeId: instance.props._leaf.getId(), - instance, - node: instance.props._leaf, - }; - } - instance = Instance.get(dom); - - let loopNum = 0; // 防止由于某种意外而导致死循环 - while (instance && instance[INTERNAL] && loopNum < 1000) { - if (isValidDesignModeRaxComponentInstance(instance)) { - // if (instance && SYMBOL_VNID in instance) { - // const docId = (instance.props as any).schema.docId; - return { - docId: instance.props._leaf.document?.id || '', - nodeId: instance.props._leaf.getId(), - instance, - node: instance.props._leaf, - }; - } - - instance = getRaxVDomParentInstance(instance); - loopNum += 1; - } - - return null; - } - - getClosestNodeInstance(from: any, nodeId?: string): IPublicTypeNodeInstance<any> | null { - const el: any = from; - if (el) { - // if (isElement(el)) { - // el = cacheReactKey(el); - // } else { - // return getNodeInstance(el, specId); - // } - return this.getNodeInstance(el); - } - return null; - } - - findDOMNodes(instance: any, selector?: string): Array<Element | Text> | null { - let el = instance; - if (selector) { - el = document.querySelector(selector); - } - try { - return raxFindDOMNodes(el); - } catch (e) { - // ignore - } - if (el && el.type && el.props && el.props.componentId) { - el = document.querySelector(`${el.type}[componentid=${el.props.componentId}]`); - } else { - console.error(instance); - throw new Error('This instance may not a valid element'); - } - return raxFindDOMNodes(el); - } - - getClientRects(element: Element | Text) { - return getClientRects(element); - } - - setNativeSelection(enableFlag: boolean) { - setNativeSelection(enableFlag); - } - setDraggingState(state: boolean) { - cursor.setDragging(state); - } - setCopyState(state: boolean) { - cursor.setCopy(state); - } - clearState() { - cursor.release(); - } - - onLayoutChange(cb: () => void) { - this.emitter.on('layoutChange', cb); - return () => { - this.emitter.removeListener('layoutChange', cb); - }; - } - - onReRender(fn: () => void) { - this.emitter.on('rerender', fn); - return () => { - this.emitter.removeListener('renderer', fn); - }; - } - - rerender() { - this.currentDocumentInstance?.refresh(); - } - - stopAutoRepaintNode() { - } - - enableAutoRepaintNode() { - } - - createComponent(schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>): Component | null { - const _schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema> = { - ...schema, - componentsTree: schema.componentsTree.map(compatibleLegaoSchema), - }; - - const componentsTreeSchema = _schema.componentsTree[0]; - - if (componentsTreeSchema.componentName === 'Component' && componentsTreeSchema.css) { - const doc = window.document; - const s = doc.createElement('style'); - s.setAttribute('type', 'text/css'); - s.setAttribute('id', `Component-${componentsTreeSchema.id || ''}`); - s.appendChild(doc.createTextNode(componentsTreeSchema.css || '')); - doc.getElementsByTagName('head')[0].appendChild(s); - } - - const renderer = this; - const { componentsMap: components } = renderer; - - class LowCodeComp extends Rax.Component { - render() { - const extraProps = getLowCodeComponentProps(this.props); - // @ts-ignore - return createElement(LowCodeRenderer, { - ...extraProps, - schema: componentsTreeSchema, - components, - designMode: '', - locale: renderer.locale, - messages: _schema.i18n || {}, - device: renderer.device, - appHelper: renderer.context, - rendererName: 'LowCodeRenderer', - thisRequiredInJSE: host.thisRequiredInJSE, - customCreateElement: (Comp: any, props: any, children: any) => { - const componentMeta = host.currentDocument?.getComponentMeta(Comp.displayName); - if (componentMeta?.isModal) { - return null; - } - - const { __id, __designMode, ...viewProps } = props; - // mock _leaf,减少性能开销 - const _leaf = { - isEmpty: () => false, - isMock: true, - }; - viewProps._leaf = _leaf; - return createElement(Comp, viewProps, children); - }, - }); - } - } - - return LowCodeComp; - } - - private _running = false; - run() { - if (this._running) { - return; - } - this._running = true; - const containerId = 'app'; - let container = document.getElementById(containerId); - if (!container) { - container = document.createElement('div'); - document.body.appendChild(container); - container.id = containerId; - } - - // ==== compatiable vision - document.documentElement.classList.add('engine-page'); - document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends - - raxRender(createElement(SimulatorRendererView, { - rendererContainer: this, - }), container, { - driver: DriverUniversal, - }); - host.project.setRendererReady(this); - } -} - -function getSubComponent(library: any, paths: string[]) { - const l = paths.length; - if (l < 1 || !library) { - return library; - } - let i = 0; - let component: any; - while (i < l) { - const key = paths[i]!; - let ex: any; - try { - component = library[key]; - } catch (e) { - ex = e; - component = null; - } - if (i === 0 && component == null && key === 'default') { - if (ex) { - return l === 1 ? library : null; - } - component = library; - } else if (component == null) { - return null; - } - library = component; - i++; - } - return component; -} - -function findComponent(libraryMap: LibraryMap, componentName: string, npm?: IPublicTypeNpmInfo) { - if (!npm) { - return accessLibrary(componentName); - } - // libraryName the key access to global - // export { exportName } from xxx exportName === global.libraryName.exportName - // export exportName from xxx exportName === global.libraryName.default || global.libraryName - // export { exportName as componentName } from package - // if exportName == null exportName === componentName; - // const componentName = exportName.subName, if exportName empty subName donot use - const exportName = npm.exportName || npm.componentName || componentName; - const libraryName = libraryMap[npm.package] || exportName; - const library = accessLibrary(libraryName); - const paths = npm.exportName && npm.subName ? npm.subName.split('.') : []; - if (npm.destructuring) { - paths.unshift(exportName); - } else if (isESModule(library)) { - paths.unshift('default'); - } - return getSubComponent(library, paths); -} - -function getLowCodeComponentProps(props: any) { - if (!props || !isPlainObject(props)) { - return props; - } - const newProps: any = {}; - Object.keys(props).forEach(k => { - if (['children', 'componentId', '__designMode', '_componentName', '_leaf'].includes(k)) { - return; - } - newProps[k] = props[k]; - }); - return newProps; -} - -/** - * 获取 Rax 里面 VDOM 的上一级的实例 - * 注意:Rax 的 development 的包是带有 __parentInstance, - * 但是 production 的包 __parentInstance 会被压缩掉, - * 所以这里遍历下其中的所有值,尝试找到有 _internal 的那个(别的值不会带有这个属性的) - */ -function getRaxVDomParentInstance(instance: { _internal: any }) { - const internalInstance = instance._internal; - return internalInstance.__parentInstance || - Object.values(internalInstance).find(v => ( - v !== null && - v !== instance && - typeof v === 'object' && - typeof (v as {_internal: unknown})._internal === 'object' - )); -} - -export default new SimulatorRendererContainer(); diff --git a/packages/rax-simulator-renderer/src/utils/create-defer.ts b/packages/rax-simulator-renderer/src/utils/create-defer.ts deleted file mode 100644 index e7997365a0..0000000000 --- a/packages/rax-simulator-renderer/src/utils/create-defer.ts +++ /dev/null @@ -1,17 +0,0 @@ -export interface Defer<T = any> { - resolve(value?: T | PromiseLike<T>): void; - reject(reason?: any): void; - promise(): Promise<T>; -} - -export function createDefer<T = any>(): Defer<T> { - const r: any = {}; - const promise = new Promise<T>((resolve, reject) => { - r.resolve = resolve; - r.reject = reject; - }); - - r.promise = () => promise; - - return r; -} diff --git a/packages/rax-simulator-renderer/src/utils/find-dom-nodes.ts b/packages/rax-simulator-renderer/src/utils/find-dom-nodes.ts deleted file mode 100644 index 106af2efac..0000000000 --- a/packages/rax-simulator-renderer/src/utils/find-dom-nodes.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { isElement } from '@alilc/lowcode-utils'; -import findDOMNode from 'rax-find-dom-node'; -// import { isDOMNode } from './is-dom-node'; - -export function raxFindDOMNodes(instance: any): Array<Element | Text> | null { - if (!instance) { - return null; - } - if (isElement(instance)) { - return [instance]; - } - // eslint-disable-next-line react/no-find-dom-node - const result = findDOMNode(instance); - if (Array.isArray(result)) { - return result; - } - return [result]; -} diff --git a/packages/rax-simulator-renderer/src/utils/get-client-rects.ts b/packages/rax-simulator-renderer/src/utils/get-client-rects.ts deleted file mode 100644 index dd13aba81e..0000000000 --- a/packages/rax-simulator-renderer/src/utils/get-client-rects.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { isElement } from '@alilc/lowcode-utils'; - -// a range for test TextNode clientRect -const cycleRange = document.createRange(); - -export function getClientRects(node: Element | Text) { - if (isElement(node)) { - return [node.getBoundingClientRect()]; - } - - cycleRange.selectNode(node); - return Array.from(cycleRange.getClientRects()); -} diff --git a/packages/rax-simulator-renderer/src/utils/get-closest-node-instance.ts b/packages/rax-simulator-renderer/src/utils/get-closest-node-instance.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/rax-simulator-renderer/src/utils/get-device-view.ts b/packages/rax-simulator-renderer/src/utils/get-device-view.ts deleted file mode 100644 index 9005562599..0000000000 --- a/packages/rax-simulator-renderer/src/utils/get-device-view.ts +++ /dev/null @@ -1,23 +0,0 @@ -function ucfirst(s: string) { - return s.charAt(0).toUpperCase() + s.substring(1); -} -function getDeviceView(view: any, device: string, mode: string) { - if (!view || typeof view === 'string') { - return view; - } - - // compatible vision Mobile | Preview - device = ucfirst(device); - if (device === 'Mobile' && view.hasOwnProperty(device)) { - view = view[device]; - } - mode = ucfirst(mode); - if (mode === 'Preview' && view.hasOwnProperty(mode)) { - view = view[mode]; - } - return view; -} - -export default { - getDeviceView, -}; diff --git a/packages/rax-simulator-renderer/src/utils/is-dom-node.ts b/packages/rax-simulator-renderer/src/utils/is-dom-node.ts deleted file mode 100644 index bfbeb79c1f..0000000000 --- a/packages/rax-simulator-renderer/src/utils/is-dom-node.ts +++ /dev/null @@ -1,4 +0,0 @@ -export function isDOMNode(node: any): node is Element | Text { - if (!node) return false; - return node.nodeType && (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE); -} diff --git a/packages/rax-simulator-renderer/src/utils/loader.ts b/packages/rax-simulator-renderer/src/utils/loader.ts deleted file mode 100644 index 436e51c441..0000000000 --- a/packages/rax-simulator-renderer/src/utils/loader.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { load, evaluate } from './script'; -import StylePoint from './style'; -import { - Asset, - AssetLevel, - AssetLevels, - AssetType, - AssetList, - isAssetBundle, - isAssetItem, - assetItem, - AssetItem, - isCSSUrl, -} from '@alilc/lowcode-utils'; - -function parseAssetList(scripts: any, styles: any, assets: AssetList, level?: AssetLevel) { - for (const asset of assets) { - parseAsset(scripts, styles, asset, level); - } -} - -function parseAsset(scripts: any, styles: any, asset: Asset | undefined | null, level?: AssetLevel) { - if (!asset) { - return; - } - if (Array.isArray(asset)) { - return parseAssetList(scripts, styles, asset, level); - } - - if (isAssetBundle(asset)) { - if (asset.assets) { - if (Array.isArray(asset.assets)) { - parseAssetList(scripts, styles, asset.assets, asset.level || level); - } else { - parseAsset(scripts, styles, asset.assets, asset.level || level); - } - return; - } - return; - } - - if (!isAssetItem(asset)) { - asset = assetItem(isCSSUrl(asset) ? AssetType.CSSUrl : AssetType.JSUrl, asset, level)!; - } - - let lv = asset.level || level; - - if (!lv || AssetLevel[lv] == null) { - lv = AssetLevel.App; - } - - asset.level = lv; - if (asset.type === AssetType.CSSUrl || asset.type == AssetType.CSSText) { - styles[lv].push(asset); - } else { - scripts[lv].push(asset); - } -} - -export class AssetLoader { - async load(asset: Asset) { - const styles: any = {}; - const scripts: any = {}; - AssetLevels.forEach(lv => { - styles[lv] = []; - scripts[lv] = []; - }); - parseAsset(scripts, styles, asset); - const styleQueue: AssetItem[] = styles[AssetLevel.Environment].concat( - styles[AssetLevel.Library], - styles[AssetLevel.Theme], - styles[AssetLevel.Runtime], - styles[AssetLevel.App], - ); - const scriptQueue: AssetItem[] = scripts[AssetLevel.Environment].concat( - scripts[AssetLevel.Library], - scripts[AssetLevel.Theme], - scripts[AssetLevel.Runtime], - scripts[AssetLevel.App], - ); - await Promise.all( - styleQueue.map(({ content, level, type, id }) => this.loadStyle(content, level!, type === AssetType.CSSUrl, id)), - ); - await Promise.all(scriptQueue.map(({ content, type }) => this.loadScript(content, type === AssetType.JSUrl))); - } - - private stylePoints = new Map<string, StylePoint>(); - - private loadStyle(content: string | undefined | null, level: AssetLevel, isUrl?: boolean, id?: string) { - if (!content) { - return; - } - let point: StylePoint | undefined; - if (id) { - point = this.stylePoints.get(id); - if (!point) { - point = new StylePoint(level, id); - this.stylePoints.set(id, point); - } - } else { - point = new StylePoint(level); - } - return isUrl ? point.applyUrl(content) : point.applyText(content); - } - - private loadScript(content: string | undefined | null, isUrl?: boolean) { - if (!content) { - return; - } - return isUrl ? load(content) : evaluate(content); - } -} - -export default new AssetLoader(); diff --git a/packages/rax-simulator-renderer/src/utils/script.ts b/packages/rax-simulator-renderer/src/utils/script.ts deleted file mode 100644 index 81841ff6d2..0000000000 --- a/packages/rax-simulator-renderer/src/utils/script.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { createDefer } from './create-defer'; - -export function evaluate(script: string) { - const scriptEl = document.createElement('script'); - scriptEl.text = script; - document.head.appendChild(scriptEl); - document.head.removeChild(scriptEl); -} - -export function load(url: string) { - const node: any = document.createElement('script'); - - // node.setAttribute('crossorigin', 'anonymous'); - - node.onload = onload; - node.onerror = onload; - - const i = createDefer(); - - function onload(e: any) { - node.onload = null; - node.onerror = null; - if (e.type === 'load') { - i.resolve(); - } else { - i.reject(); - } - // document.head.removeChild(node); - // node = null; - } - - // node.async = true; - node.src = url; - - document.head.appendChild(node); - - return i.promise(); -} - -export function evaluateExpression(expr: string) { - // eslint-disable-next-line no-new-func - const fn = new Function(expr); - return fn(); -} - -export function newFunction(args: string, code: string) { - try { - // eslint-disable-next-line no-new-func - return new Function(args, code); - } catch (e) { - console.warn('Caught error, Cant init func'); - return null; - } -} diff --git a/packages/rax-simulator-renderer/src/utils/style.ts b/packages/rax-simulator-renderer/src/utils/style.ts deleted file mode 100644 index 91dbbc6345..0000000000 --- a/packages/rax-simulator-renderer/src/utils/style.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { createDefer } from './create-defer'; - -export default class StylePoint { - private lastContent: string | undefined; - - private lastUrl: string | undefined; - - private placeholder: Element | Text; - - constructor(readonly level: number, readonly id?: string) { - let placeholder: any; - if (id) { - placeholder = document.head.querySelector(`style[data-id="${id}"]`); - } - if (!placeholder) { - placeholder = document.createTextNode(''); - const meta = document.head.querySelector(`meta[level="${level}"]`); - if (meta) { - document.head.insertBefore(placeholder, meta); - } else { - document.head.appendChild(placeholder); - } - } - this.placeholder = placeholder; - } - - applyText(content: string) { - if (this.lastContent === content) { - return; - } - this.lastContent = content; - this.lastUrl = undefined; - const element = document.createElement('style'); - element.setAttribute('type', 'text/css'); - if (this.id) { - element.setAttribute('data-id', this.id); - } - element.appendChild(document.createTextNode(content)); - document.head.insertBefore(element, this.placeholder.parentNode === document.head ? this.placeholder.nextSibling : null); - document.head.removeChild(this.placeholder); - this.placeholder = element; - } - - applyUrl(url: string) { - if (this.lastUrl === url) { - return; - } - this.lastContent = undefined; - this.lastUrl = url; - const element = document.createElement('link'); - element.onload = onload; - element.onerror = onload; - - const i = createDefer(); - function onload(e: any) { - element.onload = null; - element.onerror = null; - if (e.type === 'load') { - i.resolve(); - } else { - i.reject(); - } - } - - element.href = url; - element.rel = 'stylesheet'; - if (this.id) { - element.setAttribute('data-id', this.id); - } - document.head.insertBefore(element, this.placeholder.parentNode === document.head ? this.placeholder.nextSibling : null); - document.head.removeChild(this.placeholder); - this.placeholder = element; - return i.promise(); - } -} diff --git a/packages/rax-simulator-renderer/src/utils/url.ts b/packages/rax-simulator-renderer/src/utils/url.ts deleted file mode 100644 index d720323b3a..0000000000 --- a/packages/rax-simulator-renderer/src/utils/url.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Parse queryString - * @param {String} str '?q=query&b=test' - * @return {Object} - */ -export function parseQuery(str: string): object { - const ret: any = {}; - - if (typeof str !== 'string') { - return ret; - } - - const s = str.trim().replace(/^(\?|#|&)/, ''); - - if (!s) { - return ret; - } - - s.split('&').forEach((param) => { - const parts = param.replace(/\+/g, ' ').split('='); - let key = parts.shift()!; - let val: any = parts.length > 0 ? parts.join('=') : undefined; - - key = decodeURIComponent(key); - - val = val === undefined ? null : decodeURIComponent(val); - - if (ret[key] === undefined) { - ret[key] = val; - } else if (Array.isArray(ret[key])) { - ret[key].push(val); - } else { - ret[key] = [ret[key], val]; - } - }); - - return ret; -} - -/** - * Stringify object to query parammeters - * @param {Object} obj - * @return {String} - */ -export function stringifyQuery(obj: any): string { - const param: string[] = []; - Object.keys(obj).forEach((key) => { - let value = obj[key]; - if (value && typeof value === 'object') { - value = JSON.stringify(value); - } - param.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`); - }); - return param.join('&'); -} - -export function uriEncode(uri: string) { - return encodeURIComponent(uri); -} - -export function uriDecode(uri: string) { - return decodeURIComponent(uri); -} - -export function withQueryParams(url: string, params?: object) { - const queryStr = params ? stringifyQuery(params) : ''; - if (queryStr === '') { - return url; - } - const urlSplit = url.split('#'); - const hash = urlSplit[1] ? `#${urlSplit[1]}` : ''; - const urlWithoutHash = urlSplit[0]; - return `${urlWithoutHash}${~urlWithoutHash.indexOf('?') ? '&' : '?'}${queryStr}${hash}`; -} diff --git a/packages/renderer-core/src/adapter/index.ts b/packages/renderer-core/src/adapter/index.ts index 12896b1372..7a56bc039e 100644 --- a/packages/renderer-core/src/adapter/index.ts +++ b/packages/renderer-core/src/adapter/index.ts @@ -2,7 +2,6 @@ import { IRuntime, IRendererModules, IGeneralConstructor } from '../types'; export enum Env { React = 'react', - Rax = 'rax', } class Adapter { @@ -22,22 +21,22 @@ class Adapter { initRuntime() { const Component: IGeneralConstructor = class <T = any, S = any> { - setState() {} - forceUpdate() {} - render() {} state: Readonly<S>; props: Readonly<T> & Readonly<{ children?: any | undefined }>; refs: Record<string, unknown>; context: Record<string, unknown>; - }; - const PureComponent = class <T = any, S = any> { setState() {} forceUpdate() {} render() {} + }; + const PureComponent = class <T = any, S = any> { state: Readonly<S>; props: Readonly<T> & Readonly<{ children?: any | undefined }>; refs: Record<string, unknown>; context: Record<string, unknown>; + setState() {} + forceUpdate() {} + render() {} }; const createElement = () => {}; const createContext = () => {}; @@ -85,10 +84,6 @@ class Adapter { return this.env === Env.React; } - isRax() { - return this.env === Env.Rax; - } - setRenderers(renderers: IRendererModules) { this.renderers = renderers; } diff --git a/packages/renderer-core/tests/adapter/adapter.test.ts b/packages/renderer-core/tests/adapter/adapter.test.ts index a838602fbe..57d92d1d42 100644 --- a/packages/renderer-core/tests/adapter/adapter.test.ts +++ b/packages/renderer-core/tests/adapter/adapter.test.ts @@ -79,15 +79,10 @@ describe('test src/adapter ', () => { }); - it('setEnv/.env/isReact/isRax works', () => { + it('setEnv/.env/isReact works', () => { adapter.setEnv(Env.React); expect(adapter.env).toBe(Env.React); expect(adapter.isReact()).toBeTruthy(); - expect(adapter.isRax()).toBeFalsy(); - adapter.setEnv(Env.Rax); - expect(adapter.env).toBe(Env.Rax); - expect(adapter.isRax()).toBeTruthy(); - expect(adapter.isReact()).toBeFalsy(); }); it('setRenderers/getRenderers works', () => { diff --git a/packages/types/src/shell/type/engine-options.ts b/packages/types/src/shell/type/engine-options.ts index b570d1990a..72078c8107 100644 --- a/packages/types/src/shell/type/engine-options.ts +++ b/packages/types/src/shell/type/engine-options.ts @@ -41,7 +41,7 @@ export interface IPublicTypeEngineOptions { /** * 渲染器类型,默认值:'react' */ - renderEnv?: 'react' | 'rax' | string; + renderEnv?: 'react' | string; /** * 设备类型映射器,处理设计器与渲染器中 device 的映射 diff --git a/scripts/build.sh b/scripts/build.sh index 92b0a99c23..0d96598e62 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -9,8 +9,6 @@ lerna run build \ --scope @alilc/lowcode-designer \ --scope @alilc/lowcode-plugin-designer \ --scope @alilc/lowcode-plugin-outline-pane \ - --scope @alilc/lowcode-rax-renderer \ - --scope @alilc/lowcode-rax-simulator-renderer \ --scope @alilc/lowcode-react-renderer \ --scope @alilc/lowcode-react-simulator-renderer \ --scope @alilc/lowcode-renderer-core \ @@ -20,13 +18,9 @@ lerna run build \ lerna run build:umd \ --scope @alilc/lowcode-engine \ - --scope @alilc/lowcode-rax-simulator-renderer \ --scope @alilc/lowcode-react-simulator-renderer \ --scope @alilc/lowcode-react-renderer \ --stream cp ./packages/react-simulator-renderer/dist/js/* ./packages/engine/dist/js/ cp ./packages/react-simulator-renderer/dist/css/* ./packages/engine/dist/css/ - -cp ./packages/rax-simulator-renderer/dist/js/* ./packages/engine/dist/js/ -cp ./packages/rax-simulator-renderer/dist/css/* ./packages/engine/dist/css/ \ No newline at end of file diff --git a/scripts/sync.sh b/scripts/sync.sh index 98895c7234..e9840eeca6 100755 --- a/scripts/sync.sh +++ b/scripts/sync.sh @@ -10,8 +10,6 @@ tnpm sync @alilc/lowcode-designer tnpm sync @alilc/lowcode-plugin-designer tnpm sync @alilc/lowcode-plugin-outline-pane tnpm sync @alilc/lowcode-renderer-core -tnpm sync @alilc/lowcode-rax-renderer -tnpm sync @alilc/lowcode-rax-simulator-renderer tnpm sync @alilc/lowcode-react-renderer tnpm sync @alilc/lowcode-react-simulator-renderer tnpm sync @alilc/lowcode-engine From d47c2d2f91a57aa4f19fa5bbc8b1dfb3ded88da9 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 5 Jan 2024 08:09:04 +0000 Subject: [PATCH 409/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 4d6ef0a770..6659eaf853 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.18", + "version": "1.2.19", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 1b00c61a32027084e531a0ffacb2a9a2020fbcbf Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 8 Jan 2024 14:46:27 +0800 Subject: [PATCH 410/469] feat(engine): add context menu --- .gitignore | 2 + docs/docs/api/commonUI.md | 20 ++ docs/docs/api/configOptions.md | 6 + docs/docs/guide/expand/editor/theme.md | 1 + .../designer/src/context-menu-actions.scss | 10 + packages/designer/src/context-menu-actions.ts | 145 +++++++++++++++ packages/designer/src/designer/designer.ts | 11 +- packages/designer/src/index.ts | 1 + packages/editor-core/src/config.ts | 5 + packages/engine/src/engine-core.ts | 3 + .../src/inner-plugins/default-context-menu.ts | 172 ++++++++++++++++++ packages/engine/src/locale/en-US.json | 9 + packages/engine/src/locale/index.ts | 14 ++ packages/engine/src/locale/zh-CN.json | 9 + packages/shell/src/api/commonUI.ts | 4 + packages/shell/src/api/material.ts | 14 ++ .../shell/src/components/context-menu.tsx | 46 +++++ packages/types/src/shell/api/commonUI.ts | 8 +- packages/types/src/shell/api/material.ts | 20 +- packages/types/src/shell/enum/context-menu.ts | 7 + packages/types/src/shell/enum/index.ts | 3 +- packages/types/src/shell/type/context-menu.ts | 57 ++++++ .../types/src/shell/type/engine-options.ts | 6 + packages/types/src/shell/type/index.ts | 3 +- packages/utils/src/context-menu.scss | 33 ++++ packages/utils/src/context-menu.tsx | 138 ++++++++++++++ packages/utils/src/index.ts | 1 + 27 files changed, 743 insertions(+), 5 deletions(-) create mode 100644 packages/designer/src/context-menu-actions.scss create mode 100644 packages/designer/src/context-menu-actions.ts create mode 100644 packages/engine/src/inner-plugins/default-context-menu.ts create mode 100644 packages/engine/src/locale/en-US.json create mode 100644 packages/engine/src/locale/index.ts create mode 100644 packages/engine/src/locale/zh-CN.json create mode 100644 packages/shell/src/components/context-menu.tsx create mode 100644 packages/types/src/shell/enum/context-menu.ts create mode 100644 packages/types/src/shell/type/context-menu.ts create mode 100644 packages/utils/src/context-menu.scss create mode 100644 packages/utils/src/context-menu.tsx diff --git a/.gitignore b/.gitignore index 05159f0473..6a19ae3e0c 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,5 @@ typings/ # codealike codealike.json .node + +.must.config.js \ No newline at end of file diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md index 9d1f706520..ef7af7f415 100644 --- a/docs/docs/api/commonUI.md +++ b/docs/docs/api/commonUI.md @@ -29,6 +29,26 @@ CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开 | className | className | string (optional) | | | onClick | 点击事件 | () => void (optional) | | +### ContextMenu + +| 参数 | 说明 | 类型 | 默认值 | +|--------|----------------------------------------------------|------------------------------------|--------| +| menus | 定义上下文菜单的动作数组 | IPublicTypeContextMenuAction[] | | +| children | 组件的子元素 | React.ReactElement[] | | + +**IPublicTypeContextMenuAction Interface** + +| 参数 | 说明 | 类型 | 默认值 | +|------------|--------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|----------------------------------------| +| name | 动作的唯一标识符<br>Unique identifier for the action | string | | +| title | 显示的标题,可以是字符串或国际化数据<br>Display title, can be a string or internationalized data | string \| IPublicTypeI18nData (optional) | | +| type | 菜单项类型<br>Menu item type | IPublicEnumContextMenuType (optional) | IPublicEnumPContextMenuType.MENU_ITEM | +| action | 点击时执行的动作,可选<br>Action to execute on click, optional | (nodes: IPublicModelNode[]) => void (optional) | | +| items | 子菜单项或生成子节点的函数,可选,仅支持两级<br>Sub-menu items or function to generate child node, optional | Omit<IPublicTypeContextMenuAction, 'items'>[] \| ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]) (optional) | | +| condition | 显示条件函数<br>Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | | +| disabled | 禁用条件函数,可选<br>Function to determine disabled condition, optional | (nodes: IPublicModelNode[]) => boolean (optional) | | + + ### Balloon 详细文档: [Balloon Documentation](https://fusion.design/pc/component/balloon) diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md index 5f6ade710f..67d2fae2c1 100644 --- a/docs/docs/api/configOptions.md +++ b/docs/docs/api/configOptions.md @@ -185,6 +185,12 @@ config.set('enableCondition', false) `@type {boolean}` `@default {false}` +#### enableContextMenu - 开启右键菜单 + +`@type {boolean}` `@default {false}` + +是否开启右键菜单 + #### disableDetecting `@type {boolean}` `@default {false}` diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index ef0e04d28d..1c442c5132 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -128,6 +128,7 @@ sidebar_position: 9 - `--pane-title-height`: 面板标题高度 - `--pane-title-font-size`: 面板标题字体大小 - `--pane-title-padding`: 面板标题边距 +- `--context-menu-item-height`: 右键菜单项高度 diff --git a/packages/designer/src/context-menu-actions.scss b/packages/designer/src/context-menu-actions.scss new file mode 100644 index 0000000000..863c929447 --- /dev/null +++ b/packages/designer/src/context-menu-actions.scss @@ -0,0 +1,10 @@ +.engine-context-menu { + &.next-menu.next-ver .next-menu-item { + padding-right: 30px; + + .next-menu-item-inner { + height: var(--context-menu-item-height, 30px); + line-height: var(--context-menu-item-height, 30px); + } + } +} \ No newline at end of file diff --git a/packages/designer/src/context-menu-actions.ts b/packages/designer/src/context-menu-actions.ts new file mode 100644 index 0000000000..053e4f0313 --- /dev/null +++ b/packages/designer/src/context-menu-actions.ts @@ -0,0 +1,145 @@ +import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial } from '@alilc/lowcode-types'; +import { IDesigner, INode } from './designer'; +import { parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; +import { Menu } from '@alifd/next'; +import { engineConfig } from '@alilc/lowcode-editor-core'; +import './context-menu-actions.scss'; + +export interface IContextMenuActions { + actions: IPublicTypeContextMenuAction[]; + + adjustMenuLayoutFn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]; + + addMenuAction: IPublicApiMaterial['addContextMenuOption']; + + removeMenuAction: IPublicApiMaterial['removeContextMenuOption']; + + adjustMenuLayout: IPublicApiMaterial['adjustContextMenuLayout']; +} + +export class ContextMenuActions implements IContextMenuActions { + actions: IPublicTypeContextMenuAction[] = []; + + designer: IDesigner; + + dispose: Function[]; + + enableContextMenu: boolean; + + constructor(designer: IDesigner) { + this.designer = designer; + this.dispose = []; + + engineConfig.onGot('enableContextMenu', (enable) => { + if (this.enableContextMenu === enable) { + return; + } + this.enableContextMenu = enable; + this.dispose.forEach(d => d()); + if (enable) { + this.initEvent(); + } + }); + } + + handleContextMenu = ( + nodes: INode[], + event: MouseEvent, + ) => { + const designer = this.designer; + event.stopPropagation(); + event.preventDefault(); + + const actions = designer.contextMenuActions.actions; + + const { bounds } = designer.project.simulator?.viewport || { bounds: { left: 0, top: 0 } }; + const { left: simulatorLeft, top: simulatorTop } = bounds; + + let destroyFn: Function | undefined; + + const destroy = () => { + destroyFn?.(); + }; + + const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, { + nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!), + destroy, + }); + + if (!menus.length) { + return; + } + + const layoutMenu = designer.contextMenuActions.adjustMenuLayoutFn(menus); + + const menuNode = parseContextMenuAsReactNode(layoutMenu, { + destroy, + nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!), + designer, + }); + + const target = event.target; + + const { top, left } = target?.getBoundingClientRect(); + + const menuInstance = Menu.create({ + target: event.target, + offset: [event.clientX - left + simulatorLeft, event.clientY - top + simulatorTop], + children: menuNode, + className: 'engine-context-menu', + }); + + destroyFn = (menuInstance as any).destroy; + }; + + initEvent() { + const designer = this.designer; + this.dispose.push( + designer.editor.eventBus.on('designer.builtinSimulator.contextmenu', ({ + node, + originalEvent, + }: { + node: INode; + originalEvent: MouseEvent; + }) => { + // 如果右键的节点不在 当前选中的节点中,选中该节点 + if (!designer.currentSelection.has(node.id)) { + designer.currentSelection.select(node.id); + } + const nodes = designer.currentSelection.getNodes(); + this.handleContextMenu(nodes, originalEvent); + }), + (() => { + const handleContextMenu = (e: MouseEvent) => { + this.handleContextMenu([], e); + }; + + document.addEventListener('contextmenu', handleContextMenu); + + return () => { + document.removeEventListener('contextmenu', handleContextMenu); + }; + })(), + ); + } + + adjustMenuLayoutFn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[] = (actions) => actions; + + addMenuAction(action: IPublicTypeContextMenuAction) { + this.actions.push({ + type: IPublicEnumContextMenuType.MENU_ITEM, + ...action, + }); + } + + removeMenuAction(name: string) { + const i = this.actions.findIndex((action) => action.name === name); + if (i > -1) { + this.actions.splice(i, 1); + } + } + + adjustMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]) { + this.adjustMenuLayoutFn = fn; + } +} \ No newline at end of file diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index d7e17e84ca..1dd4bc04e6 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -20,7 +20,7 @@ import { } from '@alilc/lowcode-types'; import { mergeAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils'; import { IProject, Project } from '../project'; -import { Node, DocumentModel, insertChildren, INode } from '../document'; +import { Node, DocumentModel, insertChildren, INode, ISelection } from '../document'; import { ComponentMeta, IComponentMeta } from '../component-meta'; import { INodeSelector, Component } from '../simulator'; import { Scroller } from './scroller'; @@ -32,6 +32,7 @@ import { OffsetObserver, createOffsetObserver } from './offset-observer'; import { ISettingTopEntry, SettingTopEntry } from './setting'; import { BemToolsManager } from '../builtin-simulator/bem-tools/manager'; import { ComponentActions } from '../component-actions'; +import { ContextMenuActions, IContextMenuActions } from '../context-menu-actions'; const logger = new Logger({ level: 'warn', bizName: 'designer' }); @@ -72,12 +73,16 @@ export interface IDesigner { get componentActions(): ComponentActions; + get contextMenuActions(): ContextMenuActions; + get editor(): IPublicModelEditor; get detecting(): Detecting; get simulatorComponent(): ComponentType<any> | undefined; + get currentSelection(): ISelection; + createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller; refreshComponentMetasMap(): void; @@ -122,6 +127,8 @@ export class Designer implements IDesigner { readonly componentActions = new ComponentActions(); + readonly contextMenuActions: IContextMenuActions; + readonly activeTracker = new ActiveTracker(); readonly detecting = new Detecting(); @@ -198,6 +205,8 @@ export class Designer implements IDesigner { this.postEvent('dragstart', e); }); + this.contextMenuActions = new ContextMenuActions(this); + this.dragon.onDrag((e) => { if (this.props?.onDrag) { this.props.onDrag(e); diff --git a/packages/designer/src/index.ts b/packages/designer/src/index.ts index 489d81482f..11e6453b8a 100644 --- a/packages/designer/src/index.ts +++ b/packages/designer/src/index.ts @@ -6,3 +6,4 @@ export * from './project'; export * from './builtin-simulator'; export * from './plugin'; export * from './types'; +export * from './context-menu-actions'; diff --git a/packages/editor-core/src/config.ts b/packages/editor-core/src/config.ts index a5da74742d..c4ff407b9a 100644 --- a/packages/editor-core/src/config.ts +++ b/packages/editor-core/src/config.ts @@ -159,6 +159,11 @@ const VALID_ENGINE_OPTIONS = { type: 'function', description: '应用级设计模式下,窗口为空时展示的占位组件', }, + enableContextMenu: { + type: 'boolean', + description: '是否开启右键菜单', + default: false, + }, hideComponentAction: { type: 'boolean', description: '是否隐藏设计器辅助层', diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 9f29046fbe..29b4a7f038 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -62,6 +62,7 @@ import { setterRegistry } from './inner-plugins/setter-registry'; import { defaultPanelRegistry } from './inner-plugins/default-panel-registry'; import { shellModelFactory } from './modules/shell-model-factory'; import { builtinHotkey } from './inner-plugins/builtin-hotkey'; +import { defaultContextMenu } from './inner-plugins/default-context-menu'; import { OutlinePlugin } from '@alilc/lowcode-plugin-outline-pane'; export * from './modules/skeleton-types'; @@ -78,6 +79,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins await plugins.register(defaultPanelRegistryPlugin); await plugins.register(builtinHotkey); await plugins.register(registerDefaults, {}, { autoInit: true }); + await plugins.register(defaultContextMenu); return () => { plugins.delete(OutlinePlugin.pluginName); @@ -86,6 +88,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins plugins.delete(defaultPanelRegistryPlugin.pluginName); plugins.delete(builtinHotkey.pluginName); plugins.delete(registerDefaults.pluginName); + plugins.delete(defaultContextMenu.pluginName); }; } diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts new file mode 100644 index 0000000000..86feb17d97 --- /dev/null +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -0,0 +1,172 @@ +import { + IPublicEnumContextMenuType, + IPublicEnumTransformStage, + IPublicModelNode, + IPublicModelPluginContext, + IPublicTypeNodeSchema, +} from '@alilc/lowcode-types'; +import { isProjectSchema } from '@alilc/lowcode-utils'; +import { Notification } from '@alifd/next'; +import { intl } from '../locale'; + +function getNodesSchema(nodes: IPublicModelNode[]) { + const componentsTree = nodes.map((node) => node?.exportSchema(IPublicEnumTransformStage.Clone)); + const data = { type: 'nodeSchema', componentsMap: {}, componentsTree }; + return data; +} + +async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> { + return new Promise((resolve, reject) => { + // 使用 Clipboard API 读取剪贴板内容 + navigator.clipboard.readText().then( + (text) => { + try { + const data = JSON.parse(text); + if (isProjectSchema(data)) { + resolve(data.componentsTree); + } else { + Notification.open({ + content: intl('NotValidNodeData'), + type: 'error', + }); + reject( + new Error(intl('NotValidNodeData')), + ); + } + } catch (error) { + Notification.open({ + content: intl('NotValidNodeData'), + type: 'error', + }); + reject(error); + } + }, + (err) => { + reject(err); + }, + ); + }); +} + +export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { + const { material, canvas } = ctx; + const { clipboard } = canvas; + + return { + init() { + material.addContextMenuOption({ + name: 'selectComponent', + title: intl('SelectComponents'), + condition: (nodes) => { + return nodes.length === 1; + }, + items: [ + { + name: 'nodeTree', + type: IPublicEnumContextMenuType.NODE_TREE, + }, + ], + }); + + material.addContextMenuOption({ + name: 'copyAndPaste', + title: intl('Copy'), + condition: (nodes) => { + return nodes.length === 1; + }, + action(nodes) { + const node = nodes[0]; + const { document: doc, parent, index } = node; + if (parent) { + const newNode = doc?.insertNode(parent, node, (index ?? 0) + 1, true); + newNode?.select(); + } + }, + }); + + material.addContextMenuOption({ + name: 'copy', + title: intl('Copy.1'), + action(nodes) { + if (!nodes || nodes.length < 1) { + return; + } + + const data = getNodesSchema(nodes); + clipboard.setData(data); + }, + }); + + material.addContextMenuOption({ + name: 'zhantieToBottom', + title: intl('PasteToTheBottom'), + condition: (nodes) => { + return nodes.length === 1; + }, + async action(nodes) { + if (!nodes || nodes.length < 1) { + return; + } + + const node = nodes[0]; + const { document: doc, parent, index } = node; + + try { + const nodeSchema = await getClipboardText(); + if (parent) { + nodeSchema.forEach((schema, schemaIndex) => { + doc?.insertNode(parent, schema, (index ?? 0) + 1 + schemaIndex, true); + }); + } + } catch (error) { + console.error(error); + } + }, + }); + + material.addContextMenuOption({ + name: 'zhantieToInner', + title: intl('PasteToTheInside'), + condition: (nodes) => { + return nodes.length === 1; + }, + disabled: (nodes) => { + // 获取粘贴数据 + const node = nodes[0]; + return !node.isContainerNode; + }, + async action(nodes) { + const node = nodes[0]; + const { document: doc, parent } = node; + + try { + const nodeSchema = await getClipboardText(); + if (parent) { + const index = node.children?.size || 0; + + if (parent) { + nodeSchema.forEach((schema, schemaIndex) => { + doc?.insertNode(node, schema, (index ?? 0) + 1 + schemaIndex, true); + }); + } + } + } catch (error) { + console.error(error); + } + }, + }); + + material.addContextMenuOption({ + name: 'delete', + title: intl('Delete'), + action(nodes) { + nodes.forEach((node) => { + node.remove(); + }); + }, + }); + }, + }; +}; + +defaultContextMenu.pluginName = '___default_context_menu___'; diff --git a/packages/engine/src/locale/en-US.json b/packages/engine/src/locale/en-US.json new file mode 100644 index 0000000000..1cdb06f28b --- /dev/null +++ b/packages/engine/src/locale/en-US.json @@ -0,0 +1,9 @@ +{ + "NotValidNodeData": "Not valid node data", + "SelectComponents": "Select components", + "Copy": "Copy", + "Copy.1": "Copy", + "PasteToTheBottom": "Paste to the bottom", + "PasteToTheInside": "Paste to the inside", + "Delete": "Delete" +} diff --git a/packages/engine/src/locale/index.ts b/packages/engine/src/locale/index.ts new file mode 100644 index 0000000000..510fcf056a --- /dev/null +++ b/packages/engine/src/locale/index.ts @@ -0,0 +1,14 @@ +import { createIntl } from '@alilc/lowcode-editor-core'; +import enUS from './en-US.json'; +import zhCN from './zh-CN.json'; + +const { intl } = createIntl?.({ + 'en-US': enUS, + 'zh-CN': zhCN, +}) || { + intl: (id) => { + return zhCN[id]; + }, +}; + +export { intl, enUS, zhCN }; diff --git a/packages/engine/src/locale/zh-CN.json b/packages/engine/src/locale/zh-CN.json new file mode 100644 index 0000000000..ba0f87f8e6 --- /dev/null +++ b/packages/engine/src/locale/zh-CN.json @@ -0,0 +1,9 @@ +{ + "NotValidNodeData": "不是有效的节点数据", + "SelectComponents": "选择组件", + "Copy": "复制", + "Copy.1": "拷贝", + "PasteToTheBottom": "粘贴至下方", + "PasteToTheInside": "粘贴至内部", + "Delete": "删除" +} diff --git a/packages/shell/src/api/commonUI.ts b/packages/shell/src/api/commonUI.ts index 718b409707..9f40afa119 100644 --- a/packages/shell/src/api/commonUI.ts +++ b/packages/shell/src/api/commonUI.ts @@ -4,6 +4,7 @@ import { Title as InnerTitle, } from '@alilc/lowcode-editor-core'; import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; +import { ContextMenu } from '../components/context-menu'; export class CommonUI implements IPublicApiCommonUI { Balloon = Balloon; @@ -40,4 +41,7 @@ export class CommonUI implements IPublicApiCommonUI { get Title() { return InnerTitle; } + get ContextMenu() { + return ContextMenu; + } } diff --git a/packages/shell/src/api/material.ts b/packages/shell/src/api/material.ts index 39b21848e0..f0c37d8a4d 100644 --- a/packages/shell/src/api/material.ts +++ b/packages/shell/src/api/material.ts @@ -13,6 +13,8 @@ import { IPublicTypeNpmInfo, IPublicModelEditor, IPublicTypeDisposable, + IPublicTypeContextMenuAction, + IPublicTypeContextMenuItem, } from '@alilc/lowcode-types'; import { Workspace as InnerWorkspace } from '@alilc/lowcode-workspace'; import { editorSymbol, designerSymbol } from '../symbols'; @@ -190,4 +192,16 @@ export class Material implements IPublicApiMaterial { dispose.forEach(d => d && d()); }; } + + addContextMenuOption(option: IPublicTypeContextMenuAction) { + this[designerSymbol].contextMenuActions.addMenuAction(option); + } + + removeContextMenuOption(name: string) { + this[designerSymbol].contextMenuActions.removeMenuAction(name); + } + + adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]) { + this[designerSymbol].contextMenuActions.adjustMenuLayout(fn); + } } diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx new file mode 100644 index 0000000000..0085e1c777 --- /dev/null +++ b/packages/shell/src/components/context-menu.tsx @@ -0,0 +1,46 @@ +import { Menu } from '@alifd/next'; +import { parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; +import { engineConfig } from '@alilc/lowcode-editor-core'; +import { IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; +import React from 'react'; + +export function ContextMenu({ children, menus }: { + menus: IPublicTypeContextMenuAction[]; + children: React.ReactElement[]; +}): React.ReactElement<any, string | React.JSXElementConstructor<any>>[] { + if (!engineConfig.get('enableContextMenu')) { + return children; + } + + const handleContextMenu = (event: React.MouseEvent) => { + event.preventDefault(); + event.stopPropagation(); + + const target = event.target; + const { top, left } = target?.getBoundingClientRect(); + let destroyFn: Function | undefined; + const destroy = () => { + destroyFn?.(); + }; + const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, { + destroy, + })); + + const menuInstance = Menu.create({ + target: event.target, + offset: [event.clientX - left, event.clientY - top], + children, + }); + + destroyFn = (menuInstance as any).destroy; + }; + + // 克隆 children 并添加 onContextMenu 事件处理器 + const childrenWithContextMenu = React.Children.map(children, (child) => + React.cloneElement( + child, + { onContextMenu: handleContextMenu }, + )); + + return childrenWithContextMenu; +} \ No newline at end of file diff --git a/packages/types/src/shell/api/commonUI.ts b/packages/types/src/shell/api/commonUI.ts index 3d7bb57bf3..dcc6fab0c3 100644 --- a/packages/types/src/shell/api/commonUI.ts +++ b/packages/types/src/shell/api/commonUI.ts @@ -1,4 +1,5 @@ -import { IPublicTypeTitleContent } from '../type'; +import { ReactElement } from 'react'; +import { IPublicTypeContextMenuAction, IPublicTypeTitleContent } from '../type'; import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; export interface IPublicApiCommonUI { @@ -45,4 +46,9 @@ export interface IPublicApiCommonUI { match?: boolean; keywords?: string | null; }>; + + get ContextMenu(): (props: { + menus: IPublicTypeContextMenuAction[]; + children: React.ReactElement[]; + }) => ReactElement[]; } \ No newline at end of file diff --git a/packages/types/src/shell/api/material.ts b/packages/types/src/shell/api/material.ts index d64455eddd..6354c7fa0f 100644 --- a/packages/types/src/shell/api/material.ts +++ b/packages/types/src/shell/api/material.ts @@ -1,4 +1,4 @@ -import { IPublicTypeAssetsJson, IPublicTypeMetadataTransducer, IPublicTypeComponentAction, IPublicTypeNpmInfo, IPublicTypeDisposable } from '../type'; +import { IPublicTypeAssetsJson, IPublicTypeMetadataTransducer, IPublicTypeComponentAction, IPublicTypeNpmInfo, IPublicTypeDisposable, IPublicTypeContextMenuAction, IPublicTypeContextMenuItem } from '../type'; import { IPublicModelComponentMeta } from '../model'; import { ComponentType } from 'react'; @@ -128,4 +128,22 @@ export interface IPublicApiMaterial { * @since v1.1.7 */ refreshComponentMetasMap(): void; + + /** + * 添加右键菜单项 + * @param action + */ + addContextMenuOption(action: IPublicTypeContextMenuAction): void; + + /** + * 删除特定右键菜单项 + * @param name + */ + removeContextMenuOption(name: string): void; + + /** + * 调整右键菜单项布局 + * @param actions + */ + adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]): void; } diff --git a/packages/types/src/shell/enum/context-menu.ts b/packages/types/src/shell/enum/context-menu.ts new file mode 100644 index 0000000000..fd209b1974 --- /dev/null +++ b/packages/types/src/shell/enum/context-menu.ts @@ -0,0 +1,7 @@ +export enum IPublicEnumContextMenuType { + SEPARATOR = 'separator', + // 'menuItem' + MENU_ITEM = 'menuItem', + // 'nodeTree' + NODE_TREE = 'nodeTree', +} \ No newline at end of file diff --git a/packages/types/src/shell/enum/index.ts b/packages/types/src/shell/enum/index.ts index f3d5580119..13282d0f2b 100644 --- a/packages/types/src/shell/enum/index.ts +++ b/packages/types/src/shell/enum/index.ts @@ -3,4 +3,5 @@ export * from './transition-type'; export * from './transform-stage'; export * from './drag-object-type'; export * from './prop-value-changed-type'; -export * from './plugin-register-level'; \ No newline at end of file +export * from './plugin-register-level'; +export * from './context-menu'; \ No newline at end of file diff --git a/packages/types/src/shell/type/context-menu.ts b/packages/types/src/shell/type/context-menu.ts new file mode 100644 index 0000000000..595893d32c --- /dev/null +++ b/packages/types/src/shell/type/context-menu.ts @@ -0,0 +1,57 @@ +import { IPublicEnumContextMenuType } from '../enum'; +import { IPublicModelNode } from '../model'; +import { IPublicTypeI18nData } from './i8n-data'; + +export interface IPublicTypeContextMenuItem extends Omit<IPublicTypeContextMenuAction, 'condition' | 'disabled' | 'items'> { + disabled?: boolean; + + items?: Omit<IPublicTypeContextMenuItem, 'items'>[]; +} + +export interface IPublicTypeContextMenuAction { + + /** + * 动作的唯一标识符 + * Unique identifier for the action + */ + name: string; + + /** + * 显示的标题,可以是字符串或国际化数据 + * Display title, can be a string or internationalized data + */ + title?: string | IPublicTypeI18nData; + + /** + * 菜单项类型 + * Menu item type + * @see IPublicEnumContextMenuType + * @default IPublicEnumPContextMenuType.MENU_ITEM + */ + type?: IPublicEnumContextMenuType; + + /** + * 点击时执行的动作,可选 + * Action to execute on click, optional + */ + action?: (nodes: IPublicModelNode[]) => void; + + /** + * 子菜单项或生成子节点的函数,可选,仅支持两级 + * Sub-menu items or function to generate child node, optional + */ + items?: Omit<IPublicTypeContextMenuAction, 'items'>[] | ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]); + + /** + * 显示条件函数 + * Function to determine display condition + */ + condition?: (nodes: IPublicModelNode[]) => boolean; + + /** + * 禁用条件函数,可选 + * Function to determine disabled condition, optional + */ + disabled?: (nodes: IPublicModelNode[]) => boolean; +} + diff --git a/packages/types/src/shell/type/engine-options.ts b/packages/types/src/shell/type/engine-options.ts index 72078c8107..8221c4089c 100644 --- a/packages/types/src/shell/type/engine-options.ts +++ b/packages/types/src/shell/type/engine-options.ts @@ -178,6 +178,12 @@ export interface IPublicTypeEngineOptions { */ enableAutoOpenFirstWindow?: boolean; + /** + * @default false + * 开启右键菜单能力 + */ + enableContextMenu?: boolean; + /** * @default false * 隐藏设计器辅助层 diff --git a/packages/types/src/shell/type/index.ts b/packages/types/src/shell/type/index.ts index b2fd3313f9..b1c7779d05 100644 --- a/packages/types/src/shell/type/index.ts +++ b/packages/types/src/shell/type/index.ts @@ -91,4 +91,5 @@ export * from './hotkey-callback-config'; export * from './hotkey-callbacks'; export * from './scrollable'; export * from './simulator-renderer'; -export * from './config-transducer'; \ No newline at end of file +export * from './config-transducer'; +export * from './context-menu'; \ No newline at end of file diff --git a/packages/utils/src/context-menu.scss b/packages/utils/src/context-menu.scss new file mode 100644 index 0000000000..744eede873 --- /dev/null +++ b/packages/utils/src/context-menu.scss @@ -0,0 +1,33 @@ +.context-menu-tree-wrap { + position: relative; + padding: 4px 10px 4px 24px; +} + +.context-menu-tree-children { + margin-left: 8px; + line-height: 24px; +} + +.context-menu-tree-bg { + position: absolute; + left: 0; + right: 0; + cursor: pointer; +} + +.context-menu-tree-bg-inner { + position: absolute; + height: 24px; + top: -24px; + width: 100%; + + &:hover { + background-color: var(--color-block-background-light); + } +} + +.context-menu-tree-selected-icon { + position: absolute; + left: 10px; + color: var(--color-icon-active); +} \ No newline at end of file diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx new file mode 100644 index 0000000000..3c7bb5d134 --- /dev/null +++ b/packages/utils/src/context-menu.tsx @@ -0,0 +1,138 @@ +import { Menu, Icon } from '@alifd/next'; +import { IDesigner } from '@alilc/lowcode-designer'; +import { IPublicEnumContextMenuType, IPublicModelNode, IPublicTypeContextMenuAction, IPublicTypeContextMenuItem } from '@alilc/lowcode-types'; +import { Logger } from '@alilc/lowcode-utils'; +import React from 'react'; +import './context-menu.scss'; + +const logger = new Logger({ level: 'warn', bizName: 'designer' }); +const { Item, Divider, PopupItem } = Menu; + +const MAX_LEVEL = 2; + +const Tree = (props: { + node?: IPublicModelNode; + children?: React.ReactNode; + options: { + nodes?: IPublicModelNode[] | null; + destroy?: Function; + designer?: IDesigner; + }; +}) => { + const { node } = props; + + if (!node) { + return null; + } + + if (!node.parent) { + return ( + <div className="context-menu-tree-wrap"> + <div className="context-menu-tree-children"> + {props.children} + </div> + </div> + ); + } + + const commonUI = props.options.designer?.editor?.get('commonUI'); + + const Title = commonUI?.Title; + + return ( + <Tree {...props} node={node.parent} > + {props.options.nodes?.[0].id === node.id ? (<Icon className="context-menu-tree-selected-icon" size="small" type="success" />) : null} + <Title title={node.title} /> + <div + className="context-menu-tree-children" + > + <div + className="context-menu-tree-bg" + onClick={() => { + props.options.destroy?.(); + node.select(); + }} + > + <div className="context-menu-tree-bg-inner" /> + </div> + { props.children } + </div> + </Tree> + ); +}; + +export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], options: { + nodes?: IPublicModelNode[] | null; + destroy?: Function; + designer?: IDesigner; +} = {}): React.ReactNode[] { + const children: React.ReactNode[] = []; + menus.forEach((menu, index) => { + if (menu.type === IPublicEnumContextMenuType.SEPARATOR) { + children.push(<Divider key={menu.name || index} />); + return; + } + + if (menu.type === IPublicEnumContextMenuType.MENU_ITEM) { + if (menu.items && menu.items.length) { + children.push(( + <PopupItem key={menu.name} label={menu.title}> + <Menu className="next-context engine-context-menu"> + { parseContextMenuAsReactNode(menu.items, options) } + </Menu> + </PopupItem> + )); + } else { + children.push((<Item disabled={menu.disabled} onClick={menu.action} key={menu.name}>{menu.title}</Item>)); + } + } + + if (menu.type === IPublicEnumContextMenuType.NODE_TREE) { + children.push(( + <Tree node={options.nodes?.[0]} options={options} /> + )); + } + }); + + return children; +} + +export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction | Omit<IPublicTypeContextMenuAction, 'items'>)[], options: { + nodes?: IPublicModelNode[] | null; + destroy?: Function; +}, level = 1): IPublicTypeContextMenuItem[] { + const { nodes, destroy } = options; + if (level > MAX_LEVEL) { + logger.warn('context menu level is too deep, please check your context menu config'); + return []; + } + + return menus.filter(menu => !menu.condition || (menu.condition && menu.condition(nodes || []))).map((menu) => { + const { + name, + title, + type = IPublicEnumContextMenuType.MENU_ITEM, + } = menu; + + const result: IPublicTypeContextMenuItem = { + name, + title, + type, + action: () => { + destroy?.(); + menu.action?.(nodes || []); + }, + disabled: menu.disabled && menu.disabled(nodes || []) || false, + }; + + if ('items' in menu && menu.items) { + result.items = parseContextMenuProperties( + typeof menu.items === 'function' ? menu.items(nodes || []) : menu.items, + options, + level + 1, + ); + } + + return result; + }); +} \ No newline at end of file diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 3e37f46ba6..b99ab02073 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -31,3 +31,4 @@ export * as css from './css-helper'; export { transactionManager } from './transaction-manager'; export * from './check-types'; export * from './workspace'; +export * from './context-menu'; From 3f369e446d2c16f6c2aa88ee1c9d5f336ad37b71 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 8 Jan 2024 06:56:19 +0000 Subject: [PATCH 411/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 6659eaf853..3ef05af3cb 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.19", + "version": "1.2.20", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 6288ab9d60fe4e91475b685c7926c1adb971a935 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 8 Jan 2024 15:06:00 +0800 Subject: [PATCH 412/469] fix(docs): fix invalid doc content --- docs/docs/api/commonUI.md | 70 +++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md index ef7af7f415..82b57c3893 100644 --- a/docs/docs/api/commonUI.md +++ b/docs/docs/api/commonUI.md @@ -40,99 +40,99 @@ CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开 | 参数 | 说明 | 类型 | 默认值 | |------------|--------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|----------------------------------------| -| name | 动作的唯一标识符<br>Unique identifier for the action | string | | -| title | 显示的标题,可以是字符串或国际化数据<br>Display title, can be a string or internationalized data | string \| IPublicTypeI18nData (optional) | | -| type | 菜单项类型<br>Menu item type | IPublicEnumContextMenuType (optional) | IPublicEnumPContextMenuType.MENU_ITEM | -| action | 点击时执行的动作,可选<br>Action to execute on click, optional | (nodes: IPublicModelNode[]) => void (optional) | | -| items | 子菜单项或生成子节点的函数,可选,仅支持两级<br>Sub-menu items or function to generate child node, optional | Omit<IPublicTypeContextMenuAction, 'items'>[] \| ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]) (optional) | | -| condition | 显示条件函数<br>Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | | -| disabled | 禁用条件函数,可选<br>Function to determine disabled condition, optional | (nodes: IPublicModelNode[]) => boolean (optional) | | +| name | 动作的唯一标识符<br/>Unique identifier for the action | string | | +| title | 显示的标题,可以是字符串或国际化数据<br/>Display title, can be a string or internationalized data | string \| IPublicTypeI18nData (optional) | | +| type | 菜单项类型<br/>Menu item type | IPublicEnumContextMenuType (optional) | IPublicEnumPContextMenuType.MENU_ITEM | +| action | 点击时执行的动作,可选<br/>Action to execute on click, optional | (nodes: IPublicModelNode[]) => void (optional) | | +| items | 子菜单项或生成子节点的函数,可选,仅支持两级<br/>Sub-menu items or function to generate child node, optional | Omit<IPublicTypeContextMenuAction, 'items'>[] \| ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]) (optional) | | +| condition | 显示条件函数<br/>Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | | +| disabled | 禁用条件函数,可选<br/>Function to determine disabled condition, optional | (nodes: IPublicModelNode[]) => boolean (optional) | | ### Balloon -详细文档: [Balloon Documentation](https://fusion.design/pc/component/balloon) +详细文档: [Balloon Documentation](https://fusion.design/pc/component/balloon) ### Breadcrumb -详细文档: [Breadcrumb Documentation](https://fusion.design/pc/component/breadcrumb) +详细文档: [Breadcrumb Documentation](https://fusion.design/pc/component/breadcrumb) ### Button -详细文档: [Button Documentation](https://fusion.design/pc/component/button) +详细文档: [Button Documentation](https://fusion.design/pc/component/button) ### Card -详细文档: [Card Documentation](https://fusion.design/pc/component/card) +详细文档:[Card Documentation](https://fusion.design/pc/component/card) ### Checkbox -详细文档: [Checkbox Documentation](https://fusion.design/pc/component/checkbox) +详细文档:[Checkbox Documentation](https://fusion.design/pc/component/checkbox) ### DatePicker -详细文档: [DatePicker Documentation](https://fusion.design/pc/component/datepicker) +详细文档:[DatePicker Documentation](https://fusion.design/pc/component/datepicker) ### Dialog -详细文档: [Dialog Documentation](https://fusion.design/pc/component/dialog) +详细文档:[Dialog Documentation](https://fusion.design/pc/component/dialog) ### Dropdown -详细文档: [Dropdown Documentation](https://fusion.design/pc/component/dropdown) +详细文档:[Dropdown Documentation](https://fusion.design/pc/component/dropdown) ### Form -详细文档: [Form Documentation](https://fusion.design/pc/component/form) +详细文档:[Form Documentation](https://fusion.design/pc/component/form) ### Icon -详细文档: [Icon Documentation](https://fusion.design/pc/component/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) +详细文档:[Input Documentation](https://fusion.design/pc/component/input) ### Loading -详细文档: [Loading Documentation](https://fusion.design/pc/component/loading) +详细文档:[Loading Documentation](https://fusion.design/pc/component/loading) ### Message -详细文档: [Message Documentation](https://fusion.design/pc/component/message) +详细文档:[Message Documentation](https://fusion.design/pc/component/message) ### Overlay -详细文档: [Overlay Documentation](https://fusion.design/pc/component/overlay) +详细文档:[Overlay Documentation](https://fusion.design/pc/component/overlay) ### Pagination -详细文档: [Pagination Documentation](https://fusion.design/pc/component/pagination) +详细文档:[Pagination Documentation](https://fusion.design/pc/component/pagination) ### Radio -详细文档: [Radio Documentation](https://fusion.design/pc/component/radio) +详细文档:[Radio Documentation](https://fusion.design/pc/component/radio) ### Search -详细文档: [Search Documentation](https://fusion.design/pc/component/search) +详细文档:[Search Documentation](https://fusion.design/pc/component/search) ### Select -详细文档: [Select Documentation](https://fusion.design/pc/component/select) +详细文档:[Select Documentation](https://fusion.design/pc/component/select) ### SplitButton -详细文档: [SplitButton Documentation](https://fusion.design/pc/component/splitbutton) +详细文档:[SplitButton Documentation](https://fusion.design/pc/component/splitbutton) ### Step -详细文档: [Step Documentation](https://fusion.design/pc/component/step) +详细文档:[Step Documentation](https://fusion.design/pc/component/step) ### Switch -详细文档: [Switch Documentation](https://fusion.design/pc/component/switch) +详细文档:[Switch Documentation](https://fusion.design/pc/component/switch) ### Tab -详细文档: [Tab Documentation](https://fusion.design/pc/component/tab) +详细文档:[Tab Documentation](https://fusion.design/pc/component/tab) ### Table -详细文档: [Table Documentation](https://fusion.design/pc/component/table) +详细文档:[Table Documentation](https://fusion.design/pc/component/table) ### Tree -详细文档: [Tree Documentation](https://fusion.design/pc/component/tree) +详细文档:[Tree Documentation](https://fusion.design/pc/component/tree) ### TreeSelect -详细文档: [TreeSelect Documentation](https://fusion.design/pc/component/treeselect) +详细文档:[TreeSelect Documentation](https://fusion.design/pc/component/treeselect) ### Upload -详细文档: [Upload Documentation](https://fusion.design/pc/component/upload) +详细文档:[Upload Documentation](https://fusion.design/pc/component/upload) ### Divider -详细文档: [Divider Documentation](https://fusion.design/pc/component/divider) +详细文档:[Divider Documentation](https://fusion.design/pc/component/divider) ## 说明 -如果需要其他组件,可以提issue给我们 \ No newline at end of file +如果需要其他组件,可以提 issue 给我们。 From 6ce381f60aa1deb714d3fbe52f6240f8d352f759 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 8 Jan 2024 07:06:58 +0000 Subject: [PATCH 413/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 3ef05af3cb..1f49ab6247 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.20", + "version": "1.2.21", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 6ded1a6384174b10b0069d9129bbc14d1a9daeb6 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 8 Jan 2024 18:48:06 +0800 Subject: [PATCH 414/469] chore: update CODEOWNERS --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c2e49b783f..1000fca053 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -5,4 +5,4 @@ * @liujuping @JackLian /modules/material-parser @akirakai -/modules/code-generator @leoyuan +/modules/code-generator @qingniaotonghua From 8f0291fc3e58eaec2d786ff8e1854657208d5bde Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 8 Jan 2024 18:46:30 +0800 Subject: [PATCH 415/469] fix(context-menu): fix context menu bugs --- packages/designer/src/context-menu-actions.ts | 4 +++- .../engine/src/inner-plugins/default-context-menu.ts | 6 ++++++ packages/utils/src/context-menu.scss | 2 +- packages/utils/src/context-menu.tsx | 10 +--------- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/designer/src/context-menu-actions.ts b/packages/designer/src/context-menu-actions.ts index 053e4f0313..55a83ef2ff 100644 --- a/packages/designer/src/context-menu-actions.ts +++ b/packages/designer/src/context-menu-actions.ts @@ -17,6 +17,8 @@ export interface IContextMenuActions { adjustMenuLayout: IPublicApiMaterial['adjustContextMenuLayout']; } +let destroyFn: Function | undefined; + export class ContextMenuActions implements IContextMenuActions { actions: IPublicTypeContextMenuAction[] = []; @@ -55,7 +57,7 @@ export class ContextMenuActions implements IContextMenuActions { const { bounds } = designer.project.simulator?.viewport || { bounds: { left: 0, top: 0 } }; const { left: simulatorLeft, top: simulatorTop } = bounds; - let destroyFn: Function | undefined; + destroyFn?.(); const destroy = () => { destroyFn?.(); diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts index 86feb17d97..50a86fcec8 100644 --- a/packages/engine/src/inner-plugins/default-context-menu.ts +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -87,6 +87,9 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copy', title: intl('Copy.1'), + condition(nodes) { + return nodes.length > 0; + }, action(nodes) { if (!nodes || nodes.length < 1) { return; @@ -159,6 +162,9 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'delete', title: intl('Delete'), + condition(nodes) { + return nodes.length > 0; + }, action(nodes) { nodes.forEach((node) => { node.remove(); diff --git a/packages/utils/src/context-menu.scss b/packages/utils/src/context-menu.scss index 744eede873..0bcf39d153 100644 --- a/packages/utils/src/context-menu.scss +++ b/packages/utils/src/context-menu.scss @@ -1,6 +1,6 @@ .context-menu-tree-wrap { position: relative; - padding: 4px 10px 4px 24px; + padding: 4px 10px 4px 32px; } .context-menu-tree-children { diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx index 3c7bb5d134..f65bc312f6 100644 --- a/packages/utils/src/context-menu.tsx +++ b/packages/utils/src/context-menu.tsx @@ -22,16 +22,8 @@ const Tree = (props: { const { node } = props; if (!node) { - return null; - } - - if (!node.parent) { return ( - <div className="context-menu-tree-wrap"> - <div className="context-menu-tree-children"> - {props.children} - </div> - </div> + <div className="context-menu-tree-wrap">{ props.children }</div> ); } From c381b85f0a48b215414e72c76864aa8b435fd443 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 9 Jan 2024 16:37:42 +0800 Subject: [PATCH 416/469] fix(context-menu): fix context menu bugs --- docs/docs/api/commonUI.md | 2 +- packages/designer/src/context-menu-actions.ts | 121 +++++++++++++++--- .../src/inner-plugins/default-context-menu.ts | 4 +- packages/engine/src/locale/en-US.json | 2 +- packages/engine/src/locale/zh-CN.json | 4 +- .../shell/src/components/context-menu.tsx | 16 ++- packages/types/src/shell/api/commonUI.ts | 4 +- packages/types/src/shell/type/context-menu.ts | 4 +- packages/utils/src/context-menu.tsx | 73 +++++++---- 9 files changed, 171 insertions(+), 59 deletions(-) diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md index 82b57c3893..f3afe1fc25 100644 --- a/docs/docs/api/commonUI.md +++ b/docs/docs/api/commonUI.md @@ -42,7 +42,7 @@ CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开 |------------|--------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|----------------------------------------| | name | 动作的唯一标识符<br/>Unique identifier for the action | string | | | title | 显示的标题,可以是字符串或国际化数据<br/>Display title, can be a string or internationalized data | string \| IPublicTypeI18nData (optional) | | -| type | 菜单项类型<br/>Menu item type | IPublicEnumContextMenuType (optional) | IPublicEnumPContextMenuType.MENU_ITEM | +| type | 菜单项类型<br/>Menu item type | IPublicEnumContextMenuType (optional) | IPublicEnumContextMenuType.MENU_ITEM | | action | 点击时执行的动作,可选<br/>Action to execute on click, optional | (nodes: IPublicModelNode[]) => void (optional) | | | items | 子菜单项或生成子节点的函数,可选,仅支持两级<br/>Sub-menu items or function to generate child node, optional | Omit<IPublicTypeContextMenuAction, 'items'>[] \| ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]) (optional) | | | condition | 显示条件函数<br/>Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | | diff --git a/packages/designer/src/context-menu-actions.ts b/packages/designer/src/context-menu-actions.ts index 55a83ef2ff..8c210d89e0 100644 --- a/packages/designer/src/context-menu-actions.ts +++ b/packages/designer/src/context-menu-actions.ts @@ -1,6 +1,6 @@ import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial } from '@alilc/lowcode-types'; import { IDesigner, INode } from './designer'; -import { parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; +import { parseContextMenuAsReactNode, parseContextMenuProperties, uniqueId } from '@alilc/lowcode-utils'; import { Menu } from '@alifd/next'; import { engineConfig } from '@alilc/lowcode-editor-core'; import './context-menu-actions.scss'; @@ -17,7 +17,100 @@ export interface IContextMenuActions { adjustMenuLayout: IPublicApiMaterial['adjustContextMenuLayout']; } -let destroyFn: Function | undefined; +let adjustMenuLayoutFn: Function = (actions: IPublicTypeContextMenuAction[]) => actions; + +export class GlobalContextMenuActions { + enableContextMenu: boolean; + + dispose: Function[]; + + contextMenuActionsMap: Map<string, ContextMenuActions> = new Map(); + + constructor() { + this.dispose = []; + + engineConfig.onGot('enableContextMenu', (enable) => { + if (this.enableContextMenu === enable) { + return; + } + this.enableContextMenu = enable; + this.dispose.forEach(d => d()); + if (enable) { + this.initEvent(); + } + }); + } + + handleContextMenu = ( + event: MouseEvent, + ) => { + event.stopPropagation(); + event.preventDefault(); + + const actions: IPublicTypeContextMenuAction[] = []; + this.contextMenuActionsMap.forEach((contextMenu) => { + actions.push(...contextMenu.actions); + }); + + let destroyFn: Function | undefined; + + const destroy = () => { + destroyFn?.(); + }; + + const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, { + nodes: [], + destroy, + event, + }); + + if (!menus.length) { + return; + } + + const layoutMenu = adjustMenuLayoutFn(menus); + + const menuNode = parseContextMenuAsReactNode(layoutMenu, { + destroy, + nodes: [], + }); + + const target = event.target; + + const { top, left } = target?.getBoundingClientRect(); + + const menuInstance = Menu.create({ + target: event.target, + offset: [event.clientX - left, event.clientY - top], + children: menuNode, + className: 'engine-context-menu', + }); + + destroyFn = (menuInstance as any).destroy; + }; + + initEvent() { + this.dispose.push( + (() => { + const handleContextMenu = (e: MouseEvent) => { + this.handleContextMenu(e); + }; + + document.addEventListener('contextmenu', handleContextMenu); + + return () => { + document.removeEventListener('contextmenu', handleContextMenu); + }; + })(), + ); + } + + registerContextMenuActions(contextMenu: ContextMenuActions) { + this.contextMenuActionsMap.set(contextMenu.id, contextMenu); + } +} + +const globalContextMenuActions = new GlobalContextMenuActions(); export class ContextMenuActions implements IContextMenuActions { actions: IPublicTypeContextMenuAction[] = []; @@ -28,6 +121,8 @@ export class ContextMenuActions implements IContextMenuActions { enableContextMenu: boolean; + id: string = uniqueId('contextMenu');; + constructor(designer: IDesigner) { this.designer = designer; this.dispose = []; @@ -42,6 +137,8 @@ export class ContextMenuActions implements IContextMenuActions { this.initEvent(); } }); + + globalContextMenuActions.registerContextMenuActions(this); } handleContextMenu = ( @@ -57,7 +154,7 @@ export class ContextMenuActions implements IContextMenuActions { const { bounds } = designer.project.simulator?.viewport || { bounds: { left: 0, top: 0 } }; const { left: simulatorLeft, top: simulatorTop } = bounds; - destroyFn?.(); + let destroyFn: Function | undefined; const destroy = () => { destroyFn?.(); @@ -66,13 +163,14 @@ export class ContextMenuActions implements IContextMenuActions { const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, { nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!), destroy, + event, }); if (!menus.length) { return; } - const layoutMenu = designer.contextMenuActions.adjustMenuLayoutFn(menus); + const layoutMenu = adjustMenuLayoutFn(menus); const menuNode = parseContextMenuAsReactNode(layoutMenu, { destroy, @@ -111,22 +209,9 @@ export class ContextMenuActions implements IContextMenuActions { const nodes = designer.currentSelection.getNodes(); this.handleContextMenu(nodes, originalEvent); }), - (() => { - const handleContextMenu = (e: MouseEvent) => { - this.handleContextMenu([], e); - }; - - document.addEventListener('contextmenu', handleContextMenu); - - return () => { - document.removeEventListener('contextmenu', handleContextMenu); - }; - })(), ); } - adjustMenuLayoutFn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[] = (actions) => actions; - addMenuAction(action: IPublicTypeContextMenuAction) { this.actions.push({ type: IPublicEnumContextMenuType.MENU_ITEM, @@ -142,6 +227,6 @@ export class ContextMenuActions implements IContextMenuActions { } adjustMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]) { - this.adjustMenuLayoutFn = fn; + adjustMenuLayoutFn = fn; } } \ No newline at end of file diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts index 50a86fcec8..fc1da96b4a 100644 --- a/packages/engine/src/inner-plugins/default-context-menu.ts +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -70,7 +70,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copyAndPaste', - title: intl('Copy'), + title: intl('CopyAndPaste'), condition: (nodes) => { return nodes.length === 1; }, @@ -86,7 +86,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copy', - title: intl('Copy.1'), + title: intl('Copy'), condition(nodes) { return nodes.length > 0; }, diff --git a/packages/engine/src/locale/en-US.json b/packages/engine/src/locale/en-US.json index 1cdb06f28b..e931607073 100644 --- a/packages/engine/src/locale/en-US.json +++ b/packages/engine/src/locale/en-US.json @@ -1,8 +1,8 @@ { "NotValidNodeData": "Not valid node data", "SelectComponents": "Select components", + "CopyAndPaste": "Copy and Paste", "Copy": "Copy", - "Copy.1": "Copy", "PasteToTheBottom": "Paste to the bottom", "PasteToTheInside": "Paste to the inside", "Delete": "Delete" diff --git a/packages/engine/src/locale/zh-CN.json b/packages/engine/src/locale/zh-CN.json index ba0f87f8e6..9b68b71490 100644 --- a/packages/engine/src/locale/zh-CN.json +++ b/packages/engine/src/locale/zh-CN.json @@ -1,8 +1,8 @@ { "NotValidNodeData": "不是有效的节点数据", "SelectComponents": "选择组件", - "Copy": "复制", - "Copy.1": "拷贝", + "CopyAndPaste": "复制", + "Copy": "拷贝", "PasteToTheBottom": "粘贴至下方", "PasteToTheInside": "粘贴至内部", "Delete": "删除" diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx index 0085e1c777..f12f6ca93d 100644 --- a/packages/shell/src/components/context-menu.tsx +++ b/packages/shell/src/components/context-menu.tsx @@ -6,10 +6,12 @@ import React from 'react'; export function ContextMenu({ children, menus }: { menus: IPublicTypeContextMenuAction[]; - children: React.ReactElement[]; -}): React.ReactElement<any, string | React.JSXElementConstructor<any>>[] { + children: React.ReactElement[] | React.ReactElement; +}): React.ReactElement<any, string | React.JSXElementConstructor<any>> { if (!engineConfig.get('enableContextMenu')) { - return children; + return ( + <>{ children }</> + ); } const handleContextMenu = (event: React.MouseEvent) => { @@ -26,6 +28,10 @@ export function ContextMenu({ children, menus }: { destroy, })); + if (!children?.length) { + return; + } + const menuInstance = Menu.create({ target: event.target, offset: [event.clientX - left, event.clientY - top], @@ -42,5 +48,7 @@ export function ContextMenu({ children, menus }: { { onContextMenu: handleContextMenu }, )); - return childrenWithContextMenu; + return ( + <>{childrenWithContextMenu}</> + ); } \ No newline at end of file diff --git a/packages/types/src/shell/api/commonUI.ts b/packages/types/src/shell/api/commonUI.ts index dcc6fab0c3..71e2bbe83f 100644 --- a/packages/types/src/shell/api/commonUI.ts +++ b/packages/types/src/shell/api/commonUI.ts @@ -49,6 +49,6 @@ export interface IPublicApiCommonUI { get ContextMenu(): (props: { menus: IPublicTypeContextMenuAction[]; - children: React.ReactElement[]; - }) => ReactElement[]; + children: React.ReactElement[] | React.ReactElement; + }) => ReactElement; } \ No newline at end of file diff --git a/packages/types/src/shell/type/context-menu.ts b/packages/types/src/shell/type/context-menu.ts index 595893d32c..1eeb93d696 100644 --- a/packages/types/src/shell/type/context-menu.ts +++ b/packages/types/src/shell/type/context-menu.ts @@ -26,7 +26,7 @@ export interface IPublicTypeContextMenuAction { * 菜单项类型 * Menu item type * @see IPublicEnumContextMenuType - * @default IPublicEnumPContextMenuType.MENU_ITEM + * @default IPublicEnumContextMenuType.MENU_ITEM */ type?: IPublicEnumContextMenuType; @@ -34,7 +34,7 @@ export interface IPublicTypeContextMenuAction { * 点击时执行的动作,可选 * Action to execute on click, optional */ - action?: (nodes: IPublicModelNode[]) => void; + action?: (nodes: IPublicModelNode[], event?: MouseEvent) => void; /** * 子菜单项或生成子节点的函数,可选,仅支持两级 diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx index f65bc312f6..f28619df61 100644 --- a/packages/utils/src/context-menu.tsx +++ b/packages/utils/src/context-menu.tsx @@ -89,42 +89,61 @@ export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], return children; } +let destroyFn: Function | undefined; export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction | Omit<IPublicTypeContextMenuAction, 'items'>)[], options: { nodes?: IPublicModelNode[] | null; destroy?: Function; + event?: MouseEvent; }, level = 1): IPublicTypeContextMenuItem[] { + destroyFn?.(); + destroyFn = options.destroy; + const { nodes, destroy } = options; if (level > MAX_LEVEL) { logger.warn('context menu level is too deep, please check your context menu config'); return []; } - return menus.filter(menu => !menu.condition || (menu.condition && menu.condition(nodes || []))).map((menu) => { - const { - name, - title, - type = IPublicEnumContextMenuType.MENU_ITEM, - } = menu; - - const result: IPublicTypeContextMenuItem = { - name, - title, - type, - action: () => { - destroy?.(); - menu.action?.(nodes || []); - }, - disabled: menu.disabled && menu.disabled(nodes || []) || false, - }; - - if ('items' in menu && menu.items) { - result.items = parseContextMenuProperties( - typeof menu.items === 'function' ? menu.items(nodes || []) : menu.items, - options, - level + 1, - ); - } + return menus + .filter(menu => !menu.condition || (menu.condition && menu.condition(nodes || []))) + .map((menu) => { + const { + name, + title, + type = IPublicEnumContextMenuType.MENU_ITEM, + } = menu; + + const result: IPublicTypeContextMenuItem = { + name, + title, + type, + action: () => { + destroy?.(); + menu.action?.(nodes || [], options.event); + }, + disabled: menu.disabled && menu.disabled(nodes || []) || false, + }; + + if ('items' in menu && menu.items) { + result.items = parseContextMenuProperties( + typeof menu.items === 'function' ? menu.items(nodes || []) : menu.items, + options, + level + 1, + ); + } - return result; - }); + return result; + }) + .reduce((menus: IPublicTypeContextMenuItem[], currentMenu: IPublicTypeContextMenuItem) => { + if (!currentMenu.name) { + return menus.concat([currentMenu]); + } + + const index = menus.find(item => item.name === currentMenu.name); + if (!index) { + return menus.concat([currentMenu]); + } else { + return menus; + } + }, []); } \ No newline at end of file From 14728476b65d5bdeaa7624df1b4a74850516d049 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 9 Jan 2024 08:43:50 +0000 Subject: [PATCH 417/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 1f49ab6247..e0fea44a14 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.21", + "version": "1.2.22", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 3627ae326a5b46e669d921e5b98e237a44e9bdea Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 10 Jan 2024 15:13:44 +0800 Subject: [PATCH 418/469] feat: optimize context menu details --- docs/docs/api/material.md | 37 ++++++++ packages/designer/src/context-menu-actions.ts | 16 +--- .../src/inner-plugins/default-context-menu.ts | 90 +++++++++++++++---- packages/engine/src/locale/index.ts | 4 +- .../shell/src/components/context-menu.tsx | 13 +-- packages/utils/src/context-menu.tsx | 55 +++++++++++- 6 files changed, 174 insertions(+), 41 deletions(-) diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index 51ed4e3054..c83935b971 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -237,6 +237,43 @@ material.modifyBuiltinComponentAction('remove', (action) => { }); ``` +### 右键菜单项 +#### addContextMenuOption + +添加右键菜单项 + +```typescript +/** + * 添加右键菜单项 + * @param action + */ +addContextMenuOption(action: IPublicTypeContextMenuAction): void; +``` + +#### removeContextMenuOption + +删除特定右键菜单项 + +```typescript +/** + * 删除特定右键菜单项 + * @param name + */ +removeContextMenuOption(name: string): void; +``` + +#### adjustContextMenuLayout + +调整右键菜单项布局,每次调用都会覆盖之前注册的调整函数,只有最后注册的函数会被应用。 + +```typescript +/** + * 调整右键菜单项布局 + * @param actions + */ +adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]): void; +``` + ### 物料元数据 #### getComponentMeta 获取指定名称的物料元数据 diff --git a/packages/designer/src/context-menu-actions.ts b/packages/designer/src/context-menu-actions.ts index 8c210d89e0..5b44055b42 100644 --- a/packages/designer/src/context-menu-actions.ts +++ b/packages/designer/src/context-menu-actions.ts @@ -1,6 +1,6 @@ import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial } from '@alilc/lowcode-types'; import { IDesigner, INode } from './designer'; -import { parseContextMenuAsReactNode, parseContextMenuProperties, uniqueId } from '@alilc/lowcode-utils'; +import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties, uniqueId } from '@alilc/lowcode-utils'; import { Menu } from '@alifd/next'; import { engineConfig } from '@alilc/lowcode-editor-core'; import './context-menu-actions.scss'; @@ -178,18 +178,10 @@ export class ContextMenuActions implements IContextMenuActions { designer, }); - const target = event.target; - - const { top, left } = target?.getBoundingClientRect(); - - const menuInstance = Menu.create({ - target: event.target, - offset: [event.clientX - left + simulatorLeft, event.clientY - top + simulatorTop], - children: menuNode, - className: 'engine-context-menu', + destroyFn = createContextMenu(menuNode, { + event, + offset: [simulatorLeft, simulatorTop], }); - - destroyFn = (menuInstance as any).destroy; }; initEvent() { diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts index fc1da96b4a..9d1336b34e 100644 --- a/packages/engine/src/inner-plugins/default-context-menu.ts +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -1,13 +1,16 @@ import { IPublicEnumContextMenuType, + IPublicEnumDragObjectType, IPublicEnumTransformStage, IPublicModelNode, IPublicModelPluginContext, + IPublicTypeDragNodeDataObject, + IPublicTypeI18nData, IPublicTypeNodeSchema, } from '@alilc/lowcode-types'; -import { isProjectSchema } from '@alilc/lowcode-utils'; +import { isI18nData, isProjectSchema } from '@alilc/lowcode-utils'; import { Notification } from '@alifd/next'; -import { intl } from '../locale'; +import { intl, getLocale } from '../locale'; function getNodesSchema(nodes: IPublicModelNode[]) { const componentsTree = nodes.map((node) => node?.exportSchema(IPublicEnumTransformStage.Clone)); @@ -15,6 +18,15 @@ function getNodesSchema(nodes: IPublicModelNode[]) { return data; } +function getIntlStr(data: string | IPublicTypeI18nData) { + if (!isI18nData(data)) { + return data; + } + + const locale = getLocale(); + return data[locale] || data['zh-CN'] || data['zh_CN'] || data['en-US'] || data['en_US'] || ''; +} + async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> { return new Promise((resolve, reject) => { // 使用 Clipboard API 读取剪贴板内容 @@ -71,12 +83,18 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copyAndPaste', title: intl('CopyAndPaste'), + disabled: (nodes) => { + return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0; + }, condition: (nodes) => { return nodes.length === 1; }, action(nodes) { const node = nodes[0]; const { document: doc, parent, index } = node; + const data = getNodesSchema(nodes); + clipboard.setData(data); + if (parent) { const newNode = doc?.insertNode(parent, node, (index ?? 0) + 1, true); newNode?.select(); @@ -87,6 +105,9 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copy', title: intl('Copy'), + disabled: (nodes) => { + return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0; + }, condition(nodes) { return nodes.length > 0; }, @@ -101,7 +122,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { }); material.addContextMenuOption({ - name: 'zhantieToBottom', + name: 'pasteToBottom', title: intl('PasteToTheBottom'), condition: (nodes) => { return nodes.length === 1; @@ -116,10 +137,30 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { try { const nodeSchema = await getClipboardText(); + if (nodeSchema.length === 0) { + return; + } if (parent) { - nodeSchema.forEach((schema, schemaIndex) => { - doc?.insertNode(parent, schema, (index ?? 0) + 1 + schemaIndex, true); + let canAddNodes = nodeSchema.filter((nodeSchema: IPublicTypeNodeSchema) => { + const dragNodeObject: IPublicTypeDragNodeDataObject = { + type: IPublicEnumDragObjectType.NodeData, + data: nodeSchema, + }; + return doc?.checkNesting(parent, dragNodeObject); + }); + if (canAddNodes.length === 0) { + Notification.open({ + content: `${nodeSchema.map(d => getIntlStr(d.title || d.componentName)).join(',')}等组件无法放置到${getIntlStr(parent.title || parent.componentName as any)}内`, + type: 'error', + }); + return; + } + const nodes: IPublicModelNode[] = []; + canAddNodes.forEach((schema, schemaIndex) => { + const node = doc?.insertNode(parent, schema, (index ?? 0) + 1 + schemaIndex, true); + node && nodes.push(node); }); + doc?.selection.selectAll(nodes.map((node) => node?.id)); } } catch (error) { console.error(error); @@ -128,7 +169,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { }); material.addContextMenuOption({ - name: 'zhantieToInner', + name: 'pasteToInner', title: intl('PasteToTheInside'), condition: (nodes) => { return nodes.length === 1; @@ -140,19 +181,35 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { }, async action(nodes) { const node = nodes[0]; - const { document: doc, parent } = node; + const { document: doc } = node; try { const nodeSchema = await getClipboardText(); - if (parent) { - const index = node.children?.size || 0; - - if (parent) { - nodeSchema.forEach((schema, schemaIndex) => { - doc?.insertNode(node, schema, (index ?? 0) + 1 + schemaIndex, true); - }); - } + const index = node.children?.size || 0; + if (nodeSchema.length === 0) { + return; } + let canAddNodes = nodeSchema.filter((nodeSchema: IPublicTypeNodeSchema) => { + const dragNodeObject: IPublicTypeDragNodeDataObject = { + type: IPublicEnumDragObjectType.NodeData, + data: nodeSchema, + }; + return doc?.checkNesting(node, dragNodeObject); + }); + if (canAddNodes.length === 0) { + Notification.open({ + content: `${nodeSchema.map(d => getIntlStr(d.title || d.componentName)).join(',')}等组件无法放置到${getIntlStr(node.title || node.componentName as any)}内`, + type: 'error', + }); + return; + } + + const nodes: IPublicModelNode[] = []; + nodeSchema.forEach((schema, schemaIndex) => { + const newNode = doc?.insertNode(node, schema, (index ?? 0) + 1 + schemaIndex, true); + newNode && nodes.push(newNode); + }); + doc?.selection.selectAll(nodes.map((node) => node?.id)); } catch (error) { console.error(error); } @@ -162,6 +219,9 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'delete', title: intl('Delete'), + disabled(nodes) { + return nodes?.filter((node) => !node?.canPerformAction('remove')).length > 0; + }, condition(nodes) { return nodes.length > 0; }, diff --git a/packages/engine/src/locale/index.ts b/packages/engine/src/locale/index.ts index 510fcf056a..ca89840b05 100644 --- a/packages/engine/src/locale/index.ts +++ b/packages/engine/src/locale/index.ts @@ -2,7 +2,7 @@ import { createIntl } from '@alilc/lowcode-editor-core'; import enUS from './en-US.json'; import zhCN from './zh-CN.json'; -const { intl } = createIntl?.({ +const { intl, getLocale } = createIntl?.({ 'en-US': enUS, 'zh-CN': zhCN, }) || { @@ -11,4 +11,4 @@ const { intl } = createIntl?.({ }, }; -export { intl, enUS, zhCN }; +export { intl, enUS, zhCN, getLocale }; diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx index f12f6ca93d..acefbebd28 100644 --- a/packages/shell/src/components/context-menu.tsx +++ b/packages/shell/src/components/context-menu.tsx @@ -1,5 +1,4 @@ -import { Menu } from '@alifd/next'; -import { parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; +import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; import { engineConfig } from '@alilc/lowcode-editor-core'; import { IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; import React from 'react'; @@ -18,8 +17,6 @@ export function ContextMenu({ children, menus }: { event.preventDefault(); event.stopPropagation(); - const target = event.target; - const { top, left } = target?.getBoundingClientRect(); let destroyFn: Function | undefined; const destroy = () => { destroyFn?.(); @@ -32,13 +29,9 @@ export function ContextMenu({ children, menus }: { return; } - const menuInstance = Menu.create({ - target: event.target, - offset: [event.clientX - left, event.clientY - top], - children, + destroyFn = createContextMenu(children, { + event, }); - - destroyFn = (menuInstance as any).destroy; }; // 克隆 children 并添加 onContextMenu 事件处理器 diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx index f28619df61..1816f5b526 100644 --- a/packages/utils/src/context-menu.tsx +++ b/packages/utils/src/context-menu.tsx @@ -53,6 +53,8 @@ const Tree = (props: { ); }; +let destroyFn: Function | undefined; + export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], options: { nodes?: IPublicModelNode[] | null; destroy?: Function; @@ -89,14 +91,12 @@ export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], return children; } -let destroyFn: Function | undefined; export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction | Omit<IPublicTypeContextMenuAction, 'items'>)[], options: { nodes?: IPublicModelNode[] | null; destroy?: Function; event?: MouseEvent; }, level = 1): IPublicTypeContextMenuItem[] { destroyFn?.(); - destroyFn = options.destroy; const { nodes, destroy } = options; if (level > MAX_LEVEL) { @@ -146,4 +146,55 @@ export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction return menus; } }, []); +} + +let cachedMenuItemHeight: string | undefined; + +function getMenuItemHeight() { + if (cachedMenuItemHeight) { + return cachedMenuItemHeight; + } + const root = document.documentElement; + const styles = getComputedStyle(root); + // Access the value of the CSS variable + const menuItemHeight = styles.getPropertyValue('--context-menu-item-height').trim(); + cachedMenuItemHeight = menuItemHeight; + + return menuItemHeight; +} + +export function createContextMenu(children: React.ReactNode[], { + event, + offset = [0, 0], +}: { + event: MouseEvent | React.MouseEvent; + offset?: [number, number]; +}) { + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + const dividerCount = React.Children.count(children.filter(child => React.isValidElement(child) && child.type === Divider)); + const popupItemCount = React.Children.count(children.filter(child => React.isValidElement(child) && (child.type === PopupItem || child.type === Item))); + const menuHeight = popupItemCount * parseInt(getMenuItemHeight(), 10) + dividerCount * 8 + 16; + const menuWidthLimit = 200; + const target = event.target; + const { top, left } = (target as any)?.getBoundingClientRect(); + let x = event.clientX - left + offset[0]; + let y = event.clientY - top + offset[1]; + if (x + menuWidthLimit + left > viewportWidth) { + x = x - menuWidthLimit; + } + if (y + menuHeight + top > viewportHeight) { + y = y - menuHeight; + } + + const menuInstance = Menu.create({ + target, + offset: [x, y, 0, 0], + children, + className: 'engine-context-menu', + }); + + destroyFn = (menuInstance as any).destroy; + + return destroyFn; } \ No newline at end of file From a00c5c9b607f1e1597c1ed3b985b6f4249b11a68 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 10 Jan 2024 07:21:10 +0000 Subject: [PATCH 419/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index e0fea44a14..d1c3cd9f90 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.22", + "version": "1.2.23", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From a7d3996fa2eaccd883eb554677d6c15af6134978 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 11 Jan 2024 10:37:12 +0800 Subject: [PATCH 420/469] feat(common): add common.utils.intl API --- docs/docs/api/common.md | 16 ++++++++++++++++ packages/editor-core/src/intl/index.ts | 12 ++---------- packages/shell/src/api/common.tsx | 5 +++++ packages/types/src/shell/api/common.ts | 7 ++++++- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/docs/docs/api/common.md b/docs/docs/api/common.md index 966e2277f2..6613547ea9 100644 --- a/docs/docs/api/common.md +++ b/docs/docs/api/common.md @@ -145,6 +145,22 @@ const { intl, getLocale, setLocale } = common.utils.createIntl({ ``` +#### intl + +i18n 转换方法 + +```typescript +/** + * i18n 转换方法 + */ +intl(data: IPublicTypeI18nData | string, params?: object): string; +``` + +##### 示例 +``` +const title = common.utils.intl(node.title) +``` + ### skeletonCabin #### Workbench 编辑器框架 View diff --git a/packages/editor-core/src/intl/index.ts b/packages/editor-core/src/intl/index.ts index 6d9d840c3c..99e99a4fb9 100644 --- a/packages/editor-core/src/intl/index.ts +++ b/packages/editor-core/src/intl/index.ts @@ -3,6 +3,7 @@ import { IntlMessageFormat } from 'intl-messageformat'; import { globalLocale } from './global-locale'; import { isI18nData } from '@alilc/lowcode-utils'; import { observer } from '../utils'; +import { IPublicTypeI18nData } from '@alilc/lowcode-types'; function generateTryLocales(locale: string) { const tries = [locale, locale.replace('-', '_')]; @@ -26,18 +27,9 @@ function injectVars(msg: string, params: any, locale: string): string { } const formater = new IntlMessageFormat(msg, locale); return formater.format(params as any) as string; - /* - - return template.replace(/({\w+})/g, (_, $1) => { - const key = (/\d+/.exec($1) || [])[0] as any; - if (key && params[key] != null) { - return params[key]; - } - return $1; - }); */ } -export function intl(data: any, params?: object): ReactNode { +export function intl(data: IPublicTypeI18nData | string, params?: object): ReactNode { if (!isI18nData(data)) { return data; } diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx index a2e4d8c4fa..8ce07153ad 100644 --- a/packages/shell/src/api/common.tsx +++ b/packages/shell/src/api/common.tsx @@ -26,6 +26,7 @@ import { IPublicApiCommonEditorCabin, IPublicModelDragon, IPublicModelSettingField, + IPublicTypeI18nData, } from '@alilc/lowcode-types'; import { SettingField as InnerSettingField, @@ -261,6 +262,10 @@ class Utils implements IPublicApiCommonUtils { } { return innerCreateIntl(instance); } + + intl(data: IPublicTypeI18nData | string, params?: object): any { + return innerIntl(data, params); + } } class EditorCabin implements IPublicApiCommonEditorCabin { diff --git a/packages/types/src/shell/api/common.ts b/packages/types/src/shell/api/common.ts index 60fac1606d..05ef0da17f 100644 --- a/packages/types/src/shell/api/common.ts +++ b/packages/types/src/shell/api/common.ts @@ -1,6 +1,6 @@ import { Component, ReactNode } from 'react'; -import { IPublicTypeNodeSchema, IPublicTypeTitleContent } from '../type'; +import { IPublicTypeI18nData, IPublicTypeNodeSchema, IPublicTypeTitleContent } from '../type'; import { IPublicEnumTransitionType } from '../enum'; export interface IPublicApiCommonUtils { @@ -69,6 +69,11 @@ export interface IPublicApiCommonUtils { getLocale(): string; setLocale(locale: string): void; }; + + /** + * i18n 转换方法 + */ + intl(data: IPublicTypeI18nData | string, params?: object): string; } export interface IPublicApiCommonSkeletonCabin { From 3e7d199a7c3f1df2d813cafcb8109f24125ab4c7 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 11 Jan 2024 02:50:04 +0000 Subject: [PATCH 421/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index d1c3cd9f90..80396a0146 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.23", + "version": "1.2.24", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From bb5d7ddf827be5e72707cd1e5ccdf09f6ae16cc1 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 11 Jan 2024 10:59:44 +0800 Subject: [PATCH 422/469] feat(context-menu): update context-menu docs, details, styles --- docs/docs/api/commonUI.md | 62 +++++++++++++ docs/docs/api/material.md | 46 +++++++++ packages/designer/src/context-menu-actions.ts | 11 ++- packages/engine/src/engine-core.ts | 4 +- .../src/inner-plugins/default-context-menu.ts | 21 ++--- .../src/api/{commonUI.ts => commonUI.tsx} | 24 ++++- .../shell/src/components/context-menu.tsx | 28 +++++- packages/utils/src/context-menu.scss | 36 ++++--- packages/utils/src/context-menu.tsx | 93 ++++++++++++------- .../workspace/src/context/base-context.ts | 4 +- 10 files changed, 254 insertions(+), 75 deletions(-) rename packages/shell/src/api/{commonUI.ts => commonUI.tsx} (56%) diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md index f3afe1fc25..350d60dd7a 100644 --- a/docs/docs/api/commonUI.md +++ b/docs/docs/api/commonUI.md @@ -48,8 +48,70 @@ CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开 | condition | 显示条件函数<br/>Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | | | disabled | 禁用条件函数,可选<br/>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 ( + <div> + <ContextMenu menus={menuItems}> + <div>右键点击这里</div> + </ContextMenu> + </div> + ); +}; + +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 ( + <div> + <div onClick={(e) => { + ContextMenu.create(menuItems, e); + }}>点击这里</div> + </div> + ); +}; + +export default App; +``` ### Balloon + 详细文档: [Balloon Documentation](https://fusion.design/pc/component/balloon) ### Breadcrumb diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index c83935b971..d237180ca9 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -250,6 +250,33 @@ material.modifyBuiltinComponentAction('remove', (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 删除特定右键菜单项 @@ -274,7 +301,26 @@ removeContextMenuOption(name: string): void; 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 获取指定名称的物料元数据 diff --git a/packages/designer/src/context-menu-actions.ts b/packages/designer/src/context-menu-actions.ts index 5b44055b42..c3bad37da5 100644 --- a/packages/designer/src/context-menu-actions.ts +++ b/packages/designer/src/context-menu-actions.ts @@ -1,4 +1,4 @@ -import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial } from '@alilc/lowcode-types'; +import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial, IPublicModelPluginContext } from '@alilc/lowcode-types'; import { IDesigner, INode } from './designer'; import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties, uniqueId } from '@alilc/lowcode-utils'; import { Menu } from '@alifd/next'; @@ -48,6 +48,7 @@ export class GlobalContextMenuActions { event.preventDefault(); const actions: IPublicTypeContextMenuAction[] = []; + let contextMenu: ContextMenuActions = this.contextMenuActionsMap.values().next().value; this.contextMenuActionsMap.forEach((contextMenu) => { actions.push(...contextMenu.actions); }); @@ -57,11 +58,13 @@ export class GlobalContextMenuActions { const destroy = () => { destroyFn?.(); }; + const pluginContext: IPublicModelPluginContext = contextMenu.designer.editor.get('pluginContext') as IPublicModelPluginContext; const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, { nodes: [], destroy, event, + pluginContext, }); if (!menus.length) { @@ -73,6 +76,7 @@ export class GlobalContextMenuActions { const menuNode = parseContextMenuAsReactNode(layoutMenu, { destroy, nodes: [], + pluginContext, }); const target = event.target; @@ -160,10 +164,13 @@ export class ContextMenuActions implements IContextMenuActions { destroyFn?.(); }; + const pluginContext: IPublicModelPluginContext = this.designer.editor.get('pluginContext') as IPublicModelPluginContext; + const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, { nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!), destroy, event, + pluginContext, }); if (!menus.length) { @@ -175,7 +182,7 @@ export class ContextMenuActions implements IContextMenuActions { const menuNode = parseContextMenuAsReactNode(layoutMenu, { destroy, nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!), - designer, + pluginContext, }); destroyFn = createContextMenu(menuNode, { diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 29b4a7f038..3ccfdf51d1 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -115,12 +115,11 @@ const innerSetters = new InnerSetters(); const setters = new Setters(innerSetters); const material = new Material(editor); -const commonUI = new CommonUI(); +const commonUI = new CommonUI(editor); editor.set('project', project); editor.set('setters' as any, setters); editor.set('material', material); editor.set('innerHotkey', innerHotkey); -editor.set('commonUI' as any, commonUI); const config = new Config(engineConfig); const event = new Event(commonEvent, { prefix: 'common' }); const logger = new Logger({ level: 'warn', bizName: 'common' }); @@ -147,6 +146,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.commonUI = commonUI; context.registerLevel = IPublicEnumPluginRegisterLevel.Default; context.isPluginRegisteredInWorkspace = false; + editor.set('pluginContext', context); }, }; diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts index 9d1336b34e..db3d54a0c8 100644 --- a/packages/engine/src/inner-plugins/default-context-menu.ts +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -5,12 +5,11 @@ import { IPublicModelNode, IPublicModelPluginContext, IPublicTypeDragNodeDataObject, - IPublicTypeI18nData, IPublicTypeNodeSchema, } from '@alilc/lowcode-types'; -import { isI18nData, isProjectSchema } from '@alilc/lowcode-utils'; +import { isProjectSchema } from '@alilc/lowcode-utils'; import { Notification } from '@alifd/next'; -import { intl, getLocale } from '../locale'; +import { intl } from '../locale'; function getNodesSchema(nodes: IPublicModelNode[]) { const componentsTree = nodes.map((node) => node?.exportSchema(IPublicEnumTransformStage.Clone)); @@ -18,15 +17,6 @@ function getNodesSchema(nodes: IPublicModelNode[]) { return data; } -function getIntlStr(data: string | IPublicTypeI18nData) { - if (!isI18nData(data)) { - return data; - } - - const locale = getLocale(); - return data[locale] || data['zh-CN'] || data['zh_CN'] || data['en-US'] || data['en_US'] || ''; -} - async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> { return new Promise((resolve, reject) => { // 使用 Clipboard API 读取剪贴板内容 @@ -61,8 +51,9 @@ async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> { } export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { - const { material, canvas } = ctx; + const { material, canvas, common } = ctx; const { clipboard } = canvas; + const { intl: utilsIntl } = common.utils; return { init() { @@ -150,7 +141,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { }); if (canAddNodes.length === 0) { Notification.open({ - content: `${nodeSchema.map(d => getIntlStr(d.title || d.componentName)).join(',')}等组件无法放置到${getIntlStr(parent.title || parent.componentName as any)}内`, + content: `${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(parent.title || parent.componentName as any)}内`, type: 'error', }); return; @@ -198,7 +189,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { }); if (canAddNodes.length === 0) { Notification.open({ - content: `${nodeSchema.map(d => getIntlStr(d.title || d.componentName)).join(',')}等组件无法放置到${getIntlStr(node.title || node.componentName as any)}内`, + content: `${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(node.title || node.componentName as any)}内`, type: 'error', }); return; diff --git a/packages/shell/src/api/commonUI.ts b/packages/shell/src/api/commonUI.tsx similarity index 56% rename from packages/shell/src/api/commonUI.ts rename to packages/shell/src/api/commonUI.tsx index 9f40afa119..cb4b7ae38e 100644 --- a/packages/shell/src/api/commonUI.ts +++ b/packages/shell/src/api/commonUI.tsx @@ -1,12 +1,16 @@ -import { IPublicApiCommonUI } from '@alilc/lowcode-types'; +import { IPublicApiCommonUI, IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; import { + IEditor, Tip as InnerTip, Title as InnerTitle, } from '@alilc/lowcode-editor-core'; import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; import { ContextMenu } from '../components/context-menu'; +import { editorSymbol } from '../symbols'; export class CommonUI implements IPublicApiCommonUI { + [editorSymbol]: IEditor; + Balloon = Balloon; Breadcrumb = Breadcrumb; Button = Button; @@ -35,13 +39,29 @@ export class CommonUI implements IPublicApiCommonUI { Upload = Upload; Divider = Divider; + constructor(editor: IEditor) { + this[editorSymbol] = editor; + } + get Tip() { return InnerTip; } get Title() { return InnerTitle; } + get ContextMenu() { - return ContextMenu; + const editor = this[editorSymbol]; + const innerContextMenu = (props: any) => { + const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext; + return <ContextMenu {...props} pluginContext={pluginContext} />; + }; + + innerContextMenu.create = (menus: IPublicTypeContextMenuAction[], event: MouseEvent) => { + const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext; + return ContextMenu.create(pluginContext, menus, event); + }; + + return innerContextMenu; } } diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx index acefbebd28..d2e10abbfe 100644 --- a/packages/shell/src/components/context-menu.tsx +++ b/packages/shell/src/components/context-menu.tsx @@ -1,11 +1,12 @@ import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; import { engineConfig } from '@alilc/lowcode-editor-core'; -import { IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; +import { IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; import React from 'react'; -export function ContextMenu({ children, menus }: { +export function ContextMenu({ children, menus, pluginContext }: { menus: IPublicTypeContextMenuAction[]; children: React.ReactElement[] | React.ReactElement; + pluginContext: IPublicModelPluginContext; }): React.ReactElement<any, string | React.JSXElementConstructor<any>> { if (!engineConfig.get('enableContextMenu')) { return ( @@ -23,7 +24,10 @@ export function ContextMenu({ children, menus }: { }; const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, { destroy, - })); + pluginContext, + }), { + pluginContext, + }); if (!children?.length) { return; @@ -44,4 +48,20 @@ export function ContextMenu({ children, menus }: { return ( <>{childrenWithContextMenu}</> ); -} \ No newline at end of file +} + +ContextMenu.create = (pluginContext: IPublicModelPluginContext, menus: IPublicTypeContextMenuAction[], event: MouseEvent) => { + const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, { + pluginContext, + }), { + pluginContext, + }); + + if (!children?.length) { + return; + } + + return createContextMenu(children, { + event, + }); +}; \ No newline at end of file diff --git a/packages/utils/src/context-menu.scss b/packages/utils/src/context-menu.scss index 0bcf39d153..366d03e45a 100644 --- a/packages/utils/src/context-menu.scss +++ b/packages/utils/src/context-menu.scss @@ -1,32 +1,42 @@ -.context-menu-tree-wrap { +.engine-context-menu-tree-wrap { position: relative; padding: 4px 10px 4px 32px; } -.context-menu-tree-children { +.engine-context-menu-tree-children { margin-left: 8px; line-height: 24px; } -.context-menu-tree-bg { - position: absolute; - left: 0; - right: 0; - cursor: pointer; +.engine-context-menu-item { + .engine-context-menu-text { + color: var(--color-text); + } + + &:hover { + .engine-context-menu-text { + color: var(--color-title); + } + } + + &.disbale { + .engine-context-menu-text { + color: var(--color-text-disabled); + } + } } -.context-menu-tree-bg-inner { - position: absolute; - height: 24px; - top: -24px; - width: 100%; +.engine-context-menu-title { + color: var(--color-text); + cursor: pointer; &:hover { background-color: var(--color-block-background-light); + color: var(--color-title); } } -.context-menu-tree-selected-icon { +.engine-context-menu-tree-selecte-icon { position: absolute; left: 10px; color: var(--color-icon-active); diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx index 1816f5b526..0f157e4383 100644 --- a/packages/utils/src/context-menu.tsx +++ b/packages/utils/src/context-menu.tsx @@ -1,7 +1,7 @@ import { Menu, Icon } from '@alifd/next'; -import { IDesigner } from '@alilc/lowcode-designer'; -import { IPublicEnumContextMenuType, IPublicModelNode, IPublicTypeContextMenuAction, IPublicTypeContextMenuItem } from '@alilc/lowcode-types'; +import { IPublicEnumContextMenuType, IPublicModelNode, IPublicModelPluginContext, IPublicTypeContextMenuAction, IPublicTypeContextMenuItem } from '@alilc/lowcode-types'; import { Logger } from '@alilc/lowcode-utils'; +import classNames from 'classnames'; import React from 'react'; import './context-menu.scss'; @@ -10,43 +10,51 @@ const { Item, Divider, PopupItem } = Menu; const MAX_LEVEL = 2; +interface IOptions { + nodes?: IPublicModelNode[] | null; + destroy?: Function; + pluginContext: IPublicModelPluginContext; +} + const Tree = (props: { - node?: IPublicModelNode; + node?: IPublicModelNode | null; children?: React.ReactNode; - options: { - nodes?: IPublicModelNode[] | null; - destroy?: Function; - designer?: IDesigner; - }; + options: IOptions; }) => { const { node } = props; if (!node) { return ( - <div className="context-menu-tree-wrap">{ props.children }</div> + <div className="engine-context-menu-tree-wrap">{ props.children }</div> ); } - const commonUI = props.options.designer?.editor?.get('commonUI'); - - const Title = commonUI?.Title; + const { common } = props.options.pluginContext || {}; + const { intl } = common?.utils || {}; + const indent = node.zLevel * 8 + 32; + const style = { + paddingLeft: indent, + marginLeft: -indent, + marginRight: -10, + paddingRight: 10, + }; return ( <Tree {...props} node={node.parent} > - {props.options.nodes?.[0].id === node.id ? (<Icon className="context-menu-tree-selected-icon" size="small" type="success" />) : null} - <Title title={node.title} /> <div - className="context-menu-tree-children" + className="engine-context-menu-title" + onClick={() => { + props.options.destroy?.(); + node.select(); + }} + style={style} + > + {props.options.nodes?.[0].id === node.id ? (<Icon className="engine-context-menu-tree-selecte-icon" size="small" type="success" />) : null} + {intl(node.title)} + </div> + <div + className="engine-context-menu-tree-children" > - <div - className="context-menu-tree-bg" - onClick={() => { - props.options.destroy?.(); - node.select(); - }} - > - <div className="context-menu-tree-bg-inner" /> - </div> { props.children } </div> </Tree> @@ -55,11 +63,10 @@ const Tree = (props: { let destroyFn: Function | undefined; -export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], options: { - nodes?: IPublicModelNode[] | null; - destroy?: Function; - designer?: IDesigner; -} = {}): React.ReactNode[] { +export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], options: IOptions): React.ReactNode[] { + const { common } = options.pluginContext || {}; + const { intl = (title: any) => title } = common?.utils || {}; + const children: React.ReactNode[] = []; menus.forEach((menu, index) => { if (menu.type === IPublicEnumContextMenuType.SEPARATOR) { @@ -70,14 +77,33 @@ export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], if (menu.type === IPublicEnumContextMenuType.MENU_ITEM) { if (menu.items && menu.items.length) { children.push(( - <PopupItem key={menu.name} label={menu.title}> + <PopupItem + className={classNames('engine-context-menu-item', { + disbale: menu.disabled, + })} + key={menu.name} + label={<div className="engine-context-menu-text">{intl(menu.title)}</div>} + > <Menu className="next-context engine-context-menu"> { parseContextMenuAsReactNode(menu.items, options) } </Menu> </PopupItem> )); } else { - children.push((<Item disabled={menu.disabled} onClick={menu.action} key={menu.name}>{menu.title}</Item>)); + children.push(( + <Item + className={classNames('engine-context-menu-item', { + disbale: menu.disabled, + })} + disabled={menu.disabled} + onClick={menu.action} + key={menu.name} + > + <div className="engine-context-menu-text"> + {intl(menu.title)} + </div> + </Item> + )); } } @@ -91,9 +117,7 @@ export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], return children; } -export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction | Omit<IPublicTypeContextMenuAction, 'items'>)[], options: { - nodes?: IPublicModelNode[] | null; - destroy?: Function; +export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction | Omit<IPublicTypeContextMenuAction, 'items'>)[], options: IOptions & { event?: MouseEvent; }, level = 1): IPublicTypeContextMenuItem[] { destroyFn?.(); @@ -156,7 +180,6 @@ function getMenuItemHeight() { } const root = document.documentElement; const styles = getComputedStyle(root); - // Access the value of the CSS variable const menuItemHeight = styles.getPropertyValue('--context-menu-item-height').trim(); cachedMenuItemHeight = menuItemHeight; diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index e090d1e374..2f6154788f 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -128,13 +128,12 @@ export class BasicContext implements IBasicContext { const logger = getLogger({ level: 'warn', bizName: 'common' }); const skeleton = new Skeleton(innerSkeleton, 'any', true); const canvas = new Canvas(editor, true); - const commonUI = new CommonUI(); + const commonUI = new CommonUI(editor); editor.set('setters', setters); editor.set('project', project); editor.set('material', material); editor.set('hotkey', hotkey); editor.set('innerHotkey', innerHotkey); - editor.set('commonUI' as any, commonUI); this.innerSetters = innerSetters; this.innerSkeleton = innerSkeleton; this.skeleton = skeleton; @@ -175,6 +174,7 @@ export class BasicContext implements IBasicContext { } context.registerLevel = registerLevel; context.isPluginRegisteredInWorkspace = registerLevel === IPublicEnumPluginRegisterLevel.Workspace; + editor.set('pluginContext', context); }, }; From 18642ee92312fd335cb8d793bfc0136ccad7ad58 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 11 Jan 2024 03:17:25 +0000 Subject: [PATCH 423/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 80396a0146..1626d99578 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.24", + "version": "1.2.25", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From ce72fc1b16912312ab9fb2a38bba811dbea7ef13 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 11 Jan 2024 18:03:22 +0800 Subject: [PATCH 424/469] feat(common-ui): add HelpTip --- docs/docs/api/commonUI.md | 10 +++++ .../editor-core/src/widgets/tip/help-tips.tsx | 40 +++++++++++++++++++ packages/editor-core/src/widgets/tip/index.ts | 1 + .../src/components/widget-views/index.tsx | 24 +---------- packages/shell/src/api/commonUI.tsx | 6 +++ packages/types/src/shell/api/commonUI.ts | 36 +++++++++++++---- 6 files changed, 87 insertions(+), 30 deletions(-) create mode 100644 packages/editor-core/src/widgets/tip/help-tips.tsx diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md index 350d60dd7a..c0bbda588e 100644 --- a/docs/docs/api/commonUI.md +++ b/docs/docs/api/commonUI.md @@ -19,6 +19,16 @@ CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开 | direction | tip 的方向 | 'top' \| 'bottom' \| 'left' \| 'right' | | +### HelpTip + +带 help icon 的提示组件 + +| 参数 | 说明 | 类型 | 默认值 | +|-----------|--------|-----------------------------------|--------| +| help | 描述 | IPublicTypeHelpTipConfig | | +| direction | 方向 | IPublicTypeTipConfig['direction'] | 'top' | +| size | 方向 | IconProps['size'] | 'small'| + ### Title 标题组件 diff --git a/packages/editor-core/src/widgets/tip/help-tips.tsx b/packages/editor-core/src/widgets/tip/help-tips.tsx new file mode 100644 index 0000000000..ab5f65050e --- /dev/null +++ b/packages/editor-core/src/widgets/tip/help-tips.tsx @@ -0,0 +1,40 @@ +import { IPublicTypeHelpTipConfig, IPublicTypeTipConfig } from '@alilc/lowcode-types'; +import { Tip } from './tip'; +import { Icon } from '@alifd/next'; +import { IconProps } from '@alifd/next/types/icon'; + +export function HelpTip({ + help, + direction = 'top', + size = 'small', +}: { + help: IPublicTypeHelpTipConfig; + direction?: IPublicTypeTipConfig['direction']; + size?: IconProps['size']; +}) { + if (typeof help === 'string') { + return ( + <div> + <Icon type="help" size={size} className="lc-help-tip" /> + <Tip direction={direction}>{help}</Tip> + </div> + ); + } + + if (typeof help === 'object' && help.url) { + return ( + <div> + <a href={help.url} target="_blank" rel="noopener noreferrer"> + <Icon type="help" size={size} className="lc-help-tip" /> + </a> + <Tip direction={direction}>{help.content}</Tip> + </div> + ); + } + return ( + <div> + <Icon type="help" size="small" className="lc-help-tip" /> + <Tip direction={direction}>{help.content}</Tip> + </div> + ); +} \ No newline at end of file diff --git a/packages/editor-core/src/widgets/tip/index.ts b/packages/editor-core/src/widgets/tip/index.ts index dba4412c7f..d2b3768003 100644 --- a/packages/editor-core/src/widgets/tip/index.ts +++ b/packages/editor-core/src/widgets/tip/index.ts @@ -2,3 +2,4 @@ import './style.less'; export * from './tip'; export * from './tip-container'; +export * from './help-tips'; diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index 2b2f6931cb..7cdff4c014 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -1,7 +1,6 @@ import { Component, ReactElement } from 'react'; -import { Icon } from '@alifd/next'; import classNames from 'classnames'; -import { Title, observer, Tip } from '@alilc/lowcode-editor-core'; +import { Title, observer, HelpTip } from '@alilc/lowcode-editor-core'; import { DockProps } from '../../types'; import { PanelDock } from '../../widget/panel-dock'; import { composeTitle } from '../../widget/utils'; @@ -26,25 +25,6 @@ export function DockView({ title, icon, description, size, className, onClick }: ); } -function HelpTip({ tip }: any) { - if (tip && tip.url) { - return ( - <div> - <a href={tip.url} target="_blank" rel="noopener noreferrer"> - <Icon type="help" size="small" className="lc-help-tip" /> - </a> - <Tip>{tip.content}</Tip> - </div> - ); - } - return ( - <div> - <Icon type="help" size="small" className="lc-help-tip" /> - <Tip>{tip.content}</Tip> - </div> - ); -} - @observer export class PanelDockView extends Component<DockProps & { dock: PanelDock }> { private lastActived = false; @@ -328,7 +308,7 @@ class PanelTitle extends Component<{ panel: Panel; className?: string }> { data-name={panel.name} > <Title title={panel.title || panel.name} /> - {panel.help ? <HelpTip tip={panel.help} /> : null} + {panel.help ? <HelpTip help={panel.help} /> : null} </div> ); } diff --git a/packages/shell/src/api/commonUI.tsx b/packages/shell/src/api/commonUI.tsx index cb4b7ae38e..0a9021fe6a 100644 --- a/packages/shell/src/api/commonUI.tsx +++ b/packages/shell/src/api/commonUI.tsx @@ -1,5 +1,6 @@ import { IPublicApiCommonUI, IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; import { + HelpTip, IEditor, Tip as InnerTip, Title as InnerTitle, @@ -46,6 +47,11 @@ export class CommonUI implements IPublicApiCommonUI { get Tip() { return InnerTip; } + + get HelpTip() { + return HelpTip; + } + get Title() { return InnerTitle; } diff --git a/packages/types/src/shell/api/commonUI.ts b/packages/types/src/shell/api/commonUI.ts index 71e2bbe83f..5ac025fcde 100644 --- a/packages/types/src/shell/api/commonUI.ts +++ b/packages/types/src/shell/api/commonUI.ts @@ -1,6 +1,7 @@ -import { ReactElement } from 'react'; -import { IPublicTypeContextMenuAction, IPublicTypeTitleContent } from '../type'; +import React, { ReactElement } from 'react'; +import { IPublicTypeContextMenuAction, IPublicTypeHelpTipConfig, IPublicTypeTipConfig, IPublicTypeTitleContent } from '../type'; import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; +import { IconProps } from '@alifd/next/types/icon'; export interface IPublicApiCommonUI { Balloon: typeof Balloon; @@ -33,13 +34,30 @@ export interface IPublicApiCommonUI { /** * Title 组件 - * @experimental unstable API, pay extra caution when trying to use this */ - get Tip(): React.ComponentClass<{}>; + get Tip(): React.ComponentClass<IPublicTypeTipConfig>; + + /** + * HelpTip 组件 + */ + get HelpTip(): React.VFC<{ + help: IPublicTypeHelpTipConfig; + + /** + * 方向 + * @default 'top' + */ + direction: IPublicTypeTipConfig['direction']; + + /** + * 大小 + * @default 'small' + */ + size: IconProps['size']; + }>; /** * Tip 组件 - * @experimental unstable API, pay extra caution when trying to use this */ get Title(): React.ComponentClass<{ title: IPublicTypeTitleContent | undefined; @@ -47,8 +65,10 @@ export interface IPublicApiCommonUI { keywords?: string | null; }>; - get ContextMenu(): (props: { + get ContextMenu(): ((props: { menus: IPublicTypeContextMenuAction[]; children: React.ReactElement[] | React.ReactElement; - }) => ReactElement; -} \ No newline at end of file + }) => ReactElement) & { + create(menus: IPublicTypeContextMenuAction[], event: MouseEvent | React.MouseEvent): void; + }; +} From 6f9359e042191d488a7bf9687a1e5a45d46dfcfa Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 11 Jan 2024 10:13:55 +0000 Subject: [PATCH 425/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 1626d99578..6a029b851b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.25", + "version": "1.2.26", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 844ca783d720e5d8829a8e8e54314c97997ec275 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 11 Jan 2024 18:49:21 +0800 Subject: [PATCH 426/469] feat(context-menu): add context-menu css theme, help config, ts define --- docs/docs/guide/expand/editor/theme.md | 5 +++ .../designer/src/builtin-simulator/host.ts | 8 ++++- packages/designer/src/context-menu-actions.ts | 2 ++ .../src/inner-plugins/default-context-menu.ts | 36 +++++++++++-------- .../shell/src/components/context-menu.tsx | 8 ++--- packages/types/src/shell/type/context-menu.ts | 14 +++++--- packages/utils/src/context-menu.scss | 21 +++++++---- packages/utils/src/context-menu.tsx | 33 ++++++++++------- 8 files changed, 81 insertions(+), 46 deletions(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 1c442c5132..897b6b360b 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -53,6 +53,11 @@ sidebar_position: 9 - `--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 标签颜色 diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 6efe6a68b5..57f8569326 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -832,16 +832,22 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp doc.addEventListener('contextmenu', (e: MouseEvent) => { const targetElement = e.target as HTMLElement; const nodeInst = this.getNodeInstanceFromElement(targetElement); + const editor = this.designer?.editor; if (!nodeInst) { + editor?.eventBus.emit('designer.builtinSimulator.contextmenu', { + originalEvent: e, + }); return; } const node = nodeInst.node || this.project.currentDocument?.focusNode; if (!node) { + editor?.eventBus.emit('designer.builtinSimulator.contextmenu', { + originalEvent: e, + }); return; } // dirty code should refector - const editor = this.designer?.editor; const npm = node?.componentMeta?.npm; const selected = [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || diff --git a/packages/designer/src/context-menu-actions.ts b/packages/designer/src/context-menu-actions.ts index c3bad37da5..c88e03ac65 100644 --- a/packages/designer/src/context-menu-actions.ts +++ b/packages/designer/src/context-menu-actions.ts @@ -201,6 +201,8 @@ export class ContextMenuActions implements IContextMenuActions { node: INode; originalEvent: MouseEvent; }) => { + originalEvent.stopPropagation(); + originalEvent.preventDefault(); // 如果右键的节点不在 当前选中的节点中,选中该节点 if (!designer.currentSelection.has(node.id)) { designer.currentSelection.select(node.id); diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts index db3d54a0c8..c8997aa7ed 100644 --- a/packages/engine/src/inner-plugins/default-context-menu.ts +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -60,7 +60,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'selectComponent', title: intl('SelectComponents'), - condition: (nodes) => { + condition: (nodes = []) => { return nodes.length === 1; }, items: [ @@ -74,14 +74,17 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copyAndPaste', title: intl('CopyAndPaste'), - disabled: (nodes) => { + disabled: (nodes = []) => { return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0; }, condition: (nodes) => { - return nodes.length === 1; + return nodes?.length === 1; }, action(nodes) { - const node = nodes[0]; + const node = nodes?.[0]; + if (!node) { + return; + } const { document: doc, parent, index } = node; const data = getNodesSchema(nodes); clipboard.setData(data); @@ -96,11 +99,11 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copy', title: intl('Copy'), - disabled: (nodes) => { + disabled: (nodes = []) => { return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0; }, - condition(nodes) { - return nodes.length > 0; + condition(nodes = []) { + return nodes?.length > 0; }, action(nodes) { if (!nodes || nodes.length < 1) { @@ -116,7 +119,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { name: 'pasteToBottom', title: intl('PasteToTheBottom'), condition: (nodes) => { - return nodes.length === 1; + return nodes?.length === 1; }, async action(nodes) { if (!nodes || nodes.length < 1) { @@ -163,15 +166,18 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { name: 'pasteToInner', title: intl('PasteToTheInside'), condition: (nodes) => { - return nodes.length === 1; + return nodes?.length === 1; }, - disabled: (nodes) => { + disabled: (nodes = []) => { // 获取粘贴数据 - const node = nodes[0]; + const node = nodes?.[0]; return !node.isContainerNode; }, async action(nodes) { - const node = nodes[0]; + const node = nodes?.[0]; + if (!node) { + return; + } const { document: doc } = node; try { @@ -210,14 +216,14 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'delete', title: intl('Delete'), - disabled(nodes) { + disabled(nodes = []) { return nodes?.filter((node) => !node?.canPerformAction('remove')).length > 0; }, - condition(nodes) { + condition(nodes = []) { return nodes.length > 0; }, action(nodes) { - nodes.forEach((node) => { + nodes?.forEach((node) => { node.remove(); }); }, diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx index d2e10abbfe..c752e79903 100644 --- a/packages/shell/src/components/context-menu.tsx +++ b/packages/shell/src/components/context-menu.tsx @@ -25,17 +25,13 @@ export function ContextMenu({ children, menus, pluginContext }: { const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, { destroy, pluginContext, - }), { - pluginContext, - }); + }), { pluginContext }); if (!children?.length) { return; } - destroyFn = createContextMenu(children, { - event, - }); + destroyFn = createContextMenu(children, { event }); }; // 克隆 children 并添加 onContextMenu 事件处理器 diff --git a/packages/types/src/shell/type/context-menu.ts b/packages/types/src/shell/type/context-menu.ts index 1eeb93d696..dd6d583c25 100644 --- a/packages/types/src/shell/type/context-menu.ts +++ b/packages/types/src/shell/type/context-menu.ts @@ -1,6 +1,7 @@ import { IPublicEnumContextMenuType } from '../enum'; import { IPublicModelNode } from '../model'; import { IPublicTypeI18nData } from './i8n-data'; +import { IPublicTypeHelpTipConfig } from './widget-base-config'; export interface IPublicTypeContextMenuItem extends Omit<IPublicTypeContextMenuAction, 'condition' | 'disabled' | 'items'> { disabled?: boolean; @@ -34,24 +35,29 @@ export interface IPublicTypeContextMenuAction { * 点击时执行的动作,可选 * Action to execute on click, optional */ - action?: (nodes: IPublicModelNode[], event?: MouseEvent) => void; + action?: (nodes?: IPublicModelNode[], event?: MouseEvent) => void; /** * 子菜单项或生成子节点的函数,可选,仅支持两级 * Sub-menu items or function to generate child node, optional */ - items?: Omit<IPublicTypeContextMenuAction, 'items'>[] | ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]); + items?: Omit<IPublicTypeContextMenuAction, 'items'>[] | ((nodes?: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]); /** * 显示条件函数 * Function to determine display condition */ - condition?: (nodes: IPublicModelNode[]) => boolean; + condition?: (nodes?: IPublicModelNode[]) => boolean; /** * 禁用条件函数,可选 * Function to determine disabled condition, optional */ - disabled?: (nodes: IPublicModelNode[]) => boolean; + disabled?: (nodes?: IPublicModelNode[]) => boolean; + + /** + * 帮助提示,可选 + */ + help?: IPublicTypeHelpTipConfig; } diff --git a/packages/utils/src/context-menu.scss b/packages/utils/src/context-menu.scss index 366d03e45a..0b75ca3ec1 100644 --- a/packages/utils/src/context-menu.scss +++ b/packages/utils/src/context-menu.scss @@ -10,24 +10,31 @@ .engine-context-menu-item { .engine-context-menu-text { - color: var(--color-text); + color: var(--color-context-menu-text, var(--color-text)); + display: flex; + align-items: center; + + .lc-help-tip { + margin-left: 4px; + opacity: 0.8; + } } - &:hover { - .engine-context-menu-text { - color: var(--color-title); + &.disabled { + &:hover .engine-context-menu-text, .engine-context-menu-text { + color: var(--color-context-menu-text-disabled, var(--color-text-disabled)); } } - &.disbale { + &:hover { .engine-context-menu-text { - color: var(--color-text-disabled); + color: var(--color-context-menu-text-hover, var(--color-title)); } } } .engine-context-menu-title { - color: var(--color-text); + color: var(--color-context-menu-text, var(--color-text)); cursor: pointer; &:hover { diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx index 0f157e4383..d783a96434 100644 --- a/packages/utils/src/context-menu.tsx +++ b/packages/utils/src/context-menu.tsx @@ -64,8 +64,9 @@ const Tree = (props: { let destroyFn: Function | undefined; export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], options: IOptions): React.ReactNode[] { - const { common } = options.pluginContext || {}; + const { common, commonUI } = options.pluginContext || {}; const { intl = (title: any) => title } = common?.utils || {}; + const { HelpTip } = commonUI || {}; const children: React.ReactNode[] = []; menus.forEach((menu, index) => { @@ -79,7 +80,7 @@ export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], children.push(( <PopupItem className={classNames('engine-context-menu-item', { - disbale: menu.disabled, + disabled: menu.disabled, })} key={menu.name} label={<div className="engine-context-menu-text">{intl(menu.title)}</div>} @@ -93,14 +94,17 @@ export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], children.push(( <Item className={classNames('engine-context-menu-item', { - disbale: menu.disabled, + disabled: menu.disabled, })} disabled={menu.disabled} - onClick={menu.action} + onClick={() => { + menu.action?.(); + }} key={menu.name} > <div className="engine-context-menu-text"> - {intl(menu.title)} + { menu.title ? intl(menu.title) : null } + { menu.help ? <HelpTip size="xs" help={menu.help} direction="right" /> : null } </div> </Item> )); @@ -135,12 +139,14 @@ export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction name, title, type = IPublicEnumContextMenuType.MENU_ITEM, + help, } = menu; const result: IPublicTypeContextMenuItem = { name, title, type, + help, action: () => { destroy?.(); menu.action?.(nodes || [], options.event); @@ -193,26 +199,27 @@ export function createContextMenu(children: React.ReactNode[], { event: MouseEvent | React.MouseEvent; offset?: [number, number]; }) { + event.preventDefault(); + event.stopPropagation(); + const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const dividerCount = React.Children.count(children.filter(child => React.isValidElement(child) && child.type === Divider)); const popupItemCount = React.Children.count(children.filter(child => React.isValidElement(child) && (child.type === PopupItem || child.type === Item))); const menuHeight = popupItemCount * parseInt(getMenuItemHeight(), 10) + dividerCount * 8 + 16; const menuWidthLimit = 200; - const target = event.target; - const { top, left } = (target as any)?.getBoundingClientRect(); - let x = event.clientX - left + offset[0]; - let y = event.clientY - top + offset[1]; - if (x + menuWidthLimit + left > viewportWidth) { + let x = event.clientX + offset[0]; + let y = event.clientY + offset[1]; + if (x + menuWidthLimit > viewportWidth) { x = x - menuWidthLimit; } - if (y + menuHeight + top > viewportHeight) { + if (y + menuHeight > viewportHeight) { y = y - menuHeight; } const menuInstance = Menu.create({ - target, - offset: [x, y, 0, 0], + target: document.body, + offset: [x, y], children, className: 'engine-context-menu', }); From 8931d8393d74133fe0f3201d1826fffc7d2849d1 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 12 Jan 2024 01:17:52 +0000 Subject: [PATCH 427/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 6a029b851b..643bdace2b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.26", + "version": "1.2.27", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 34a5a11b49cac4eddd0a4871cf0bb7e16543a493 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 12 Jan 2024 15:51:18 +0800 Subject: [PATCH 428/469] fix: fix clipboard.setData fial in workspace mode --- packages/designer/src/designer/clipboard.ts | 4 ++++ packages/designer/src/designer/designer-view.tsx | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/designer/src/designer/clipboard.ts b/packages/designer/src/designer/clipboard.ts index 941f914428..26f57f8112 100644 --- a/packages/designer/src/designer/clipboard.ts +++ b/packages/designer/src/designer/clipboard.ts @@ -36,6 +36,10 @@ class Clipboard implements IClipboard { private waitFn?: (data: any, e: ClipboardEvent) => void; + constructor() { + this.injectCopyPaster(document); + } + isCopyPasteEvent(e: Event) { this.isCopyPaster(e.target); } diff --git a/packages/designer/src/designer/designer-view.tsx b/packages/designer/src/designer/designer-view.tsx index 0db2a3fa3e..aaf0c9583e 100644 --- a/packages/designer/src/designer/designer-view.tsx +++ b/packages/designer/src/designer/designer-view.tsx @@ -4,7 +4,6 @@ import BuiltinDragGhostComponent from './drag-ghost'; import { Designer, DesignerProps } from './designer'; import { ProjectView } from '../project'; import './designer.less'; -import { clipboard } from './clipboard'; type IProps = DesignerProps & { designer?: Designer; @@ -44,7 +43,6 @@ export class DesignerView extends Component<IProps> { if (onMount) { onMount(this.designer); } - clipboard.injectCopyPaster(document); this.designer.postEvent('mount', this.designer); } From 1132a30483e31d82e33d8aa036f6733bfad67483 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 12 Jan 2024 15:52:36 +0800 Subject: [PATCH 429/469] feat: update context-menu message --- .../src/inner-plugins/default-context-menu.ts | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts index c8997aa7ed..81978d9209 100644 --- a/packages/engine/src/inner-plugins/default-context-menu.ts +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -8,7 +8,7 @@ import { IPublicTypeNodeSchema, } from '@alilc/lowcode-types'; import { isProjectSchema } from '@alilc/lowcode-utils'; -import { Notification } from '@alifd/next'; +import { Message } from '@alifd/next'; import { intl } from '../locale'; function getNodesSchema(nodes: IPublicModelNode[]) { @@ -27,19 +27,13 @@ async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> { if (isProjectSchema(data)) { resolve(data.componentsTree); } else { - Notification.open({ - content: intl('NotValidNodeData'), - type: 'error', - }); + Message.error(intl('NotValidNodeData')); reject( new Error(intl('NotValidNodeData')), ); } } catch (error) { - Notification.open({ - content: intl('NotValidNodeData'), - type: 'error', - }); + Message.error(intl('NotValidNodeData')); reject(error); } }, @@ -143,10 +137,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { return doc?.checkNesting(parent, dragNodeObject); }); if (canAddNodes.length === 0) { - Notification.open({ - content: `${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(parent.title || parent.componentName as any)}内`, - type: 'error', - }); + Message.error(`${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(parent.title || parent.componentName as any)}内`); return; } const nodes: IPublicModelNode[] = []; @@ -194,10 +185,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { return doc?.checkNesting(node, dragNodeObject); }); if (canAddNodes.length === 0) { - Notification.open({ - content: `${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(node.title || node.componentName as any)}内`, - type: 'error', - }); + Message.error(`${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(node.title || node.componentName as any)}内`); return; } From adb9f6b090a71052ece0b10d3b6e48125c8799e8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 15 Jan 2024 10:02:26 +0800 Subject: [PATCH 430/469] fix(canvas): clipboard init error --- packages/designer/src/designer/clipboard.ts | 8 +++++++- packages/types/src/shell/api/material.ts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/designer/src/designer/clipboard.ts b/packages/designer/src/designer/clipboard.ts index 26f57f8112..34ce2b5b53 100644 --- a/packages/designer/src/designer/clipboard.ts +++ b/packages/designer/src/designer/clipboard.ts @@ -73,7 +73,13 @@ class Clipboard implements IClipboard { } const copyPaster = document.createElement<'textarea'>('textarea'); copyPaster.style.cssText = 'position: absolute;left: -9999px;top:-100px'; - document.body.appendChild(copyPaster); + if (document.body) { + document.body.appendChild(copyPaster); + } else { + document.addEventListener('DOMContentLoaded', () => { + document.body.appendChild(copyPaster); + }); + } const dispose = this.initCopyPaster(copyPaster); return () => { dispose(); diff --git a/packages/types/src/shell/api/material.ts b/packages/types/src/shell/api/material.ts index 6354c7fa0f..89b2b39ad1 100644 --- a/packages/types/src/shell/api/material.ts +++ b/packages/types/src/shell/api/material.ts @@ -15,7 +15,7 @@ export interface IPublicApiMaterial { * set data for Assets * @returns void */ - setAssets(assets: IPublicTypeAssetsJson): void; + setAssets(assets: IPublicTypeAssetsJson): Promise<void>; /** * 获取「资产包」结构 From d1a8bacd75df198ca0f97ebaf985bd3438049114 Mon Sep 17 00:00:00 2001 From: eightHundreds <mingoing@outlook.com> Date: Mon, 15 Jan 2024 12:10:52 +0800 Subject: [PATCH 431/469] fix(designer): node.ts cannot generate declaration file --- packages/designer/src/document/node/node.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 4071fb9138..c8363d0586 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -392,7 +392,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> this.isInited = true; this.emitter = createModuleEventBus('Node'); - const editor = this.document.designer.editor; + const { editor } = this.document.designer; this.onVisibleChange((visible: boolean) => { editor?.eventBus.emit(EDITOR_EVENT.NODE_VISIBLE_CHANGE, this, visible); }); @@ -1219,11 +1219,18 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> /** * 获取磁贴相关信息 */ - getRGL() { + getRGL(): { + isContainerNode: boolean; + isEmptyNode: boolean; + isRGLContainerNode: boolean; + isRGLNode: boolean; + isRGL: boolean; + rglNode: Node | null; + } { const isContainerNode = this.isContainer(); const isEmptyNode = this.isEmpty(); const isRGLContainerNode = this.isRGLContainer; - const isRGLNode = this.getParent()?.isRGLContainer; + const isRGLNode = (this.getParent()?.isRGLContainer) as boolean; const isRGL = isRGLContainerNode || (isRGLNode && (!isContainerNode || !isEmptyNode)); let rglNode = isRGLContainerNode ? this : isRGL ? this?.getParent() : null; return { isContainerNode, isEmptyNode, isRGLContainerNode, isRGLNode, isRGL, rglNode }; From e77063636cd053a2ca7730298520bef56e246651 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 15 Jan 2024 14:02:38 +0800 Subject: [PATCH 432/469] chore: add pub:minor and pub:major commands --- .github/workflows/publish engine.yml | 6 +++++- package.json | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index 6825c66fca..ab63eec52e 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -2,6 +2,10 @@ name: Publish Engine on: workflow_dispatch: + inputs: + publishCommand: + description: 'publish command' + required: true jobs: publish-engine: @@ -21,7 +25,7 @@ jobs: npm run build git config --local user.email "action@github.com" git config --local user.name "GitHub Action" - - run: npm run pub + - run: npm run ${{ github.event.inputs.publishCommand }} env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version diff --git a/package.json b/package.json index caabbeeb13..6562cec3b5 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,8 @@ "lint:modules": "f2elint scan -q -i ./modules/*/src", "lint:modules:fix": "f2elint fix -i ./modules/*/src", "pub": "npm run watchdog:build && lerna publish patch --yes --force-publish --exact --no-changelog", + "pub:minor": "npm run watchdog:build && lerna publish minor --yes --force-publish --exact --no-changelog", + "pub:major": "npm run watchdog:build && lerna publish major --yes --force-publish --exact --no-changelog", "pub:premajor": "npm run watchdog:build && lerna publish premajor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:preminor": "npm run watchdog:build && lerna publish preminor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:prepatch": "npm run watchdog:build && lerna publish prepatch --force-publish --exact --dist-tag beta --preid beta --no-changelog", From d957be8072a7d9004c5b5875a39861386ac8e52b Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 15 Jan 2024 14:02:38 +0800 Subject: [PATCH 433/469] chore: add pub:minor and pub:major commands --- .github/workflows/publish engine.yml | 6 +++++- package.json | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index ad4c3963b2..dcbf0547e7 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -2,6 +2,10 @@ name: Publish Engine on: workflow_dispatch: + inputs: + publishCommand: + description: 'publish command' + required: true jobs: publish-engine: @@ -21,7 +25,7 @@ jobs: npm run build git config --local user.email "action@github.com" git config --local user.name "GitHub Action" - - run: npm run pub + - run: npm run ${{ github.event.inputs.publishCommand }} env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version diff --git a/package.json b/package.json index 047b287b98..8b566e0f0c 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,8 @@ "lint:modules": "f2elint scan -q -i ./modules/*/src", "lint:modules:fix": "f2elint fix -i ./modules/*/src", "pub": "npm run watchdog:build && lerna publish patch --yes --force-publish --exact --no-changelog", + "pub:minor": "npm run watchdog:build && lerna publish minor --yes --force-publish --exact --no-changelog", + "pub:major": "npm run watchdog:build && lerna publish major --yes --force-publish --exact --no-changelog", "pub:premajor": "npm run watchdog:build && lerna publish premajor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:preminor": "npm run watchdog:build && lerna publish preminor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:prepatch": "npm run watchdog:build && lerna publish prepatch --force-publish --exact --dist-tag beta --preid beta --no-changelog", From 1943172d65ece0608e7fef760bd35a4c93c9b2a2 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 15 Jan 2024 06:12:28 +0000 Subject: [PATCH 434/469] chore(release): publish 1.3.0 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 15 files changed, 57 insertions(+), 57 deletions(-) diff --git a/lerna.json b/lerna.json index 1170309170..33d4899d0c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.5", + "version": "1.3.0", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 0e6e67e882..5ecf6c1390 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.5", + "version": "1.3.0", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.5", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-editor-core": "1.3.0", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 0875584501..888642adf5 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.5", + "version": "1.3.0", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 648ed5be1f..58c5f2e18a 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.5", + "version": "1.3.0", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-editor-core": "1.2.5", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-editor-core": "1.3.0", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 4caf32c009..7eef6514b3 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.5", + "version": "1.3.0", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-editor-core": "1.2.5", - "@alilc/lowcode-editor-skeleton": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-editor-core": "1.3.0", + "@alilc/lowcode-editor-skeleton": "1.3.0", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.5", - "@alilc/lowcode-plugin-outline-pane": "1.2.5", - "@alilc/lowcode-shell": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", - "@alilc/lowcode-workspace": "1.2.5", + "@alilc/lowcode-plugin-designer": "1.3.0", + "@alilc/lowcode-plugin-outline-pane": "1.3.0", + "@alilc/lowcode-shell": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-workspace": "1.3.0", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index f131dc14c3..cb87c297f8 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.5", + "version": "1.3.0", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index d764f7d9ed..a2c0fcf191 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.5", + "version": "1.3.0", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-editor-core": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-editor-core": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index f864356fc8..073830381f 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.5", + "version": "1.3.0", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 2970e93410..b1b22f8f4e 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.5", + "version": "1.3.0", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.5" + "@alilc/lowcode-renderer-core": "1.3.0" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 030a197082..49778b5df9 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.5", + "version": "1.3.0", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-react-renderer": "1.2.5", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-react-renderer": "1.3.0", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index fab0d3f133..bf2afdea1f 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.5", + "version": "1.3.0", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 86c4c7d11e..fba14598eb 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.5", + "version": "1.3.0", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-editor-core": "1.2.5", - "@alilc/lowcode-editor-skeleton": "1.2.5", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", - "@alilc/lowcode-workspace": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-editor-core": "1.3.0", + "@alilc/lowcode-editor-skeleton": "1.3.0", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-workspace": "1.3.0", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 52a5e03ae0..8d056e4eed 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.5", + "version": "1.3.0", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 976b76341b..2172041323 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.5", + "version": "1.3.0", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-types": "1.3.0", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index cbc31f3797..3c58c040e6 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.5", + "version": "1.3.0", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-editor-core": "1.2.5", - "@alilc/lowcode-editor-skeleton": "1.2.5", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-editor-core": "1.3.0", + "@alilc/lowcode-editor-skeleton": "1.3.0", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From d8406c5bab142641f7ffc559794e2d5159b0c1f7 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 16 Jan 2024 10:32:47 +0800 Subject: [PATCH 435/469] docs: update resource docs --- docs/docs/api/model/resource.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/docs/api/model/resource.md b/docs/docs/api/model/resource.md index 3977234545..a5fdeaf782 100644 --- a/docs/docs/api/model/resource.md +++ b/docs/docs/api/model/resource.md @@ -15,6 +15,12 @@ sidebar_position: 13 `@type {string}` +### id + +资源 id + +`@type {string}` + ### name 资源名字 @@ -44,3 +50,9 @@ sidebar_position: 13 资源配置信息 `@type {Object}` + +### config + +资源配置信息 + +`@type {Object}` \ No newline at end of file From 7f2b2870aa8d4402069258932a00f8566b7f290a Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 16 Jan 2024 02:35:43 +0000 Subject: [PATCH 436/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 643bdace2b..3b7f1e95c2 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.27", + "version": "1.2.28", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 4dd6f7a352f7ba1cea0774114142abe663b6cc31 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 16 Jan 2024 10:34:26 +0800 Subject: [PATCH 437/469] feat: update comtext menu component --- .../shell/src/components/context-menu.tsx | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx index c752e79903..ccd910efc4 100644 --- a/packages/shell/src/components/context-menu.tsx +++ b/packages/shell/src/components/context-menu.tsx @@ -1,20 +1,14 @@ import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; import { engineConfig } from '@alilc/lowcode-editor-core'; import { IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; -import React from 'react'; +import React, { useCallback } from 'react'; export function ContextMenu({ children, menus, pluginContext }: { menus: IPublicTypeContextMenuAction[]; children: React.ReactElement[] | React.ReactElement; pluginContext: IPublicModelPluginContext; }): React.ReactElement<any, string | React.JSXElementConstructor<any>> { - if (!engineConfig.get('enableContextMenu')) { - return ( - <>{ children }</> - ); - } - - const handleContextMenu = (event: React.MouseEvent) => { + const handleContextMenu = useCallback((event: React.MouseEvent) => { event.preventDefault(); event.stopPropagation(); @@ -32,7 +26,19 @@ export function ContextMenu({ children, menus, pluginContext }: { } destroyFn = createContextMenu(children, { event }); - }; + }, [menus]); + + if (!engineConfig.get('enableContextMenu')) { + return ( + <>{ children }</> + ); + } + + if (!menus || !menus.length) { + return ( + <>{ children }</> + ); + } // 克隆 children 并添加 onContextMenu 事件处理器 const childrenWithContextMenu = React.Children.map(children, (child) => From 84b4c76db250fb8b644998fcd22e4df88f10b2a6 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 16 Jan 2024 17:16:05 +0800 Subject: [PATCH 438/469] chore: update build-plugin-lce version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8b566e0f0c..213bbc1c45 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "yarn": "^1.22.17", "rimraf": "^3.0.2", "@types/react-router": "5.1.18", - "@alilc/build-plugin-lce": "^0.0.4", + "@alilc/build-plugin-lce": "^0.0.5", "babel-jest": "^26.5.2", "@alilc/lowcode-test-mate": "^1.0.1" }, From a8b9b2b5e13c10dea802bfe1d85f78217e7186a8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 16 Jan 2024 18:00:18 +0800 Subject: [PATCH 439/469] chore: add "set -e" in build.sh --- .github/workflows/pre build.yml | 34 +++++++++++++++++++++++++++++ packages/shell/src/api/commonUI.tsx | 2 +- scripts/build.sh | 2 ++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/pre build.yml diff --git a/.github/workflows/pre build.yml b/.github/workflows/pre build.yml new file mode 100644 index 0000000000..e6f7d6479d --- /dev/null +++ b/.github/workflows/pre build.yml @@ -0,0 +1,34 @@ +name: Pre Build + +on: + push: + paths: + - 'packages/**' + - '!packages/**.md' + pull_request: + paths: + - 'packages/**' + - '!packages/**.md' + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install dependencies and setup + run: npm install && npm run setup + + - name: Build + run: npm run build + + - name: Check build status + run: | + if [ $? -eq 0 ]; then + echo "Build succeeded!" + else + echo "Build failed!" + exit 1 + fi diff --git a/packages/shell/src/api/commonUI.tsx b/packages/shell/src/api/commonUI.tsx index 0a9021fe6a..f25cd232c4 100644 --- a/packages/shell/src/api/commonUI.tsx +++ b/packages/shell/src/api/commonUI.tsx @@ -23,7 +23,7 @@ export class CommonUI implements IPublicApiCommonUI { Form = Form; Icon = Icon; Input = Input; - Loading = Loading; + Loading = Loading as any; Message = Message; Overlay = Overlay; Pagination = Pagination; diff --git a/scripts/build.sh b/scripts/build.sh index 0d96598e62..828bb16d99 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +set -e + lerna run build \ --scope @alilc/lowcode-types \ --scope @alilc/lowcode-utils \ From 8f8908c83242b6c418cb7486195b3b13d1516782 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 17 Jan 2024 11:08:28 +0800 Subject: [PATCH 440/469] fix(context-menu): fix context menu component instance changed --- packages/shell/src/api/commonUI.tsx | 35 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/shell/src/api/commonUI.tsx b/packages/shell/src/api/commonUI.tsx index f25cd232c4..69dd104b2a 100644 --- a/packages/shell/src/api/commonUI.tsx +++ b/packages/shell/src/api/commonUI.tsx @@ -8,6 +8,7 @@ import { import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; import { ContextMenu } from '../components/context-menu'; import { editorSymbol } from '../symbols'; +import { ReactElement } from 'react'; export class CommonUI implements IPublicApiCommonUI { [editorSymbol]: IEditor; @@ -40,8 +41,27 @@ export class CommonUI implements IPublicApiCommonUI { Upload = Upload; Divider = Divider; + ContextMenu: ((props: { + menus: IPublicTypeContextMenuAction[]; + children: React.ReactElement[] | React.ReactElement; + }) => ReactElement) & { + create(menus: IPublicTypeContextMenuAction[], event: MouseEvent | React.MouseEvent): void; + }; + constructor(editor: IEditor) { this[editorSymbol] = editor; + + const innerContextMenu = (props: any) => { + const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext; + return <ContextMenu {...props} pluginContext={pluginContext} />; + }; + + innerContextMenu.create = (menus: IPublicTypeContextMenuAction[], event: MouseEvent) => { + const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext; + return ContextMenu.create(pluginContext, menus, event); + }; + + this.ContextMenu = innerContextMenu; } get Tip() { @@ -55,19 +75,4 @@ export class CommonUI implements IPublicApiCommonUI { get Title() { return InnerTitle; } - - get ContextMenu() { - const editor = this[editorSymbol]; - const innerContextMenu = (props: any) => { - const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext; - return <ContextMenu {...props} pluginContext={pluginContext} />; - }; - - innerContextMenu.create = (menus: IPublicTypeContextMenuAction[], event: MouseEvent) => { - const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext; - return ContextMenu.create(pluginContext, menus, event); - }; - - return innerContextMenu; - } } From 4025a7d2e00f06501121485dcbce7ecdefb7b9ce Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 17 Jan 2024 06:01:02 +0000 Subject: [PATCH 441/469] chore(release): publish 1.3.1 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 15 files changed, 57 insertions(+), 57 deletions(-) diff --git a/lerna.json b/lerna.json index 33d4899d0c..7de339c6cd 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.3.0", + "version": "1.3.1", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 5ecf6c1390..ec7c153c80 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.3.0", + "version": "1.3.1", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.3.0", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-editor-core": "1.3.1", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 888642adf5..f807ef5155 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.3.0", + "version": "1.3.1", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 58c5f2e18a..7c14943552 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.3.0", + "version": "1.3.1", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.3.0", - "@alilc/lowcode-editor-core": "1.3.0", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-editor-core": "1.3.1", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 7eef6514b3..4b622eaa4b 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.3.0", + "version": "1.3.1", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.3.0", - "@alilc/lowcode-editor-core": "1.3.0", - "@alilc/lowcode-editor-skeleton": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-editor-core": "1.3.1", + "@alilc/lowcode-editor-skeleton": "1.3.1", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.3.0", - "@alilc/lowcode-plugin-outline-pane": "1.3.0", - "@alilc/lowcode-shell": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", - "@alilc/lowcode-workspace": "1.3.0", + "@alilc/lowcode-plugin-designer": "1.3.1", + "@alilc/lowcode-plugin-outline-pane": "1.3.1", + "@alilc/lowcode-shell": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-workspace": "1.3.1", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index cb87c297f8..a32e30783f 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.3.0", + "version": "1.3.1", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index a2c0fcf191..9fb9a75655 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.3.0", + "version": "1.3.1", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.3.0", - "@alilc/lowcode-editor-core": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-editor-core": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 073830381f..1539ac6ae3 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.3.0", + "version": "1.3.1", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index b1b22f8f4e..b041823e85 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.3.0", + "version": "1.3.1", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.3.0" + "@alilc/lowcode-renderer-core": "1.3.1" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 49778b5df9..1361535099 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.3.0", + "version": "1.3.1", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.3.0", - "@alilc/lowcode-react-renderer": "1.3.0", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-react-renderer": "1.3.1", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index bf2afdea1f..dd48d361f1 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.3.0", + "version": "1.3.1", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index fba14598eb..87f71a5ee6 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.3.0", + "version": "1.3.1", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.3.0", - "@alilc/lowcode-editor-core": "1.3.0", - "@alilc/lowcode-editor-skeleton": "1.3.0", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", - "@alilc/lowcode-workspace": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-editor-core": "1.3.1", + "@alilc/lowcode-editor-skeleton": "1.3.1", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-workspace": "1.3.1", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 8d056e4eed..31dadb5ea0 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.3.0", + "version": "1.3.1", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 2172041323..12e3ebc1b3 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.3.0", + "version": "1.3.1", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-types": "1.3.1", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 3c58c040e6..7af4a7159c 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.3.0", + "version": "1.3.1", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.3.0", - "@alilc/lowcode-editor-core": "1.3.0", - "@alilc/lowcode-editor-skeleton": "1.3.0", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-editor-core": "1.3.1", + "@alilc/lowcode-editor-skeleton": "1.3.1", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 9b19d8f8895415335ffb862051f0ac6e5873ecfe Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 18 Jan 2024 08:00:41 +0800 Subject: [PATCH 442/469] =?UTF-8?q?docs:=20remove=20title=20level=20from?= =?UTF-8?q?=20=E7=A4=BA=E4=BE=8B=20sections=20in=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/api/common.md | 7 ++++--- docs/docs/api/config.md | 12 ++++++------ docs/docs/api/material.md | 22 +++++++++++----------- docs/docs/api/project.md | 2 +- docs/docs/api/simulatorHost.md | 2 +- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/docs/docs/api/common.md b/docs/docs/api/common.md index 6613547ea9..1a70436adf 100644 --- a/docs/docs/api/common.md +++ b/docs/docs/api/common.md @@ -82,7 +82,7 @@ executeTransaction(fn: () => void, type: IPublicEnumTransitionType): void; ``` **@since v1.0.16** -##### 示例 +**示例** ```typescript import { common } from '@alilc/lowcode-engine'; import { IPublicEnumTransitionType } from '@alilc/lowcode-types'; @@ -132,7 +132,8 @@ createIntl(instance: string | object): { **@since v1.0.17** -##### 示例 +**示例** + ```typescript import { common } from '@alilc/lowcode-engine'; import enUS from './en-US.json'; @@ -156,7 +157,7 @@ i18n 转换方法 intl(data: IPublicTypeI18nData | string, params?: object): string; ``` -##### 示例 +**示例** ``` const title = common.utils.intl(node.title) ``` diff --git a/docs/docs/api/config.md b/docs/docs/api/config.md index 9294b9d289..fb631a945f 100644 --- a/docs/docs/api/config.md +++ b/docs/docs/api/config.md @@ -24,7 +24,7 @@ sidebar_position: 8 */ get(key: string, defaultValue?: any): any; ``` -#### 示例 +**示例** ```typescript import { config } from '@alilc/lowcode-engine'; @@ -43,7 +43,7 @@ config.get('keyB', { a: 1 }); */ set(key: string, value: any): void; ``` -#### 示例 +**示例** ```typescript import { config } from '@alilc/lowcode-engine'; @@ -63,7 +63,7 @@ config.set('keyC', 1); has(key: string): boolean; ``` -#### 示例 +**示例** ```typescript import { config } from '@alilc/lowcode-engine'; @@ -81,7 +81,7 @@ config.has('keyD'); */ setConfig(config: { [key: string]: any }): void; ``` -#### 示例 +**示例** ```typescript import { config } from '@alilc/lowcode-engine'; @@ -134,7 +134,7 @@ config.getPreference().set(`${panelName}-pinned-status-isFloat`, false, 'skeleto */ onceGot(key: string): Promise<any>; ``` -#### 示例 +**示例** ```typescript import { config } from '@alilc/lowcode-engine'; @@ -160,7 +160,7 @@ const value = await config.onceGot('keyA'); */ onGot(key: string, fn: (data: any) => void): () => void; ``` -#### 示例 +**示例** ```typescript import { config } from '@alilc/lowcode-engine'; diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index d237180ca9..b6ef070b2c 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -39,7 +39,7 @@ 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'; @@ -85,7 +85,7 @@ 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'; @@ -106,7 +106,7 @@ loadIncrementalAssets(incrementalAssets: IPublicTypeAssetsJson): Promise<void>; ``` 相关类型:[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-<siteId>/assets.json'; @@ -146,7 +146,7 @@ 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'; @@ -186,7 +186,7 @@ removeBuiltinComponentAction(name: string): void; - lock:锁定,不可编辑 - unlock:解锁,可编辑 -##### 示例 +**示例** ```typescript import { material } from '@alilc/lowcode-engine'; @@ -222,7 +222,7 @@ modifyBuiltinComponentAction( -##### 示例 +**示例** 给原始的 remove 扩展时间添加执行前后的日志 ```typescript import { material } from '@alilc/lowcode-engine'; @@ -335,7 +335,7 @@ 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'; @@ -356,7 +356,7 @@ material.getComponentMeta('Input'); ``` 相关类型:[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts) -##### 示例 +**示例** ```typescript import { material } from '@alilc/lowcode-engine'; @@ -393,7 +393,7 @@ registerMetadataTransducer( ): void; ``` -##### 示例 +**示例** 给每一个组件的配置添加高级配置面板,其中有一个是否渲染配置项 ```typescript import { material } from '@alilc/lowcode-engine' @@ -475,7 +475,7 @@ material.registerMetadataTransducer((transducer) => { getRegisteredMetadataTransducers(): IPublicTypeMetadataTransducer[]; ``` -##### 示例 +**示例** ```typescript import { material } from '@alilc/lowcode-engine' @@ -496,7 +496,7 @@ 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'; diff --git a/docs/docs/api/project.md b/docs/docs/api/project.md index 7998228e2b..49d3193858 100644 --- a/docs/docs/api/project.md +++ b/docs/docs/api/project.md @@ -201,7 +201,7 @@ addPropsTransducer( - [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'; diff --git a/docs/docs/api/simulatorHost.md b/docs/docs/api/simulatorHost.md index ee8f038fc3..c7f739f6b4 100644 --- a/docs/docs/api/simulatorHost.md +++ b/docs/docs/api/simulatorHost.md @@ -20,7 +20,7 @@ sidebar_position: 3 */ set(key: string, value: any): void; ``` -#### 示例 +**示例** 设置若干用于画布渲染的变量,比如画布大小、locale 等。 以设置画布大小为例: From de738b5d7cfd2eaa4afcbc9583675c8c1095b054 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 18 Jan 2024 01:06:41 +0000 Subject: [PATCH 443/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 3b7f1e95c2..69dddfce2c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.28", + "version": "1.2.29", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From e6ba79b4d7eab23962c5aae29fca633a9862d173 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 24 Jan 2024 17:02:28 +0800 Subject: [PATCH 444/469] feat(utils): checkPropTypes suport IPublicTypePropType as rule for check --- packages/renderer-core/src/utils/common.ts | 48 ++++- .../renderer-core/tests/utils/common.test.ts | 184 +++++++++++++++++- 2 files changed, 229 insertions(+), 3 deletions(-) diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts index 495744acd9..894d2d8ca8 100644 --- a/packages/renderer-core/src/utils/common.ts +++ b/packages/renderer-core/src/utils/common.ts @@ -1,7 +1,7 @@ /* eslint-disable no-console */ /* eslint-disable no-new-func */ import logger from './logger'; -import { IPublicTypeRootSchema, IPublicTypeNodeSchema, IPublicTypeJSSlot } from '@alilc/lowcode-types'; +import { IPublicTypeRootSchema, IPublicTypeNodeSchema, IPublicTypeJSSlot, IPublicTypePropType, IPublicTypeRequiredType, IPublicTypeBasicType } from '@alilc/lowcode-types'; import { isI18nData, isJSExpression } from '@alilc/lowcode-utils'; import { isEmpty } from 'lodash'; import IntlMessageFormat from 'intl-messageformat'; @@ -183,8 +183,54 @@ export function transformArrayToMap(arr: any[], key: string, overwrite = true) { return res; } +export function isBasicType(propType: IPublicTypePropType): propType is IPublicTypeBasicType { + if (!propType) { + return false; + } + return typeof propType === 'string'; +} + +export function isRequiredType(propType: IPublicTypePropType): propType is IPublicTypeRequiredType { + if (!propType) { + return false; + } + return typeof propType === 'object' && propType.type && ['array', 'bool', 'func', 'number', 'object', 'string', 'node', 'element', 'any'].includes(propType.type); +} + +export function transformPropTypesRuleToString(rule: IPublicTypePropType): string { + if (!rule) { + return 'PropTypes.any'; + } + + if (typeof rule === 'string') { + return `PropTypes.${rule}`; + } + + if (isRequiredType(rule)) { + const { type, isRequired } = rule; + return `PropTypes.${type}${isRequired ? '.isRequired' : ''}`; + } + + const { type, value } = rule; + switch (type) { + case 'oneOf': + return `PropTypes.oneOf([${value.map((item: any) => `"${item}"`).join(',')}])`; + case 'oneOfType': + return `PropTypes.oneOfType([${value.map((item: any) => transformPropTypesRuleToString(item)).join(', ')}])`; + case 'arrayOf': + case 'objectOf': + return `PropTypes.${type}(${transformPropTypesRuleToString(value)})`; + case 'shape': + case 'exact': + return `PropTypes.${type}({${value.map((item: any) => `${item.name}: ${transformPropTypesRuleToString(item.propType)}`).join(',')}})`; + } +} + export function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean { let ruleFunction = rule; + if (typeof rule === 'object') { + ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${transformPropTypesRuleToString(rule)}`)(PropTypes2); + } if (typeof rule === 'string') { ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2); } diff --git a/packages/renderer-core/tests/utils/common.test.ts b/packages/renderer-core/tests/utils/common.test.ts index 2ee3ed4dcc..45a8e33d7e 100644 --- a/packages/renderer-core/tests/utils/common.test.ts +++ b/packages/renderer-core/tests/utils/common.test.ts @@ -19,6 +19,9 @@ import { parseI18n, parseData, checkPropTypes, + transformPropTypesRuleToString, + isRequiredType, + isBasicType, } from '../../src/utils/common'; import logger from '../../src/utils/logger'; @@ -283,7 +286,7 @@ describe('test capitalizeFirstLetter ', () => { describe('test forEach ', () => { it('should work', () => { const mockFn = jest.fn(); - + forEach(null, mockFn); expect(mockFn).toBeCalledTimes(0); @@ -298,7 +301,7 @@ describe('test forEach ', () => { forEach({ a: 1, b: 2, c: 3 }, mockFn); expect(mockFn).toBeCalledTimes(3); - + const mockFn2 = jest.fn(); forEach({ a: 1 }, mockFn2, { b: 'bbb' }); expect(mockFn2).toHaveBeenCalledWith(1, 'a'); @@ -468,6 +471,28 @@ describe('test parseData ', () => { }); }); +describe('test isBasicType ', () => { + it('should work', () => { + expect(isBasicType(null)).toBeFalsy(); + expect(isBasicType(undefined)).toBeFalsy(); + expect(isBasicType({})).toBeFalsy(); + expect(isBasicType({ type: 'any other type' })).toBeFalsy(); + expect(isBasicType('string')).toBeTruthy(); + }); +}); + +describe('test isRequiredType', () => { + it('should work', () => { + expect(isRequiredType(null)).toBeFalsy(); + expect(isRequiredType(undefined)).toBeFalsy(); + expect(isRequiredType({})).toBeFalsy(); + expect(isRequiredType({ type: 'any other type' })).toBeFalsy(); + expect(isRequiredType('string')).toBeFalsy(); + expect(isRequiredType({ type: 'string' })).toBeTruthy(); + expect(isRequiredType({ type: 'string', isRequired: true })).toBeTruthy(); + }); +}) + describe('checkPropTypes', () => { it('should validate correctly with valid prop type', () => { expect(checkPropTypes(123, 'age', PropTypes.number, 'TestComponent')).toBe(true); @@ -499,4 +524,159 @@ describe('checkPropTypes', () => { const result = checkPropTypes(123, 'age', 123, 'TestComponent'); expect(result).toBe(true); }); + + // oneOf + it('should validate correctly with valid oneOf prop type', () => { + const rule = { + type: 'oneOf', + value: ['News', 'Photos'], + } + expect(transformPropTypesRuleToString(rule)).toBe(`PropTypes.oneOf(["News","Photos"])`); + expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes('Others', 'type', rule, 'TestComponent')).toBe(false); + }); + + // oneOfType + it('should validate correctly with valid oneOfType prop type', () => { + const rule = { + type: 'oneOfType', + value: ['string', 'number', { + type: 'array', + isRequired: true, + }], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array.isRequired])'); + expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes(123, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({}, 'type', rule, 'TestComponent')).toBe(false); + }); + + // arrayOf + it('should validate correctly with valid arrayOf prop type', () => { + const rule = { + type: 'arrayOf', + value: { + type: 'string', + isRequired: true, + }, + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.arrayOf(PropTypes.string.isRequired)'); + expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes(['News', 123], 'type', rule, 'TestComponent')).toBe(false); + }); + + // objectOf + it('should validate correctly with valid objectOf prop type', () => { + const rule = { + type: 'objectOf', + value: { + type: 'string', + isRequired: true, + }, + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.objectOf(PropTypes.string.isRequired)'); + expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(false); + }); + + // shape + it('should validate correctly with valid shape prop type', () => { + const rule = { + type: 'shape', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: true, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false); + + // isRequired + const rule2 = { + type: 'shape', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: false, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true); + expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false); + }); + + // exact + it('should validate correctly with valid exact prop type', () => { + const rule = { + type: 'exact', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: true, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false); + + // isRequired + const rule2 = { + type: 'exact', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: false, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true); + expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false); + }); }); \ No newline at end of file From cd67a8cea37af8b801b765b2a4b648fcf6d957c2 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 24 Jan 2024 14:58:56 +0800 Subject: [PATCH 445/469] test(designer): add parse-metadata test --- packages/designer/jest.config.js | 1 + .../builtin-simulator/utils/parse-metadata.ts | 12 +- .../utils/parse-metadata.test.ts | 166 +++++++++++++++++- 3 files changed, 176 insertions(+), 3 deletions(-) diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index f0ad2e861e..3684a48acb 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -21,6 +21,7 @@ const jestConfig = { // testMatch: ['**/builtin-hotkey.test.ts'], // testMatch: ['**/selection.test.ts'], // testMatch: ['**/plugin/sequencify.test.ts'], + // testMatch: ['**/builtin-simulator/utils/parse-metadata.test.ts'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], diff --git a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts index 5c81340a14..6969a47db5 100644 --- a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts +++ b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts @@ -16,8 +16,16 @@ export const primitiveTypes = [ 'any', ]; +interface LowcodeCheckType { + // isRequired, props, propName, componentName, location, propFullName, secret + (props: any, propName: string, componentName: string, ...rest: any[]): Error | null; + // (...reset: any[]): Error | null; + isRequired?: LowcodeCheckType; + type?: string | object; +} + // eslint-disable-next-line @typescript-eslint/ban-types -function makeRequired(propType: any, lowcodeType: string | object) { +function makeRequired(propType: any, lowcodeType: string | object): LowcodeCheckType { function lowcodeCheckTypeIsRequired(...rest: any[]) { return propType.isRequired(...rest); } @@ -34,7 +42,7 @@ function makeRequired(propType: any, lowcodeType: string | object) { } // eslint-disable-next-line @typescript-eslint/ban-types -function define(propType: any = PropTypes.any, lowcodeType: string | object = {}) { +function define(propType: any = PropTypes.any, lowcodeType: string | object = {}): LowcodeCheckType { if (!propType._inner && propType.name !== 'lowcodeCheckType') { propType.lowcodeType = lowcodeType; } diff --git a/packages/designer/tests/builtin-simulator/utils/parse-metadata.test.ts b/packages/designer/tests/builtin-simulator/utils/parse-metadata.test.ts index 1843a24429..64e19376e2 100644 --- a/packages/designer/tests/builtin-simulator/utils/parse-metadata.test.ts +++ b/packages/designer/tests/builtin-simulator/utils/parse-metadata.test.ts @@ -1,5 +1,7 @@ import '../../fixtures/window'; -import { parseMetadata } from '../../../src/builtin-simulator/utils/parse-metadata'; +import PropTypes from 'prop-types'; +import { LowcodeTypes, parseMetadata, parseProps } from '../../../src/builtin-simulator/utils/parse-metadata'; +import { default as ReactPropTypesSecret } from 'prop-types/lib/ReactPropTypesSecret'; describe('parseMetadata', () => { it('parseMetadata', async () => { @@ -11,3 +13,165 @@ describe('parseMetadata', () => { expect(result).toBeDefined(); }); }); + +describe('LowcodeTypes basic type validators', () => { + it('should validate string types', () => { + const stringValidator = LowcodeTypes.string; + // 对 stringValidator 进行测试 + const props = { testProp: 'This is a string' }; + const propName = 'testProp'; + const componentName = 'TestComponent'; + + const result = stringValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeNull(); // No error for valid string + }); + + it('should fail with a non-string type', () => { + const stringValidator = LowcodeTypes.string; + const props = { testProp: 42 }; + const propName = 'testProp'; + const componentName = 'TestComponent'; + + const result = stringValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeInstanceOf(Error); // Error for non-string type + expect(result.message).toContain('Invalid prop `testProp` of type `number` supplied to `TestComponent`, expected `string`.'); + }); + + it('should pass with a valid number', () => { + const numberValidator = LowcodeTypes.number; + const props = { testProp: 42 }; + const propName = 'testProp'; + const componentName = 'TestComponent'; + + const result = numberValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeNull(); // No error for valid number + }); + + it('should fail with a non-number type', () => { + const numberValidator = LowcodeTypes.number; + const props = { testProp: 'Not a number' }; + const propName = 'testProp'; + const componentName = 'TestComponent'; + + const result = numberValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeInstanceOf(Error); // Error for non-number type + expect(result.message).toContain('Invalid prop `testProp` of type `string` supplied to `TestComponent`, expected `number`.'); + }); +}); + +describe('Custom type constructors', () => { + it('should create a custom type validator using define', () => { + const customType = LowcodeTypes.define(PropTypes.string, 'customType'); + const props = { testProp: 'This is a string' }; + const propName = 'testProp'; + const componentName = 'TestComponent'; + + // 测试有效值 + const validResult = customType(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(validResult).toBeNull(); // No error for valid string + + // 测试无效值 + const invalidProps = { testProp: 42 }; + const invalidResult = customType(invalidProps, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(invalidResult).toBeInstanceOf(Error); // Error for non-string type + + // 验证 lowcodeType 属性 + expect(customType.lowcodeType).toEqual('customType'); + + // 验证 isRequired 属性 + const requiredResult = customType.isRequired(invalidProps, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(requiredResult).toBeInstanceOf(Error); // Error for non-string type + }); +}); + + +describe('Advanced type constructors', () => { + describe('oneOf Type Validator', () => { + const oneOfValidator = LowcodeTypes.oneOf(['red', 'green', 'blue']); + const propName = 'color'; + const componentName = 'ColorPicker'; + + it('should pass with a valid value', () => { + const props = { color: 'red' }; + const result = oneOfValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeNull(); // No error for valid value + }); + + it('should fail with an invalid value', () => { + const props = { color: 'yellow' }; + const result = oneOfValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeInstanceOf(Error); // Error for invalid value + expect(result.message).toContain(`Invalid prop \`${propName}\` of value \`yellow\` supplied to \`${componentName}\`, expected one of ["red","green","blue"].`); + }); + + it('should fail with a non-existing value', () => { + const props = { color: 'others' }; + const result = oneOfValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeInstanceOf(Error); // Error for non-existing value + expect(result.message).toContain(`Invalid prop \`${propName}\` of value \`others\` supplied to \`${componentName}\`, expected one of ["red","green","blue"].`); + }); + }); +}); + + +describe('parseProps function', () => { + it('should correctly parse propTypes and defaultProps', () => { + const component = { + propTypes: { + name: LowcodeTypes.string, + age: LowcodeTypes.number, + }, + defaultProps: { + name: 'John Doe', + age: 30, + }, + }; + const parsedProps = parseProps(component); + + // 测试结果长度 + expect(parsedProps.length).toBe(2); + + // 测试 name 属性 + const nameProp: any = parsedProps.find(prop => prop.name === 'name'); + expect(nameProp).toBeDefined(); + expect(nameProp.propType).toEqual('string'); + expect(nameProp.defaultValue).toEqual('John Doe'); + + // 测试 age 属性 + const ageProp: any = parsedProps.find(prop => prop.name === 'age'); + expect(ageProp).toBeDefined(); + expect(ageProp.propType).toEqual('number'); + expect(ageProp.defaultValue).toEqual(30); + }); +}); + +describe('parseProps function', () => { + it('should correctly parse propTypes and defaultProps', () => { + const component = { + propTypes: { + name: LowcodeTypes.string, + age: LowcodeTypes.number, + }, + defaultProps: { + name: 'John Doe', + age: 30, + }, + }; + const parsedProps = parseProps(component); + + // 测试结果长度 + expect(parsedProps.length).toBe(2); + + // 测试 name 属性 + const nameProp: any = parsedProps.find(prop => prop.name === 'name'); + expect(nameProp).toBeDefined(); + expect(nameProp.propType).toEqual('string'); + expect(nameProp.defaultValue).toEqual('John Doe'); + + // 测试 age 属性 + const ageProp: any = parsedProps.find(prop => prop.name === 'age'); + expect(ageProp).toBeDefined(); + expect(ageProp.propType).toEqual('number'); + expect(ageProp.defaultValue).toEqual(30); + }); +}); From 0e65f021169aa9ddc9016cfa2929bcfd15fd605e Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 25 Jan 2024 10:38:52 +0800 Subject: [PATCH 446/469] feat(utils): move checkPropTypes to utils module --- packages/renderer-core/src/renderer/base.tsx | 3 +- packages/renderer-core/src/utils/common.ts | 76 ------ .../renderer-core/tests/utils/common.test.ts | 219 ------------------ packages/utils/package.json | 1 + packages/utils/src/check-prop-types.ts | 68 ++++++ packages/utils/src/check-types/index.ts | 4 +- .../src/check-types/is-basic-prop-type.ts | 8 + .../src/check-types/is-required-prop-type.ts | 8 + packages/utils/src/context-menu.tsx | 2 +- packages/utils/src/index.ts | 1 + .../utils/test/src/check-prop-types.test.ts | 190 +++++++++++++++ .../check-types/is-basic-prop-type.test.ts | 11 + .../check-types/is-required-prop-type.test.ts | 13 ++ 13 files changed, 305 insertions(+), 299 deletions(-) create mode 100644 packages/utils/src/check-prop-types.ts create mode 100644 packages/utils/src/check-types/is-basic-prop-type.ts create mode 100644 packages/utils/src/check-types/is-required-prop-type.ts create mode 100644 packages/utils/test/src/check-prop-types.test.ts create mode 100644 packages/utils/test/src/check-types/is-basic-prop-type.test.ts create mode 100644 packages/utils/test/src/check-types/is-required-prop-type.test.ts diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 9d9e88ab59..d240095604 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -4,7 +4,7 @@ import classnames from 'classnames'; import { create as createDataSourceEngine } from '@alilc/lowcode-datasource-engine/interpret'; import { IPublicTypeNodeSchema, IPublicTypeNodeData, IPublicTypeJSONValue, IPublicTypeCompositeValue } from '@alilc/lowcode-types'; -import { isI18nData, isJSExpression, isJSFunction } from '@alilc/lowcode-utils'; +import { checkPropTypes, isI18nData, isJSExpression, isJSFunction } from '@alilc/lowcode-utils'; import adapter from '../adapter'; import divFactory from '../components/Div'; import visualDomFactory from '../components/VisualDom'; @@ -21,7 +21,6 @@ import { isFileSchema, transformArrayToMap, transformStringToFunction, - checkPropTypes, getI18n, getFileCssName, capitalizeFirstLetter, diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts index 894d2d8ca8..80150f379f 100644 --- a/packages/renderer-core/src/utils/common.ts +++ b/packages/renderer-core/src/utils/common.ts @@ -6,16 +6,11 @@ import { isI18nData, isJSExpression } from '@alilc/lowcode-utils'; import { isEmpty } from 'lodash'; import IntlMessageFormat from 'intl-messageformat'; import pkg from '../../package.json'; -import * as ReactIs from 'react-is'; -import { default as ReactPropTypesSecret } from 'prop-types/lib/ReactPropTypesSecret'; -import { default as factoryWithTypeCheckers } from 'prop-types/factoryWithTypeCheckers'; (window as any).sdkVersion = pkg.version; export { pick, isEqualWith as deepEqual, cloneDeep as clone, isEmpty, throttle, debounce } from 'lodash'; -const PropTypes2 = factoryWithTypeCheckers(ReactIs.isElement, true); - const EXPRESSION_TYPE = { JSEXPRESSION: 'JSExpression', JSFUNCTION: 'JSFunction', @@ -183,77 +178,6 @@ export function transformArrayToMap(arr: any[], key: string, overwrite = true) { return res; } -export function isBasicType(propType: IPublicTypePropType): propType is IPublicTypeBasicType { - if (!propType) { - return false; - } - return typeof propType === 'string'; -} - -export function isRequiredType(propType: IPublicTypePropType): propType is IPublicTypeRequiredType { - if (!propType) { - return false; - } - return typeof propType === 'object' && propType.type && ['array', 'bool', 'func', 'number', 'object', 'string', 'node', 'element', 'any'].includes(propType.type); -} - -export function transformPropTypesRuleToString(rule: IPublicTypePropType): string { - if (!rule) { - return 'PropTypes.any'; - } - - if (typeof rule === 'string') { - return `PropTypes.${rule}`; - } - - if (isRequiredType(rule)) { - const { type, isRequired } = rule; - return `PropTypes.${type}${isRequired ? '.isRequired' : ''}`; - } - - const { type, value } = rule; - switch (type) { - case 'oneOf': - return `PropTypes.oneOf([${value.map((item: any) => `"${item}"`).join(',')}])`; - case 'oneOfType': - return `PropTypes.oneOfType([${value.map((item: any) => transformPropTypesRuleToString(item)).join(', ')}])`; - case 'arrayOf': - case 'objectOf': - return `PropTypes.${type}(${transformPropTypesRuleToString(value)})`; - case 'shape': - case 'exact': - return `PropTypes.${type}({${value.map((item: any) => `${item.name}: ${transformPropTypesRuleToString(item.propType)}`).join(',')}})`; - } -} - -export function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean { - let ruleFunction = rule; - if (typeof rule === 'object') { - ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${transformPropTypesRuleToString(rule)}`)(PropTypes2); - } - if (typeof rule === 'string') { - ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2); - } - if (!ruleFunction || typeof ruleFunction !== 'function') { - logger.warn('checkPropTypes should have a function type rule argument'); - return true; - } - const err = ruleFunction( - { - [name]: value, - }, - name, - componentName, - 'prop', - null, - ReactPropTypesSecret, - ); - if (err) { - logger.warn(err); - } - return !err; -} - /** * transform string to a function * @param str function in string form diff --git a/packages/renderer-core/tests/utils/common.test.ts b/packages/renderer-core/tests/utils/common.test.ts index 45a8e33d7e..13b6908d50 100644 --- a/packages/renderer-core/tests/utils/common.test.ts +++ b/packages/renderer-core/tests/utils/common.test.ts @@ -1,4 +1,3 @@ -import factoryWithTypeCheckers from 'prop-types/factoryWithTypeCheckers'; import { isSchema, isFileSchema, @@ -18,17 +17,9 @@ import { parseThisRequiredExpression, parseI18n, parseData, - checkPropTypes, - transformPropTypesRuleToString, - isRequiredType, - isBasicType, } from '../../src/utils/common'; import logger from '../../src/utils/logger'; -var ReactIs = require('react-is'); - -const PropTypes = factoryWithTypeCheckers(ReactIs.isElement, true); - describe('test isSchema', () => { it('should be false when empty value is passed', () => { expect(isSchema(null)).toBeFalsy(); @@ -470,213 +461,3 @@ describe('test parseData ', () => { }); }); - -describe('test isBasicType ', () => { - it('should work', () => { - expect(isBasicType(null)).toBeFalsy(); - expect(isBasicType(undefined)).toBeFalsy(); - expect(isBasicType({})).toBeFalsy(); - expect(isBasicType({ type: 'any other type' })).toBeFalsy(); - expect(isBasicType('string')).toBeTruthy(); - }); -}); - -describe('test isRequiredType', () => { - it('should work', () => { - expect(isRequiredType(null)).toBeFalsy(); - expect(isRequiredType(undefined)).toBeFalsy(); - expect(isRequiredType({})).toBeFalsy(); - expect(isRequiredType({ type: 'any other type' })).toBeFalsy(); - expect(isRequiredType('string')).toBeFalsy(); - expect(isRequiredType({ type: 'string' })).toBeTruthy(); - expect(isRequiredType({ type: 'string', isRequired: true })).toBeTruthy(); - }); -}) - -describe('checkPropTypes', () => { - it('should validate correctly with valid prop type', () => { - expect(checkPropTypes(123, 'age', PropTypes.number, 'TestComponent')).toBe(true); - expect(checkPropTypes('123', 'age', PropTypes.string, 'TestComponent')).toBe(true); - }); - - it('should log a warning and return false with invalid prop type', () => { - expect(checkPropTypes(123, 'age', PropTypes.string, 'TestComponent')).toBe(false); - expect(checkPropTypes('123', 'age', PropTypes.number, 'TestComponent')).toBe(false); - }); - - it('should handle custom rule functions correctly', () => { - const customRule = (props, propName) => { - if (props[propName] !== 123) { - return new Error('Invalid value'); - } - }; - const result = checkPropTypes(123, 'customProp', customRule, 'TestComponent'); - expect(result).toBe(true); - }); - - - it('should interpret and validate a rule given as a string', () => { - const result = checkPropTypes(123, 'age', 'PropTypes.number', 'TestComponent'); - expect(result).toBe(true); - }); - - it('should log a warning for invalid rule type', () => { - const result = checkPropTypes(123, 'age', 123, 'TestComponent'); - expect(result).toBe(true); - }); - - // oneOf - it('should validate correctly with valid oneOf prop type', () => { - const rule = { - type: 'oneOf', - value: ['News', 'Photos'], - } - expect(transformPropTypesRuleToString(rule)).toBe(`PropTypes.oneOf(["News","Photos"])`); - expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes('Others', 'type', rule, 'TestComponent')).toBe(false); - }); - - // oneOfType - it('should validate correctly with valid oneOfType prop type', () => { - const rule = { - type: 'oneOfType', - value: ['string', 'number', { - type: 'array', - isRequired: true, - }], - }; - expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array.isRequired])'); - expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes(123, 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes({}, 'type', rule, 'TestComponent')).toBe(false); - }); - - // arrayOf - it('should validate correctly with valid arrayOf prop type', () => { - const rule = { - type: 'arrayOf', - value: { - type: 'string', - isRequired: true, - }, - }; - expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.arrayOf(PropTypes.string.isRequired)'); - expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes(['News', 123], 'type', rule, 'TestComponent')).toBe(false); - }); - - // objectOf - it('should validate correctly with valid objectOf prop type', () => { - const rule = { - type: 'objectOf', - value: { - type: 'string', - isRequired: true, - }, - }; - expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.objectOf(PropTypes.string.isRequired)'); - expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(false); - }); - - // shape - it('should validate correctly with valid shape prop type', () => { - const rule = { - type: 'shape', - value: [ - { - name: 'a', - propType: { - type: 'string', - isRequired: true, - }, - }, - { - name: 'b', - propType: { - type: 'number', - isRequired: true, - }, - }, - ], - }; - expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})'); - expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false); - - // isRequired - const rule2 = { - type: 'shape', - value: [ - { - name: 'a', - propType: { - type: 'string', - isRequired: true, - }, - }, - { - name: 'b', - propType: { - type: 'number', - isRequired: false, - }, - }, - ], - }; - expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number})'); - expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true); - expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false); - }); - - // exact - it('should validate correctly with valid exact prop type', () => { - const rule = { - type: 'exact', - value: [ - { - name: 'a', - propType: { - type: 'string', - isRequired: true, - }, - }, - { - name: 'b', - propType: { - type: 'number', - isRequired: true, - }, - }, - ], - }; - expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})'); - expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false); - - // isRequired - const rule2 = { - type: 'exact', - value: [ - { - name: 'a', - propType: { - type: 'string', - isRequired: true, - }, - }, - { - name: 'b', - propType: { - type: 'number', - isRequired: false, - }, - }, - ], - }; - expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number})'); - expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true); - expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false); - }); -}); \ No newline at end of file diff --git a/packages/utils/package.json b/packages/utils/package.json index 12e3ebc1b3..cc363a7292 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -17,6 +17,7 @@ "@alilc/lowcode-types": "1.3.1", "lodash": "^4.17.21", "mobx": "^6.3.0", + "prop-types": "^15.8.1", "react": "^16" }, "devDependencies": { diff --git a/packages/utils/src/check-prop-types.ts b/packages/utils/src/check-prop-types.ts new file mode 100644 index 0000000000..89555c70b4 --- /dev/null +++ b/packages/utils/src/check-prop-types.ts @@ -0,0 +1,68 @@ +import * as ReactIs from 'react-is'; +import { default as ReactPropTypesSecret } from 'prop-types/lib/ReactPropTypesSecret'; +import { default as factoryWithTypeCheckers } from 'prop-types/factoryWithTypeCheckers'; +import { IPublicTypePropType } from '@alilc/lowcode-types'; +import { isRequiredPropType } from './check-types/is-required-prop-type'; +import { Logger } from './logger'; + +const PropTypes2 = factoryWithTypeCheckers(ReactIs.isElement, true); +const logger = new Logger({ level: 'warn', bizName: 'utils' }); + +export function transformPropTypesRuleToString(rule: IPublicTypePropType): string { + if (!rule) { + return 'PropTypes.any'; + } + + if (typeof rule === 'string') { + return `PropTypes.${rule}`; + } + + if (isRequiredPropType(rule)) { + const { type, isRequired } = rule; + return `PropTypes.${type}${isRequired ? '.isRequired' : ''}`; + } + + const { type, value } = rule; + switch (type) { + case 'oneOf': + return `PropTypes.oneOf([${value.map((item: any) => `"${item}"`).join(',')}])`; + case 'oneOfType': + return `PropTypes.oneOfType([${value.map((item: any) => transformPropTypesRuleToString(item)).join(', ')}])`; + case 'arrayOf': + case 'objectOf': + return `PropTypes.${type}(${transformPropTypesRuleToString(value)})`; + case 'shape': + case 'exact': + return `PropTypes.${type}({${value.map((item: any) => `${item.name}: ${transformPropTypesRuleToString(item.propType)}`).join(',')}})`; + } +} + +export function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean { + let ruleFunction = rule; + if (typeof rule === 'object') { + // eslint-disable-next-line no-new-func + ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${transformPropTypesRuleToString(rule)}`)(PropTypes2); + } + if (typeof rule === 'string') { + // eslint-disable-next-line no-new-func + ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2); + } + if (!ruleFunction || typeof ruleFunction !== 'function') { + logger.warn('checkPropTypes should have a function type rule argument'); + return true; + } + const err = ruleFunction( + { + [name]: value, + }, + name, + componentName, + 'prop', + null, + ReactPropTypesSecret, + ); + if (err) { + logger.warn(err); + } + return !err; +} diff --git a/packages/utils/src/check-types/index.ts b/packages/utils/src/check-types/index.ts index 3155926ef2..507259b2c5 100644 --- a/packages/utils/src/check-types/index.ts +++ b/packages/utils/src/check-types/index.ts @@ -23,4 +23,6 @@ export * from './is-location-data'; export * from './is-setting-field'; export * from './is-lowcode-component-type'; export * from './is-lowcode-project-schema'; -export * from './is-component-schema'; \ No newline at end of file +export * from './is-component-schema'; +export * from './is-basic-prop-type'; +export * from './is-required-prop-type'; \ No newline at end of file diff --git a/packages/utils/src/check-types/is-basic-prop-type.ts b/packages/utils/src/check-types/is-basic-prop-type.ts new file mode 100644 index 0000000000..fd3b1b1dcb --- /dev/null +++ b/packages/utils/src/check-types/is-basic-prop-type.ts @@ -0,0 +1,8 @@ +import { IPublicTypeBasicType, IPublicTypePropType } from '@alilc/lowcode-types'; + +export function isBasicPropType(propType: IPublicTypePropType): propType is IPublicTypeBasicType { + if (!propType) { + return false; + } + return typeof propType === 'string'; +} \ No newline at end of file diff --git a/packages/utils/src/check-types/is-required-prop-type.ts b/packages/utils/src/check-types/is-required-prop-type.ts new file mode 100644 index 0000000000..106da78a00 --- /dev/null +++ b/packages/utils/src/check-types/is-required-prop-type.ts @@ -0,0 +1,8 @@ +import { IPublicTypePropType, IPublicTypeRequiredType } from '@alilc/lowcode-types'; + +export function isRequiredPropType(propType: IPublicTypePropType): propType is IPublicTypeRequiredType { + if (!propType) { + return false; + } + return typeof propType === 'object' && propType.type && ['array', 'bool', 'func', 'number', 'object', 'string', 'node', 'element', 'any'].includes(propType.type); +} \ No newline at end of file diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx index d783a96434..185abbb343 100644 --- a/packages/utils/src/context-menu.tsx +++ b/packages/utils/src/context-menu.tsx @@ -5,7 +5,7 @@ import classNames from 'classnames'; import React from 'react'; import './context-menu.scss'; -const logger = new Logger({ level: 'warn', bizName: 'designer' }); +const logger = new Logger({ level: 'warn', bizName: 'utils' }); const { Item, Divider, PopupItem } = Menu; const MAX_LEVEL = 2; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index b99ab02073..22bad0e36e 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -32,3 +32,4 @@ export { transactionManager } from './transaction-manager'; export * from './check-types'; export * from './workspace'; export * from './context-menu'; +export { checkPropTypes } from './check-prop-types'; \ No newline at end of file diff --git a/packages/utils/test/src/check-prop-types.test.ts b/packages/utils/test/src/check-prop-types.test.ts new file mode 100644 index 0000000000..c1902bec38 --- /dev/null +++ b/packages/utils/test/src/check-prop-types.test.ts @@ -0,0 +1,190 @@ +import { checkPropTypes, transformPropTypesRuleToString } from '../../src/check-prop-types'; +import PropTypes from 'prop-types'; + +describe('checkPropTypes', () => { + it('should validate correctly with valid prop type', () => { + expect(checkPropTypes(123, 'age', PropTypes.number, 'TestComponent')).toBe(true); + expect(checkPropTypes('123', 'age', PropTypes.string, 'TestComponent')).toBe(true); + }); + + it('should log a warning and return false with invalid prop type', () => { + expect(checkPropTypes(123, 'age', PropTypes.string, 'TestComponent')).toBe(false); + expect(checkPropTypes('123', 'age', PropTypes.number, 'TestComponent')).toBe(false); + }); + + it('should handle custom rule functions correctly', () => { + const customRule = (props, propName) => { + if (props[propName] !== 123) { + return new Error('Invalid value'); + } + }; + const result = checkPropTypes(123, 'customProp', customRule, 'TestComponent'); + expect(result).toBe(true); + }); + + + it('should interpret and validate a rule given as a string', () => { + const result = checkPropTypes(123, 'age', 'PropTypes.number', 'TestComponent'); + expect(result).toBe(true); + }); + + it('should log a warning for invalid rule type', () => { + const result = checkPropTypes(123, 'age', 123, 'TestComponent'); + expect(result).toBe(true); + }); + + // oneOf + it('should validate correctly with valid oneOf prop type', () => { + const rule = { + type: 'oneOf', + value: ['News', 'Photos'], + } + expect(transformPropTypesRuleToString(rule)).toBe(`PropTypes.oneOf(["News","Photos"])`); + expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes('Others', 'type', rule, 'TestComponent')).toBe(false); + }); + + // oneOfType + it('should validate correctly with valid oneOfType prop type', () => { + const rule = { + type: 'oneOfType', + value: ['string', 'number', { + type: 'array', + isRequired: true, + }], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array.isRequired])'); + expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes(123, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({}, 'type', rule, 'TestComponent')).toBe(false); + }); + + // arrayOf + it('should validate correctly with valid arrayOf prop type', () => { + const rule = { + type: 'arrayOf', + value: { + type: 'string', + isRequired: true, + }, + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.arrayOf(PropTypes.string.isRequired)'); + expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes(['News', 123], 'type', rule, 'TestComponent')).toBe(false); + }); + + // objectOf + it('should validate correctly with valid objectOf prop type', () => { + const rule = { + type: 'objectOf', + value: { + type: 'string', + isRequired: true, + }, + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.objectOf(PropTypes.string.isRequired)'); + expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(false); + }); + + // shape + it('should validate correctly with valid shape prop type', () => { + const rule = { + type: 'shape', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: true, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false); + + // isRequired + const rule2 = { + type: 'shape', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: false, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true); + expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false); + }); + + // exact + it('should validate correctly with valid exact prop type', () => { + const rule = { + type: 'exact', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: true, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false); + + // isRequired + const rule2 = { + type: 'exact', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: false, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true); + expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/check-types/is-basic-prop-type.test.ts b/packages/utils/test/src/check-types/is-basic-prop-type.test.ts new file mode 100644 index 0000000000..81a1bf0d34 --- /dev/null +++ b/packages/utils/test/src/check-types/is-basic-prop-type.test.ts @@ -0,0 +1,11 @@ +import { isBasicPropType } from '../../../src'; + +describe('test isBasicPropType ', () => { + it('should work', () => { + expect(isBasicPropType(null)).toBeFalsy(); + expect(isBasicPropType(undefined)).toBeFalsy(); + expect(isBasicPropType({})).toBeFalsy(); + expect(isBasicPropType({ type: 'any other type' })).toBeFalsy(); + expect(isBasicPropType('string')).toBeTruthy(); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/check-types/is-required-prop-type.test.ts b/packages/utils/test/src/check-types/is-required-prop-type.test.ts new file mode 100644 index 0000000000..25515f9aab --- /dev/null +++ b/packages/utils/test/src/check-types/is-required-prop-type.test.ts @@ -0,0 +1,13 @@ +import { isRequiredPropType } from '../../../src'; + +describe('test isRequiredType', () => { + it('should work', () => { + expect(isRequiredPropType(null)).toBeFalsy(); + expect(isRequiredPropType(undefined)).toBeFalsy(); + expect(isRequiredPropType({})).toBeFalsy(); + expect(isRequiredPropType({ type: 'any other type' })).toBeFalsy(); + expect(isRequiredPropType('string')).toBeFalsy(); + expect(isRequiredPropType({ type: 'string' })).toBeTruthy(); + expect(isRequiredPropType({ type: 'string', isRequired: true })).toBeTruthy(); + }); +}) From dca3448cbf52d6f96d7219858f6b2aed6609cf02 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 25 Jan 2024 15:45:26 +0800 Subject: [PATCH 447/469] chore(editor-core): init test --- .github/workflows/test packages.yml | 18 +++++++++++++++++- packages/editor-core/build.test.json | 9 +++++++++ packages/editor-core/jest.config.js | 26 ++++++++++++++++++++++++++ packages/editor-core/package.json | 4 +++- 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 packages/editor-core/build.test.json create mode 100644 packages/editor-core/jest.config.js diff --git a/.github/workflows/test packages.yml b/.github/workflows/test packages.yml index 4ee9b4156c..abb2973708 100644 --- a/.github/workflows/test packages.yml +++ b/.github/workflows/test packages.yml @@ -105,4 +105,20 @@ jobs: run: npm i && npm run setup:skip-build - name: test - run: cd packages/utils && npm test \ No newline at end of file + 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 \ No newline at end of file diff --git a/packages/editor-core/build.test.json b/packages/editor-core/build.test.json new file mode 100644 index 0000000000..10d18109b8 --- /dev/null +++ b/packages/editor-core/build.test.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + "@alilc/build-plugin-lce", + "@alilc/lowcode-test-mate/plugin/index.ts" + ], + "babelPlugins": [ + ["@babel/plugin-proposal-private-property-in-object", { "loose": true }] + ] +} diff --git a/packages/editor-core/jest.config.js b/packages/editor-core/jest.config.js new file mode 100644 index 0000000000..e8441e3dbb --- /dev/null +++ b/packages/editor-core/jest.config.js @@ -0,0 +1,26 @@ +const fs = require('fs'); +const { join } = require('path'); +const esModules = [].join('|'); +const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.')); + +const jestConfig = { + transformIgnorePatterns: [ + `/node_modules/(?!${esModules})/`, + ], + moduleFileExtensions: ['ts', 'tsx', 'js', 'json'], + collectCoverage: false, + collectCoverageFrom: [ + 'src/**/*.ts', + '!src/**/*.d.ts', + '!src/icons/**', + '!src/locale/**', + '!**/node_modules/**', + '!**/vendor/**', + ], +}; + +// 只对本仓库内的 pkg 做 mapping +jestConfig.moduleNameMapper = {}; +jestConfig.moduleNameMapper[`^@alilc/lowcode\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src'; + +module.exports = jestConfig; \ No newline at end of file diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index f807ef5155..98644ad3d6 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -10,7 +10,9 @@ "es" ], "scripts": { - "build": "build-scripts build" + "build": "build-scripts build", + "test": "build-scripts test --config build.test.json", + "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { "@alifd/next": "^1.19.16", From 947c6218225e8b88df604cb3fa964e1298b18b84 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 25 Jan 2024 15:47:48 +0800 Subject: [PATCH 448/469] test(utils): add more test case for checkPropTypes --- packages/utils/src/check-prop-types.ts | 10 ++- .../utils/test/src/check-prop-types.test.ts | 65 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/packages/utils/src/check-prop-types.ts b/packages/utils/src/check-prop-types.ts index 89555c70b4..dc9ce31ed5 100644 --- a/packages/utils/src/check-prop-types.ts +++ b/packages/utils/src/check-prop-types.ts @@ -8,13 +8,13 @@ import { Logger } from './logger'; const PropTypes2 = factoryWithTypeCheckers(ReactIs.isElement, true); const logger = new Logger({ level: 'warn', bizName: 'utils' }); -export function transformPropTypesRuleToString(rule: IPublicTypePropType): string { +export function transformPropTypesRuleToString(rule: IPublicTypePropType | string): string { if (!rule) { return 'PropTypes.any'; } if (typeof rule === 'string') { - return `PropTypes.${rule}`; + return rule.startsWith('PropTypes.') ? rule : `PropTypes.${rule}`; } if (isRequiredPropType(rule)) { @@ -34,7 +34,11 @@ export function transformPropTypesRuleToString(rule: IPublicTypePropType): strin case 'shape': case 'exact': return `PropTypes.${type}({${value.map((item: any) => `${item.name}: ${transformPropTypesRuleToString(item.propType)}`).join(',')}})`; + default: + logger.error(`Unknown prop type: ${type}`); } + + return 'PropTypes.any'; } export function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean { @@ -45,7 +49,7 @@ export function checkPropTypes(value: any, name: string, rule: any, componentNam } if (typeof rule === 'string') { // eslint-disable-next-line no-new-func - ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2); + ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${transformPropTypesRuleToString(rule)}`)(PropTypes2); } if (!ruleFunction || typeof ruleFunction !== 'function') { logger.warn('checkPropTypes should have a function type rule argument'); diff --git a/packages/utils/test/src/check-prop-types.test.ts b/packages/utils/test/src/check-prop-types.test.ts index c1902bec38..74146f2d94 100644 --- a/packages/utils/test/src/check-prop-types.test.ts +++ b/packages/utils/test/src/check-prop-types.test.ts @@ -12,6 +12,26 @@ describe('checkPropTypes', () => { expect(checkPropTypes('123', 'age', PropTypes.number, 'TestComponent')).toBe(false); }); + it('should validate correctly with valid object prop type', () => { + expect(checkPropTypes({ a: 123 }, 'age', PropTypes.object, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: '123' }, 'age', PropTypes.object, 'TestComponent')).toBe(true); + }); + + it('should validate correctly with valid object string prop type', () => { + expect(checkPropTypes({ a: 123 }, 'age', 'object', 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: '123' }, 'age', 'object', 'TestComponent')).toBe(true); + }); + + it('should validate correctly with valid isRequired prop type', () => { + const rule = { + type: 'string', + isRequired: true, + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.string.isRequired'); + expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes(undefined, 'type', rule, 'TestComponent')).toBe(false); + }); + it('should handle custom rule functions correctly', () => { const customRule = (props, propName) => { if (props[propName] !== 123) { @@ -28,6 +48,11 @@ describe('checkPropTypes', () => { expect(result).toBe(true); }); + it('should interpret and validate a rule given as a string', () => { + expect(checkPropTypes(123, 'age', 'number', 'TestComponent')).toBe(true); + expect(checkPropTypes('123', 'age', 'string', 'TestComponent')).toBe(true); + }); + it('should log a warning for invalid rule type', () => { const result = checkPropTypes(123, 'age', 123, 'TestComponent'); expect(result).toBe(true); @@ -60,6 +85,46 @@ describe('checkPropTypes', () => { expect(checkPropTypes({}, 'type', rule, 'TestComponent')).toBe(false); }); + it('should validate correctly with valid oneOfType prop type', () => { + const rule = { + type: 'oneOfType', + value: [ + 'bool', + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSExpression'], + } + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + ], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.oneOfType([PropTypes.bool, PropTypes.shape({type: PropTypes.oneOf(["JSExpression"]),value: PropTypes.string})])'); + expect(checkPropTypes(true, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ type: 'JSExpression', value: '1 + 1 === 2' }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ type: 'JSExpression' }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ type: 'JSExpression', value: 123 }, 'type', rule, 'TestComponent')).toBe(false); + }); + + it('should log a warning for invalid type', () => { + const rule = { + type: 'inval', + value: ['News', 'Photos'], + } + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.any'); + expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes('Others', 'type', rule, 'TestComponent')).toBe(true); + }); + // arrayOf it('should validate correctly with valid arrayOf prop type', () => { const rule = { From b3880e9a96c70d750f8f8487913bf6329cdcfb92 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 25 Jan 2024 15:55:32 +0800 Subject: [PATCH 449/469] feat(command): add command apis --- packages/designer/src/plugin/plugin-types.ts | 2 + packages/editor-core/src/command.ts | 91 +++ packages/editor-core/src/index.ts | 1 + packages/editor-core/test/command.test.ts | 326 +++++++++++ packages/engine/src/engine-core.ts | 29 + .../src/inner-plugins/default-command.ts | 524 ++++++++++++++++++ .../inner-plugins/default-command.test.ts | 110 ++++ packages/renderer-core/src/utils/common.ts | 2 +- packages/shell/src/api/command.ts | 46 ++ packages/shell/src/api/index.ts | 3 +- packages/shell/src/index.ts | 2 + packages/shell/src/symbols.ts | 3 +- packages/types/src/shell/api/command.ts | 34 ++ packages/types/src/shell/api/index.ts | 1 + .../types/src/shell/model/plugin-context.ts | 3 + packages/types/src/shell/type/command.ts | 71 +++ packages/types/src/shell/type/index.ts | 3 +- packages/types/src/shell/type/plugin-meta.ts | 8 + .../workspace/src/context/base-context.ts | 7 + 19 files changed, 1262 insertions(+), 4 deletions(-) create mode 100644 packages/editor-core/src/command.ts create mode 100644 packages/editor-core/test/command.test.ts create mode 100644 packages/engine/src/inner-plugins/default-command.ts create mode 100644 packages/engine/tests/inner-plugins/default-command.test.ts create mode 100644 packages/shell/src/api/command.ts create mode 100644 packages/types/src/shell/api/command.ts create mode 100644 packages/types/src/shell/type/command.ts diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index d648067a36..cfc38866f5 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -19,6 +19,7 @@ import { IPublicModelWindow, IPublicEnumPluginRegisterLevel, IPublicApiCommonUI, + IPublicApiCommand, } from '@alilc/lowcode-types'; import PluginContext from './plugin-context'; @@ -63,6 +64,7 @@ export interface ILowCodePluginContextPrivate { set registerLevel(level: IPublicEnumPluginRegisterLevel); set isPluginRegisteredInWorkspace(flag: boolean); set commonUI(commonUI: IPublicApiCommonUI); + set command(command: IPublicApiCommand); } export interface ILowCodePluginContextApiAssembler { assembleApis( diff --git a/packages/editor-core/src/command.ts b/packages/editor-core/src/command.ts new file mode 100644 index 0000000000..7facc33d94 --- /dev/null +++ b/packages/editor-core/src/command.ts @@ -0,0 +1,91 @@ +import { IPublicApiCommand, IPublicEnumTransitionType, IPublicModelPluginContext, IPublicTypeCommand, IPublicTypeCommandHandlerArgs, IPublicTypeListCommand } from '@alilc/lowcode-types'; +import { checkPropTypes } from '@alilc/lowcode-utils'; +export interface ICommand extends Omit<IPublicApiCommand, 'registerCommand' | 'batchExecuteCommand'> { + registerCommand(command: IPublicTypeCommand, options?: { + commandScope?: string; + }): void; + + batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[], pluginContext?: IPublicModelPluginContext): void; +} + +export interface ICommandOptions { + commandScope?: string; +} + +export class Command implements ICommand { + private commands: Map<string, IPublicTypeCommand> = new Map(); + private commandErrors: Function[] = []; + + registerCommand(command: IPublicTypeCommand, options?: ICommandOptions): void { + if (!options?.commandScope) { + throw new Error('plugin meta.commandScope is required.'); + } + const name = `${options.commandScope}:${command.name}`; + if (this.commands.has(name)) { + throw new Error(`Command '${command.name}' is already registered.`); + } + this.commands.set(name, { + ...command, + name, + }); + } + + unregisterCommand(name: string): void { + if (!this.commands.has(name)) { + throw new Error(`Command '${name}' is not registered.`); + } + this.commands.delete(name); + } + + executeCommand(name: string, args: IPublicTypeCommandHandlerArgs): void { + const command = this.commands.get(name); + if (!command) { + throw new Error(`Command '${name}' is not registered.`); + } + command.parameters?.forEach(d => { + if (!checkPropTypes(args[d.name], d.name, d.propType, 'command')) { + throw new Error(`Command '${name}' arguments ${d.name} is invalid.`); + } + }); + try { + command.handler(args); + } catch (error) { + if (this.commandErrors && this.commandErrors.length) { + this.commandErrors.forEach(callback => callback(name, error)); + } else { + throw error; + } + } + } + + batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[], pluginContext: IPublicModelPluginContext): void { + if (!commands || !commands.length) { + return; + } + pluginContext.common.utils.executeTransaction(() => { + commands.forEach(command => this.executeCommand(command.name, command.args)); + }, IPublicEnumTransitionType.REPAINT); + } + + listCommands(): IPublicTypeListCommand[] { + return Array.from(this.commands.values()).map(d => { + const result: IPublicTypeListCommand = { + name: d.name, + }; + + if (d.description) { + result.description = d.description; + } + + if (d.parameters) { + result.parameters = d.parameters; + } + + return result; + }); + } + + onCommandError(callback: (name: string, error: Error) => void): void { + this.commandErrors.push(callback); + } +} diff --git a/packages/editor-core/src/index.ts b/packages/editor-core/src/index.ts index 9b0542bdaf..c4a54bccde 100644 --- a/packages/editor-core/src/index.ts +++ b/packages/editor-core/src/index.ts @@ -6,3 +6,4 @@ export * from './hotkey'; export * from './widgets'; export * from './config'; export * from './event-bus'; +export * from './command'; diff --git a/packages/editor-core/test/command.test.ts b/packages/editor-core/test/command.test.ts new file mode 100644 index 0000000000..bb2e15943d --- /dev/null +++ b/packages/editor-core/test/command.test.ts @@ -0,0 +1,326 @@ +import { Command } from '../src/command'; + +describe('Command', () => { + let commandInstance; + let mockHandler; + + beforeEach(() => { + commandInstance = new Command(); + mockHandler = jest.fn(); + }); + + describe('registerCommand', () => { + it('should register a command successfully', () => { + const command = { + name: 'testCommand', + handler: mockHandler, + }; + commandInstance.registerCommand(command, { commandScope: 'testScope' }); + + const registeredCommand = commandInstance.listCommands().find(c => c.name === 'testScope:testCommand'); + expect(registeredCommand).toBeDefined(); + expect(registeredCommand.name).toBe('testScope:testCommand'); + }); + + it('should throw an error if commandScope is not provided', () => { + const command = { + name: 'testCommand', + handler: mockHandler, + }; + + expect(() => { + commandInstance.registerCommand(command); + }).toThrow('plugin meta.commandScope is required.'); + }); + + it('should throw an error if command is already registered', () => { + const command = { + name: 'testCommand', + handler: mockHandler, + }; + commandInstance.registerCommand(command, { commandScope: 'testScope' }); + + expect(() => { + commandInstance.registerCommand(command, { commandScope: 'testScope' }); + }).toThrow(`Command 'testCommand' is already registered.`); + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); + +describe('unregisterCommand', () => { + let commandInstance; + let mockHandler; + + beforeEach(() => { + commandInstance = new Command(); + mockHandler = jest.fn(); + // 先注册一个命令以便之后注销 + const command = { + name: 'testCommand', + handler: mockHandler, + }; + commandInstance.registerCommand(command, { commandScope: 'testScope' }); + }); + + it('should unregister a command successfully', () => { + const commandName = 'testScope:testCommand'; + expect(commandInstance.listCommands().find(c => c.name === commandName)).toBeDefined(); + + commandInstance.unregisterCommand(commandName); + + expect(commandInstance.listCommands().find(c => c.name === commandName)).toBeUndefined(); + }); + + it('should throw an error if the command is not registered', () => { + const nonExistingCommandName = 'testScope:nonExistingCommand'; + expect(() => { + commandInstance.unregisterCommand(nonExistingCommandName); + }).toThrow(`Command '${nonExistingCommandName}' is not registered.`); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); + +describe('executeCommand', () => { + let commandInstance; + let mockHandler; + + beforeEach(() => { + commandInstance = new Command(); + mockHandler = jest.fn(); + // 注册一个带参数校验的命令 + const command = { + name: 'testCommand', + handler: mockHandler, + parameters: [ + { name: 'param1', propType: 'string' }, + { name: 'param2', propType: 'number' } + ], + }; + commandInstance.registerCommand(command, { commandScope: 'testScope' }); + }); + + it('should execute a command successfully', () => { + const commandName = 'testScope:testCommand'; + const args = { param1: 'test', param2: 42 }; + + commandInstance.executeCommand(commandName, args); + + expect(mockHandler).toHaveBeenCalledWith(args); + }); + + it('should throw an error if the command is not registered', () => { + const nonExistingCommandName = 'testScope:nonExistingCommand'; + expect(() => { + commandInstance.executeCommand(nonExistingCommandName, {}); + }).toThrow(`Command '${nonExistingCommandName}' is not registered.`); + }); + + it('should throw an error if arguments are invalid', () => { + const commandName = 'testScope:testCommand'; + const invalidArgs = { param1: 'test', param2: 'not-a-number' }; // param2 should be a number + + expect(() => { + commandInstance.executeCommand(commandName, invalidArgs); + }).toThrow(`Command '${commandName}' arguments param2 is invalid.`); + }); + + it('should handle errors thrown by the command handler', () => { + const commandName = 'testScope:testCommand'; + const args = { param1: 'test', param2: 42 }; + const errorMessage = 'Command handler error'; + mockHandler.mockImplementation(() => { + throw new Error(errorMessage); + }); + + expect(() => { + commandInstance.executeCommand(commandName, args); + }).toThrow(errorMessage); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); + +describe('batchExecuteCommand', () => { + let commandInstance; + let mockHandler; + let mockExecuteTransaction; + let mockPluginContext; + + beforeEach(() => { + commandInstance = new Command(); + mockHandler = jest.fn(); + mockExecuteTransaction = jest.fn(callback => callback()); + mockPluginContext = { + common: { + utils: { + executeTransaction: mockExecuteTransaction + } + } + }; + + // 注册几个命令 + const command1 = { + name: 'testCommand1', + handler: mockHandler, + }; + const command2 = { + name: 'testCommand2', + handler: mockHandler, + }; + commandInstance.registerCommand(command1, { commandScope: 'testScope' }); + commandInstance.registerCommand(command2, { commandScope: 'testScope' }); + }); + + it('should execute a batch of commands', () => { + const commands = [ + { name: 'testScope:testCommand1', args: { param: 'value1' } }, + { name: 'testScope:testCommand2', args: { param: 'value2' } }, + ]; + + commandInstance.batchExecuteCommand(commands, mockPluginContext); + + expect(mockExecuteTransaction).toHaveBeenCalledTimes(1); + expect(mockHandler).toHaveBeenCalledWith({ param: 'value1' }); + expect(mockHandler).toHaveBeenCalledWith({ param: 'value2' }); + }); + + it('should not execute anything if commands array is empty', () => { + commandInstance.batchExecuteCommand([], mockPluginContext); + + expect(mockExecuteTransaction).not.toHaveBeenCalled(); + expect(mockHandler).not.toHaveBeenCalled(); + }); + + it('should handle errors thrown during command execution', () => { + const errorMessage = 'Command handler error'; + mockHandler.mockImplementation(() => { + throw new Error(errorMessage); + }); + + const commands = [ + { name: 'testScope:testCommand1', args: { param: 'value1' } }, + { name: 'testScope:testCommand2', args: { param: 'value2' } }, + ]; + + expect(() => { + commandInstance.batchExecuteCommand(commands, mockPluginContext); + }).toThrow(errorMessage); + + expect(mockExecuteTransaction).toHaveBeenCalledTimes(1); // Still called once + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); + +describe('listCommands', () => { + let commandInstance; + let mockHandler; + + beforeEach(() => { + commandInstance = new Command(); + mockHandler = jest.fn(); + }); + + it('should list all registered commands', () => { + // 注册几个命令 + const command1 = { + name: 'testCommand1', + handler: mockHandler, + description: 'Test Command 1', + parameters: [{ name: 'param1', propType: 'string' }] + }; + const command2 = { + name: 'testCommand2', + handler: mockHandler, + description: 'Test Command 2', + parameters: [{ name: 'param2', propType: 'number' }] + }; + commandInstance.registerCommand(command1, { commandScope: 'testScope' }); + commandInstance.registerCommand(command2, { commandScope: 'testScope' }); + + const listedCommands = commandInstance.listCommands(); + + expect(listedCommands.length).toBe(2); + expect(listedCommands).toEqual(expect.arrayContaining([ + expect.objectContaining({ + name: 'testScope:testCommand1', + description: 'Test Command 1', + parameters: [{ name: 'param1', propType: 'string' }] + }), + expect.objectContaining({ + name: 'testScope:testCommand2', + description: 'Test Command 2', + parameters: [{ name: 'param2', propType: 'number' }] + }) + ])); + }); + + it('should return an empty array if no commands are registered', () => { + const listedCommands = commandInstance.listCommands(); + expect(listedCommands).toEqual([]); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); + +describe('onCommandError', () => { + let commandInstance; + let mockHandler; + let mockErrorHandler1; + let mockErrorHandler2; + + beforeEach(() => { + commandInstance = new Command(); + mockHandler = jest.fn(); + mockErrorHandler1 = jest.fn(); + mockErrorHandler2 = jest.fn(); + + // 注册一个命令,该命令会抛出错误 + const command = { + name: 'testCommand', + handler: () => { + throw new Error('Command execution failed'); + }, + }; + commandInstance.registerCommand(command, { commandScope: 'testScope' }); + }); + + it('should call all registered error handlers when a command throws an error', () => { + const commandName = 'testScope:testCommand'; + commandInstance.onCommandError(mockErrorHandler1); + commandInstance.onCommandError(mockErrorHandler2); + + expect(() => { + commandInstance.executeCommand(commandName, {}); + }).not.toThrow(); + + // 确保所有错误处理函数都被调用,并且传递了正确的参数 + expect(mockErrorHandler1).toHaveBeenCalledWith(commandName, expect.any(Error)); + expect(mockErrorHandler2).toHaveBeenCalledWith(commandName, expect.any(Error)); + }); + + it('should throw the error if no error handlers are registered', () => { + const commandName = 'testScope:testCommand'; + + expect(() => { + commandInstance.executeCommand(commandName, {}); + }).toThrow('Command execution failed'); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 3ccfdf51d1..778438a3d4 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -10,6 +10,7 @@ import { Setters as InnerSetters, Hotkey as InnerHotkey, IEditor, + Command as InnerCommand, } from '@alilc/lowcode-editor-core'; import { IPublicTypeEngineOptions, @@ -19,6 +20,7 @@ import { IPublicApiPlugins, IPublicApiWorkspace, IPublicEnumPluginRegisterLevel, + IPublicModelPluginContext, } from '@alilc/lowcode-types'; import { Designer, @@ -52,6 +54,7 @@ import { Workspace, Config, CommonUI, + Command, } from '@alilc/lowcode-shell'; import { isPlainObject } from '@alilc/lowcode-utils'; import './modules/live-editing'; @@ -63,6 +66,7 @@ import { defaultPanelRegistry } from './inner-plugins/default-panel-registry'; import { shellModelFactory } from './modules/shell-model-factory'; import { builtinHotkey } from './inner-plugins/builtin-hotkey'; import { defaultContextMenu } from './inner-plugins/default-context-menu'; +import { defaultCommand } from './inner-plugins/default-command'; import { OutlinePlugin } from '@alilc/lowcode-plugin-outline-pane'; export * from './modules/skeleton-types'; @@ -80,6 +84,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins await plugins.register(builtinHotkey); await plugins.register(registerDefaults, {}, { autoInit: true }); await plugins.register(defaultContextMenu); + await plugins.register(defaultCommand, {}); return () => { plugins.delete(OutlinePlugin.pluginName); @@ -89,6 +94,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins plugins.delete(builtinHotkey.pluginName); plugins.delete(registerDefaults.pluginName); plugins.delete(defaultContextMenu.pluginName); + plugins.delete(defaultCommand.pluginName); }; } @@ -99,6 +105,8 @@ globalContext.register(editor, Editor); globalContext.register(editor, 'editor'); globalContext.register(innerWorkspace, 'workspace'); +const engineContext: Partial<ILowCodePluginContextPrivate> = {}; + const innerSkeleton = new InnerSkeleton(editor); editor.set('skeleton' as any, innerSkeleton); @@ -113,6 +121,8 @@ const project = new Project(innerProject); const skeleton = new Skeleton(innerSkeleton, 'any', false); const innerSetters = new InnerSetters(); const setters = new Setters(innerSetters); +const innerCommand = new InnerCommand(); +const command = new Command(innerCommand, engineContext as IPublicModelPluginContext); const material = new Material(editor); const commonUI = new CommonUI(editor); @@ -136,6 +146,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.setters = setters; context.material = material; const eventPrefix = meta?.eventPrefix || 'common'; + const commandScope = meta?.commandScope; context.event = new Event(commonEvent, { prefix: eventPrefix }); context.config = config; context.common = common; @@ -144,6 +155,9 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.workspace = workspace; context.commonUI = commonUI; + context.command = new Command(innerCommand, context as IPublicModelPluginContext, { + commandScope, + }); context.registerLevel = IPublicEnumPluginRegisterLevel.Default; context.isPluginRegisteredInWorkspace = false; editor.set('pluginContext', context); @@ -155,6 +169,20 @@ plugins = new Plugins(innerPlugins).toProxy(); editor.set('innerPlugins' as any, innerPlugins); editor.set('plugins' as any, plugins); +engineContext.skeleton = skeleton; +engineContext.plugins = plugins; +engineContext.project = project; +engineContext.setters = setters; +engineContext.material = material; +engineContext.event = event; +engineContext.logger = logger; +engineContext.hotkey = hotkey; +engineContext.common = common; +engineContext.workspace = workspace; +engineContext.canvas = canvas; +engineContext.commonUI = commonUI; +engineContext.command = command; + export { skeleton, plugins, @@ -169,6 +197,7 @@ export { workspace, canvas, commonUI, + command, }; // declare this is open-source version export const isOpenSource = true; diff --git a/packages/engine/src/inner-plugins/default-command.ts b/packages/engine/src/inner-plugins/default-command.ts new file mode 100644 index 0000000000..b2b899acb0 --- /dev/null +++ b/packages/engine/src/inner-plugins/default-command.ts @@ -0,0 +1,524 @@ +import { + IPublicModelPluginContext, + IPublicTypeNodeSchema, + IPublicTypePropType, +} from '@alilc/lowcode-types'; +import { isNodeSchema } from '@alilc/lowcode-utils'; + +const sampleNodeSchema: IPublicTypePropType = { + type: 'shape', + value: [ + { + name: 'id', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'componentName', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'props', + propType: 'object', + }, + { + name: 'condition', + propType: 'any', + }, + { + name: 'loop', + propType: 'any', + }, + { + name: 'loopArgs', + propType: 'any', + }, + { + name: 'children', + propType: 'any', + }, + ], +}; + +export const nodeSchemaPropType: IPublicTypePropType = { + type: 'shape', + value: [ + sampleNodeSchema.value[0], + sampleNodeSchema.value[1], + { + name: 'props', + propType: { + type: 'objectOf', + value: { + type: 'oneOfType', + // 不会强制校验,更多作为提示 + value: [ + 'any', + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSExpression'], + }, + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSFunction'], + }, + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSSlot'], + }, + }, + { + name: 'value', + propType: { + type: 'oneOfType', + value: [ + sampleNodeSchema, + { + type: 'arrayOf', + value: sampleNodeSchema, + }, + ], + }, + }, + ], + }, + ], + }, + }, + }, + { + name: 'condition', + propType: { + type: 'oneOfType', + value: [ + 'bool', + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSExpression'], + }, + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + ], + }, + }, + { + name: 'loop', + propType: { + type: 'oneOfType', + value: [ + 'array', + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSExpression'], + }, + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + ], + }, + }, + { + name: 'loopArgs', + propType: { + type: 'oneOfType', + value: [ + { + type: 'arrayOf', + value: { + type: 'oneOfType', + value: [ + 'any', + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSExpression'], + }, + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + ], + }, + }, + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSExpression'], + }, + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + ], + }, + }, + { + name: 'children', + propType: { + type: 'arrayOf', + value: sampleNodeSchema, + }, + }, + ], +}; + +export const historyCommand = (ctx: IPublicModelPluginContext) => { + const { command, project } = ctx; + return { + init() { + command.registerCommand({ + name: 'undo', + description: 'Undo the last operation.', + handler: () => { + const state = project.currentDocument?.history.getState() || 0; + const enable = !!(state & 1); + if (!enable) { + throw new Error('Can not undo.'); + } + project.currentDocument?.history.back(); + }, + }); + + command.registerCommand({ + name: 'redo', + description: 'Redo the last operation.', + handler: () => { + const state = project.currentDocument?.history.getState() || 0; + const enable = !!(state & 2); + if (!enable) { + throw new Error('Can not redo.'); + } + project.currentDocument?.history.forward(); + }, + }); + }, + }; +}; + +historyCommand.pluginName = '___history_command___'; +historyCommand.meta = { + commandScope: 'history', +}; + +export const nodeCommand = (ctx: IPublicModelPluginContext) => { + const { command, project } = ctx; + return { + init() { + command.registerCommand({ + name: 'add', + description: 'Add a node to the canvas.', + handler: (param: { + parentNodeId: string; + nodeSchema: IPublicTypeNodeSchema; + }) => { + const { + parentNodeId, + nodeSchema, + } = param; + const { project } = ctx; + const parentNode = project.currentDocument?.getNodeById(parentNodeId); + if (!parentNode) { + throw new Error(`Can not find node '${parentNodeId}'.`); + } + + if (!parentNode.isContainerNode) { + throw new Error(`Node '${parentNodeId}' is not a container node.`); + } + + if (!isNodeSchema(nodeSchema)) { + throw new Error('Invalid node.'); + } + + project.currentDocument?.insertNode(parentNode, nodeSchema); + }, + parameters: [ + { + name: 'parentNodeId', + propType: 'string', + description: 'The id of the parent node.', + }, + { + name: 'nodeSchema', + propType: nodeSchemaPropType, + description: 'The node to be added.', + }, + ], + }); + + command.registerCommand({ + name: 'move', + description: 'Move a node to another node.', + handler(param: { + nodeId: string; + targetNodeId: string; + index: number; + }) { + const { + nodeId, + targetNodeId, + index = 0, + } = param; + + const node = project.currentDocument?.getNodeById(nodeId); + const targetNode = project.currentDocument?.getNodeById(targetNodeId); + if (!node) { + throw new Error(`Can not find node '${nodeId}'.`); + } + + if (!targetNode) { + throw new Error(`Can not find node '${targetNodeId}'.`); + } + + if (!targetNode.isContainerNode) { + throw new Error(`Node '${targetNodeId}' is not a container node.`); + } + + if (index < 0 || index > (targetNode.children?.size || 0)) { + throw new Error(`Invalid index '${index}'.`); + } + + project.currentDocument?.removeNode(node); + project.currentDocument?.insertNode(targetNode, node, index); + }, + parameters: [ + { + name: 'nodeId', + propType: 'string', + description: 'The id of the node to be moved.', + }, + { + name: 'targetNodeId', + propType: 'string', + description: 'The id of the target node.', + }, + { + name: 'index', + propType: 'number', + description: 'The index of the node to be moved.', + }, + ], + }); + + command.registerCommand({ + name: 'remove', + description: 'Remove a node from the canvas.', + handler(param: { + nodeId: string; + }) { + const { + nodeId, + } = param; + + const node = project.currentDocument?.getNodeById(nodeId); + if (!node) { + throw new Error(`Can not find node '${nodeId}'.`); + } + + project.currentDocument?.removeNode(node); + }, + parameters: [ + { + name: 'nodeId', + propType: 'string', + description: 'The id of the node to be removed.', + }, + ], + }); + + command.registerCommand({ + name: 'replace', + description: 'Replace a node with another node.', + handler(param: { + nodeId: string; + nodeSchema: IPublicTypeNodeSchema; + }) { + const { + nodeId, + nodeSchema, + } = param; + + const node = project.currentDocument?.getNodeById(nodeId); + if (!node) { + throw new Error(`Can not find node '${nodeId}'.`); + } + + if (!isNodeSchema(nodeSchema)) { + throw new Error('Invalid node.'); + } + + node.importSchema(nodeSchema); + }, + parameters: [ + { + name: 'nodeId', + propType: 'string', + description: 'The id of the node to be replaced.', + }, + { + name: 'nodeSchema', + propType: nodeSchemaPropType, + description: 'The node to replace.', + }, + ], + }); + + command.registerCommand({ + name: 'updateProps', + description: 'Update the properties of a node.', + handler(param: { + nodeId: string; + props: Record<string, any>; + }) { + const { + nodeId, + props, + } = param; + + const node = project.currentDocument?.getNodeById(nodeId); + if (!node) { + throw new Error(`Can not find node '${nodeId}'.`); + } + + Object.keys(props).forEach(key => { + node.setPropValue(key, props[key]); + }); + }, + parameters: [ + { + name: 'nodeId', + propType: 'string', + description: 'The id of the node to be updated.', + }, + { + name: 'props', + propType: 'object', + description: 'The properties to be updated.', + }, + ], + }); + + command.registerCommand({ + name: 'removeProps', + description: 'Remove the properties of a node.', + handler(param: { + nodeId: string; + propNames: string[]; + }) { + const { + nodeId, + propNames, + } = param; + + const node = project.currentDocument?.getNodeById(nodeId); + if (!node) { + throw new Error(`Can not find node '${nodeId}'.`); + } + + propNames.forEach(key => { + node.props?.getProp(key)?.remove(); + }); + }, + parameters: [ + { + name: 'nodeId', + propType: 'string', + description: 'The id of the node to be updated.', + }, + { + name: 'propNames', + propType: 'array', + description: 'The properties to be removed.', + }, + ], + }); + }, + }; +}; + +nodeCommand.pluginName = '___node_command___'; +nodeCommand.meta = { + commandScope: 'node', +}; + +export const defaultCommand = (ctx: IPublicModelPluginContext) => { + const { plugins } = ctx; + plugins.register(nodeCommand); + plugins.register(historyCommand); + + return { + init() { + }, + }; +}; + +defaultCommand.pluginName = '___default_command___'; +defaultCommand.meta = { + commandScope: 'common', +}; diff --git a/packages/engine/tests/inner-plugins/default-command.test.ts b/packages/engine/tests/inner-plugins/default-command.test.ts new file mode 100644 index 0000000000..0e28c642b8 --- /dev/null +++ b/packages/engine/tests/inner-plugins/default-command.test.ts @@ -0,0 +1,110 @@ +import { checkPropTypes } from '@alilc/lowcode-utils/src/check-prop-types'; +import { nodeSchemaPropType } from '../../src/inner-plugins/default-command'; + +describe('nodeSchemaPropType', () => { + const componentName = 'NodeComponent'; + const getPropType = (name: string) => nodeSchemaPropType.value.find(d => d.name === name)?.propType; + + it('should validate the id as a string', () => { + const validId = 'node1'; + const invalidId = 123; // Not a string + expect(checkPropTypes(validId, 'id', getPropType('id'), componentName)).toBe(true); + expect(checkPropTypes(invalidId, 'id', getPropType('id'), componentName)).toBe(false); + // isRequired + expect(checkPropTypes(undefined, 'id', getPropType('id'), componentName)).toBe(false); + }); + + it('should validate the componentName as a string', () => { + const validComponentName = 'Button'; + const invalidComponentName = false; // Not a string + expect(checkPropTypes(validComponentName, 'componentName', getPropType('componentName'), componentName)).toBe(true); + expect(checkPropTypes(invalidComponentName, 'componentName', getPropType('componentName'), componentName)).toBe(false); + // isRequired + expect(checkPropTypes(undefined, 'componentName', getPropType('componentName'), componentName)).toBe(false); + }); + + it('should validate the props as an object', () => { + const validProps = { key: 'value' }; + const invalidProps = 'Not an object'; // Not an object + expect(checkPropTypes(validProps, 'props', getPropType('props'), componentName)).toBe(true); + expect(checkPropTypes(invalidProps, 'props', getPropType('props'), componentName)).toBe(false); + }); + + it('should validate the props as a JSExpression', () => { + const validProps = { type: 'JSExpression', value: 'props' }; + expect(checkPropTypes(validProps, 'props', getPropType('props'), componentName)).toBe(true); + }); + + it('should validate the props as a JSFunction', () => { + const validProps = { type: 'JSFunction', value: 'props' }; + expect(checkPropTypes(validProps, 'props', getPropType('props'), componentName)).toBe(true); + }); + + it('should validate the props as a JSSlot', () => { + const validProps = { type: 'JSSlot', value: 'props' }; + expect(checkPropTypes(validProps, 'props', getPropType('props'), componentName)).toBe(true); + }); + + it('should validate the condition as a bool', () => { + const validCondition = true; + const invalidCondition = 'Not a bool'; // Not a boolean + expect(checkPropTypes(validCondition, 'condition', getPropType('condition'), componentName)).toBe(true); + expect(checkPropTypes(invalidCondition, 'condition', getPropType('condition'), componentName)).toBe(false); + }); + + it('should validate the condition as a JSExpression', () => { + const validCondition = { type: 'JSExpression', value: '1 + 1 === 2' }; + const invalidCondition = { type: 'JSExpression', value: 123 }; // Not a string + expect(checkPropTypes(validCondition, 'condition', getPropType('condition'), componentName)).toBe(true); + expect(checkPropTypes(invalidCondition, 'condition', getPropType('condition'), componentName)).toBe(false); + }); + + it('should validate the loop as an array', () => { + const validLoop = ['item1', 'item2']; + const invalidLoop = 'Not an array'; // Not an array + expect(checkPropTypes(validLoop, 'loop', getPropType('loop'), componentName)).toBe(true); + expect(checkPropTypes(invalidLoop, 'loop', getPropType('loop'), componentName)).toBe(false); + }); + + it('should validate the loop as a JSExpression', () => { + const validLoop = { type: 'JSExpression', value: 'items' }; + const invalidLoop = { type: 'JSExpression', value: 123 }; // Not a string + expect(checkPropTypes(validLoop, 'loop', getPropType('loop'), componentName)).toBe(true); + expect(checkPropTypes(invalidLoop, 'loop', getPropType('loop'), componentName)).toBe(false); + }) + + it('should validate the loopArgs as an array', () => { + const validLoopArgs = ['item']; + const invalidLoopArgs = 'Not an array'; // Not an array + expect(checkPropTypes(validLoopArgs, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(true); + expect(checkPropTypes(invalidLoopArgs, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(false); + }); + + it('should validate the loopArgs as a JSExpression', () => { + const validLoopArgs = { type: 'JSExpression', value: 'item' }; + const invalidLoopArgs = { type: 'JSExpression', value: 123 }; // Not a string + const validLoopArgs2 = [{ type: 'JSExpression', value: 'item' }, { type: 'JSExpression', value: 'index' }]; + expect(checkPropTypes(validLoopArgs, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(true); + expect(checkPropTypes(invalidLoopArgs, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(false); + expect(checkPropTypes(validLoopArgs2, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(true); + }); + + it('should validate the children as an array', () => { + const validChildren = [{ + id: 'child1', + componentName: 'Button', + }, { + id: 'child2', + componentName: 'Button', + }]; + const invalidChildren = 'Not an array'; // Not an array + const invalidChildren2 = [{}]; // Not an valid array + expect(checkPropTypes(invalidChildren, 'children', getPropType('children'), componentName)).toBe(false); + expect(checkPropTypes(validChildren, 'children', getPropType('children'), componentName)).toBe(true); + expect(checkPropTypes(invalidChildren2, 'children', getPropType('children'), componentName)).toBe(false); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts index 80150f379f..0462d358a7 100644 --- a/packages/renderer-core/src/utils/common.ts +++ b/packages/renderer-core/src/utils/common.ts @@ -1,7 +1,7 @@ /* eslint-disable no-console */ /* eslint-disable no-new-func */ import logger from './logger'; -import { IPublicTypeRootSchema, IPublicTypeNodeSchema, IPublicTypeJSSlot, IPublicTypePropType, IPublicTypeRequiredType, IPublicTypeBasicType } from '@alilc/lowcode-types'; +import { IPublicTypeRootSchema, IPublicTypeNodeSchema, IPublicTypeJSSlot } from '@alilc/lowcode-types'; import { isI18nData, isJSExpression } from '@alilc/lowcode-utils'; import { isEmpty } from 'lodash'; import IntlMessageFormat from 'intl-messageformat'; diff --git a/packages/shell/src/api/command.ts b/packages/shell/src/api/command.ts new file mode 100644 index 0000000000..ebab4a9ff5 --- /dev/null +++ b/packages/shell/src/api/command.ts @@ -0,0 +1,46 @@ +import { IPublicApiCommand, IPublicModelPluginContext, IPublicTypeCommand, IPublicTypeCommandHandlerArgs, IPublicTypeListCommand } from '@alilc/lowcode-types'; +import { commandSymbol, pluginContextSymbol } from '../symbols'; +import { ICommand, ICommandOptions } from '@alilc/lowcode-editor-core'; + +const optionsSymbol = Symbol('options'); +const commandScopeSet = new Set<string>(); + +export class Command implements IPublicApiCommand { + [commandSymbol]: ICommand; + [optionsSymbol]?: ICommandOptions; + [pluginContextSymbol]?: IPublicModelPluginContext; + + constructor(innerCommand: ICommand, pluginContext?: IPublicModelPluginContext, options?: ICommandOptions) { + this[commandSymbol] = innerCommand; + this[optionsSymbol] = options; + this[pluginContextSymbol] = pluginContext; + const commandScope = options?.commandScope; + if (commandScope && commandScopeSet.has(commandScope)) { + throw new Error(`Command scope "${commandScope}" has been registered.`); + } + } + + registerCommand(command: IPublicTypeCommand): void { + this[commandSymbol].registerCommand(command, this[optionsSymbol]); + } + + batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[]): void { + this[commandSymbol].batchExecuteCommand(commands, this[pluginContextSymbol]); + } + + executeCommand(name: string, args: IPublicTypeCommandHandlerArgs): void { + this[commandSymbol].executeCommand(name, args); + } + + listCommands(): IPublicTypeListCommand[] { + return this[commandSymbol].listCommands(); + } + + unregisterCommand(name: string): void { + this[commandSymbol].unregisterCommand(name); + } + + onCommandError(callback: (name: string, error: Error) => void): void { + this[commandSymbol].onCommandError(callback); + } +} diff --git a/packages/shell/src/api/index.ts b/packages/shell/src/api/index.ts index 3726020de0..79340f6777 100644 --- a/packages/shell/src/api/index.ts +++ b/packages/shell/src/api/index.ts @@ -11,4 +11,5 @@ export * from './skeleton'; export * from './canvas'; export * from './workspace'; export * from './config'; -export * from './commonUI'; \ No newline at end of file +export * from './commonUI'; +export * from './command'; \ No newline at end of file diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index ce09ccaaa7..fb1e7228f3 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -29,6 +29,7 @@ import { SimulatorHost, Config, CommonUI, + Command, } from './api'; export * from './symbols'; @@ -70,4 +71,5 @@ export { SettingField, SkeletonItem, CommonUI, + Command, }; diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index 8e2962a24f..e0f846ad36 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -39,4 +39,5 @@ export const configSymbol = Symbol('configSymbol'); export const conditionGroupSymbol = Symbol('conditionGroup'); export const editorViewSymbol = Symbol('editorView'); export const pluginContextSymbol = Symbol('pluginContext'); -export const skeletonItemSymbol = Symbol('skeletonItem'); \ No newline at end of file +export const skeletonItemSymbol = Symbol('skeletonItem'); +export const commandSymbol = Symbol('command'); \ No newline at end of file diff --git a/packages/types/src/shell/api/command.ts b/packages/types/src/shell/api/command.ts new file mode 100644 index 0000000000..5cbfaa2e10 --- /dev/null +++ b/packages/types/src/shell/api/command.ts @@ -0,0 +1,34 @@ +import { IPublicTypeCommand, IPublicTypeCommandHandlerArgs, IPublicTypeListCommand } from '../type'; + +export interface IPublicApiCommand { + + /** + * 注册一个新命令及其处理函数 + */ + registerCommand(command: IPublicTypeCommand): void; + + /** + * 注销一个已存在的命令 + */ + unregisterCommand(name: string): void; + + /** + * 通过名称和给定参数执行一个命令,会校验参数是否符合命令定义 + */ + executeCommand(name: string, args: IPublicTypeCommandHandlerArgs): void; + + /** + * 批量执行命令,执行完所有命令后再进行一次重绘,历史记录中只会记录一次 + */ + batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[]): void; + + /** + * 列出所有已注册的命令 + */ + listCommands(): IPublicTypeListCommand[]; + + /** + * 注册错误处理回调函数 + */ + onCommandError(callback: (name: string, error: Error) => void): void; +} \ No newline at end of file diff --git a/packages/types/src/shell/api/index.ts b/packages/types/src/shell/api/index.ts index 79f1b0dc7c..8f14d8dadd 100644 --- a/packages/types/src/shell/api/index.ts +++ b/packages/types/src/shell/api/index.ts @@ -11,3 +11,4 @@ export * from './logger'; export * from './canvas'; export * from './workspace'; export * from './commonUI'; +export * from './command'; \ No newline at end of file diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts index 45568424de..d4d715e96b 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -12,6 +12,7 @@ import { IPublicApiPlugins, IPublicApiWorkspace, IPublicApiCommonUI, + IPublicApiCommand, } from '../api'; import { IPublicEnumPluginRegisterLevel } from '../enum'; import { IPublicModelEngineConfig, IPublicModelWindow } from './'; @@ -109,6 +110,8 @@ export interface IPublicModelPluginContext { */ get commonUI(): IPublicApiCommonUI; + get command(): IPublicApiCommand; + /** * 插件注册层级 * @since v1.1.7 diff --git a/packages/types/src/shell/type/command.ts b/packages/types/src/shell/type/command.ts new file mode 100644 index 0000000000..dd0420def1 --- /dev/null +++ b/packages/types/src/shell/type/command.ts @@ -0,0 +1,71 @@ +// 定义命令处理函数的参数类型 +export interface IPublicTypeCommandHandlerArgs { + [key: string]: any; +} + +// 定义复杂参数类型的接口 +export interface IPublicTypeCommandPropType { + + /** + * 参数基础类型 + */ + type: string; + + /** + * 参数是否必需(可选) + */ + isRequired?: boolean; +} + +// 定义命令参数的接口 +export interface IPublicTypeCommandParameter { + + /** + * 参数名称 + */ + name: string; + + /** + * 参数类型或详细类型描述 + */ + propType: string | IPublicTypeCommandPropType; + + /** + * 参数描述 + */ + description: string; + + /** + * 参数默认值(可选) + */ + defaultValue?: any; +} + +// 定义单个命令的接口 +export interface IPublicTypeCommand { + + /** + * 命令名称 + * 命名规则:commandName + * 使用规则:commandScope:commandName (commandScope 在插件 meta 中定义,用于区分不同插件的命令) + */ + name: string; + + /** + * 命令参数 + */ + parameters?: IPublicTypeCommandParameter[]; + + /** + * 命令描述 + */ + description?: string; + + /** + * 命令处理函数 + */ + handler: (args: any) => void; +} + +export interface IPublicTypeListCommand extends Pick<IPublicTypeCommand, 'name' | 'description' | 'parameters'> { +} \ No newline at end of file diff --git a/packages/types/src/shell/type/index.ts b/packages/types/src/shell/type/index.ts index b1c7779d05..76dd389255 100644 --- a/packages/types/src/shell/type/index.ts +++ b/packages/types/src/shell/type/index.ts @@ -92,4 +92,5 @@ export * from './hotkey-callbacks'; export * from './scrollable'; export * from './simulator-renderer'; export * from './config-transducer'; -export * from './context-menu'; \ No newline at end of file +export * from './context-menu'; +export * from './command'; \ No newline at end of file diff --git a/packages/types/src/shell/type/plugin-meta.ts b/packages/types/src/shell/type/plugin-meta.ts index 421e59ad0a..bf7f6212e8 100644 --- a/packages/types/src/shell/type/plugin-meta.ts +++ b/packages/types/src/shell/type/plugin-meta.ts @@ -1,14 +1,17 @@ import { IPublicTypePluginDeclaration } from './'; export interface IPublicTypePluginMeta { + /** * define dependencies which the plugin depends on */ dependencies?: string[]; + /** * specify which engine version is compatible with the plugin */ engines?: { + /** e.g. '^1.0.0' */ lowcodeEngine?: string; }; @@ -26,4 +29,9 @@ export interface IPublicTypePluginMeta { * event.emit('someEventName') is actually sending event with name 'myEvent:someEventName' */ eventPrefix?: string; + + /** + * 如果要使用 command 注册命令,需要在插件 meta 中定义 commandScope + */ + commandScope?: string; } diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index 2f6154788f..db33597aea 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -5,6 +5,7 @@ import { commonEvent, IEngineConfig, IHotKey, + Command as InnerCommand, } from '@alilc/lowcode-editor-core'; import { Designer, @@ -33,6 +34,7 @@ import { Window, Canvas, CommonUI, + Command, } from '@alilc/lowcode-shell'; import { IPluginPreferenceMananger, @@ -129,6 +131,7 @@ export class BasicContext implements IBasicContext { const skeleton = new Skeleton(innerSkeleton, 'any', true); const canvas = new Canvas(editor, true); const commonUI = new CommonUI(editor); + const innerCommand = new InnerCommand(); editor.set('setters', setters); editor.set('project', project); editor.set('material', material); @@ -162,6 +165,7 @@ export class BasicContext implements IBasicContext { context.setters = setters; context.material = material; const eventPrefix = meta?.eventPrefix || 'common'; + const commandScope = meta?.commandScope; context.event = new Event(commonEvent, { prefix: eventPrefix }); context.config = config; context.common = common; @@ -172,6 +176,9 @@ export class BasicContext implements IBasicContext { if (editorWindow) { context.editorWindow = new Window(editorWindow); } + context.command = new Command(innerCommand, context as IPublicModelPluginContext, { + commandScope, + }); context.registerLevel = registerLevel; context.isPluginRegisteredInWorkspace = registerLevel === IPublicEnumPluginRegisterLevel.Workspace; editor.set('pluginContext', context); From b29c53901e4a1c1f437d9fe71aadaa16d02686f4 Mon Sep 17 00:00:00 2001 From: ZeralZhang <zeralzhang@gmail.com> Date: Fri, 26 Jan 2024 09:38:37 +0800 Subject: [PATCH 450/469] fix(react-simulator-renderer): detached node has children detached node has children will return false, causing memory leaks. --- packages/react-simulator-renderer/src/renderer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index efebeda040..20f6e18c0b 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -614,7 +614,7 @@ function getNodeInstance(fiberNode: any, specId?: string): IPublicTypeNodeInstan function checkInstanceMounted(instance: any): boolean { if (isElement(instance)) { - return instance.parentElement != null; + return instance.parentElement != null && window.document.contains(instance); } return true; } From b97570f10c1035991d17aba49031edd0ef710024 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 26 Jan 2024 15:20:13 +0800 Subject: [PATCH 451/469] docs(demo): add dialog use desc --- docs/docs/demoUsage/makeStuff/dialog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/demoUsage/makeStuff/dialog.md b/docs/docs/demoUsage/makeStuff/dialog.md index 56303067cb..da78cc8e8c 100644 --- a/docs/docs/demoUsage/makeStuff/dialog.md +++ b/docs/docs/demoUsage/makeStuff/dialog.md @@ -2,6 +2,8 @@ title: 3. 如何通过按钮展示/隐藏弹窗 sidebar_position: 1 --- +> 说明:这个方式依赖低代码弹窗组件是否对外保留了相关的 API,不同的物料支持的方式不一样,这里只针对综合场景的弹窗物料。 + ## 1.拖拽一个按钮 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01kLaWA31D6WwTui9VW_!!6000000000167-2-tps-3584-1812.png) From 739572172a9901c7223f7bc1617495b8e8752900 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 26 Jan 2024 08:40:59 +0000 Subject: [PATCH 452/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 69dddfce2c..ce6a969c1f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.29", + "version": "1.2.30", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 6e89d4d605760d376fedf350b99f24bc11770ec5 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 26 Jan 2024 15:14:16 +0800 Subject: [PATCH 453/469] feat(setter): add field ts --- packages/editor-core/src/di/setter.ts | 6 +++--- .../src/components/settings/settings-pane.tsx | 4 ++-- packages/editor-skeleton/src/transducers/parse-props.ts | 3 ++- packages/types/src/shell/type/field-extra-props.ts | 2 +- packages/types/src/shell/type/registered-setter.ts | 7 +++++-- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/editor-core/src/di/setter.ts b/packages/editor-core/src/di/setter.ts index 437d9a89e2..5af2c0230f 100644 --- a/packages/editor-core/src/di/setter.ts +++ b/packages/editor-core/src/di/setter.ts @@ -1,5 +1,5 @@ import { ReactNode } from 'react'; -import { IPublicApiSetters, IPublicTypeCustomView, IPublicTypeRegisteredSetter } from '@alilc/lowcode-types'; +import { IPublicApiSetters, IPublicModelSettingField, IPublicTypeCustomView, IPublicTypeRegisteredSetter } from '@alilc/lowcode-types'; import { createContent, isCustomView } from '@alilc/lowcode-utils'; const settersMap = new Map<string, IPublicTypeRegisteredSetter & { @@ -28,7 +28,7 @@ export function registerSetter( if (!setter.initialValue) { const initial = getInitialFromSetter(setter.component); if (initial) { - setter.initialValue = (field: any) => { + setter.initialValue = (field: IPublicModelSettingField) => { return initial.call(field, field.getValue()); }; } @@ -81,7 +81,7 @@ export class Setters implements ISetters { if (!setter.initialValue) { const initial = getInitialFromSetter(setter.component); if (initial) { - setter.initialValue = (field: any) => { + setter.initialValue = (field: IPublicModelSettingField) => { return initial.call(field, field.getValue()); }; } diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index 1d651bb5a3..1561bf8bbe 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -225,7 +225,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView const value = this.value; - let _onChange = extraProps?.onChange; + let onChangeAPI = extraProps?.onChange; let stageName = this.stageName; return createField( @@ -261,7 +261,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView value, }); field.setValue(value, true); - if (_onChange) _onChange(value, field); + if (onChangeAPI) onChangeAPI(value, field.internalToShellField()); }, onInitial: () => { if (initialValue == null) { diff --git a/packages/editor-skeleton/src/transducers/parse-props.ts b/packages/editor-skeleton/src/transducers/parse-props.ts index d22f07f437..573d24ac62 100644 --- a/packages/editor-skeleton/src/transducers/parse-props.ts +++ b/packages/editor-skeleton/src/transducers/parse-props.ts @@ -9,6 +9,7 @@ import { IPublicTypeTransformedComponentMetadata, IPublicTypeOneOfType, ConfigureSupportEvent, + IPublicModelSettingField, } from '@alilc/lowcode-types'; function propConfigToFieldConfig(propConfig: IPublicTypePropConfig): IPublicTypeFieldConfig { @@ -102,7 +103,7 @@ function propTypeToSetter(propType: IPublicTypePropType): IPublicTypeSetterType }, }, isRequired, - initialValue: (field: any) => { + initialValue: (field: IPublicModelSettingField) => { const data: any = {}; items.forEach((item: any) => { let initial = item.defaultValue; diff --git a/packages/types/src/shell/type/field-extra-props.ts b/packages/types/src/shell/type/field-extra-props.ts index 3e2df280b7..7aae7e0fe8 100644 --- a/packages/types/src/shell/type/field-extra-props.ts +++ b/packages/types/src/shell/type/field-extra-props.ts @@ -77,5 +77,5 @@ export interface IPublicTypeFieldExtraProps { /** * onChange 事件 */ - onChange?: (value: any, field: any) => void; + onChange?: (value: any, field: IPublicModelSettingField) => void; } diff --git a/packages/types/src/shell/type/registered-setter.ts b/packages/types/src/shell/type/registered-setter.ts index 85cad5a803..55a90465a8 100644 --- a/packages/types/src/shell/type/registered-setter.ts +++ b/packages/types/src/shell/type/registered-setter.ts @@ -1,17 +1,20 @@ +import { IPublicModelSettingField } from '../model'; import { IPublicTypeCustomView, IPublicTypeTitleContent } from './'; export interface IPublicTypeRegisteredSetter { component: IPublicTypeCustomView; defaultProps?: object; title?: IPublicTypeTitleContent; + /** * for MixedSetter to check this setter if available */ - condition?: (field: any) => boolean; + condition?: (field: IPublicModelSettingField) => boolean; + /** * for MixedSetter to manual change to this setter */ - initialValue?: any | ((field: any) => any); + initialValue?: any | ((field: IPublicModelSettingField) => any); recommend?: boolean; // 标识是否为动态 setter,默认为 true isDynamic?: boolean; From e3a19896d78cf79736e0fabba9dd37c4c3f22997 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 26 Jan 2024 16:58:20 +0800 Subject: [PATCH 454/469] fix(prop): emit event when unset prop --- .../designer/src/document/node/props/prop.ts | 43 ++++--- .../tests/document/node/props/prop.test.ts | 106 +++++++++++++++++- 2 files changed, 132 insertions(+), 17 deletions(-) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index e2d9f12e8e..fd9401314a 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -353,7 +353,6 @@ export class Prop implements IProp, IPropParent { @action setValue(val: IPublicTypeCompositeValue) { if (val === this._value) return; - const editor = this.owner.document?.designer.editor; const oldValue = this._value; this._value = val; this._code = null; @@ -386,22 +385,31 @@ export class Prop implements IProp, IPropParent { this.setupItems(); if (oldValue !== this._value) { - const propsInfo = { - key: this.key, - prop: this, - oldValue, - newValue: this._value, - }; - - editor?.eventBus.emit(GlobalEvent.Node.Prop.InnerChange, { - node: this.owner as any, - ...propsInfo, - }); - - this.owner?.emitPropChange?.(propsInfo); + this.emitChange({ oldValue }); } } + emitChange = ({ + oldValue, + }: { + oldValue: IPublicTypeCompositeValue | UNSET; + }) => { + const editor = this.owner.document?.designer.editor; + const propsInfo = { + key: this.key, + prop: this, + oldValue, + newValue: this.type === 'unset' ? undefined : this._value, + }; + + editor?.eventBus.emit(GlobalEvent.Node.Prop.InnerChange, { + node: this.owner as any, + ...propsInfo, + }); + + this.owner?.emitPropChange?.(propsInfo); + }; + getValue(): IPublicTypeCompositeValue { return this.export(IPublicEnumTransformStage.Serilize); } @@ -462,7 +470,12 @@ export class Prop implements IProp, IPropParent { */ @action unset() { - this._type = 'unset'; + if (this._type !== 'unset') { + this._type = 'unset'; + this.emitChange({ + oldValue: this._value, + }); + } } /** diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 4424eb6010..8630376b68 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -3,7 +3,7 @@ import { Editor, engineConfig } from '@alilc/lowcode-editor-core'; import { Designer } from '../../../../src/designer/designer'; import { DocumentModel } from '../../../../src/document/document-model'; import { Prop, isProp, isValidArrayIndex } from '../../../../src/document/node/props/prop'; -import { IPublicEnumTransformStage } from '@alilc/lowcode-types'; +import { GlobalEvent, IPublicEnumTransformStage } from '@alilc/lowcode-types'; import { shellModelFactory } from '../../../../../engine/src/modules/shell-model-factory'; const slotNodeImportMockFn = jest.fn(); @@ -24,9 +24,16 @@ const mockOwner = { remove: slotNodeRemoveMockFn, }; }, - designer: {}, + designer: { + editor: { + eventBus: { + emit: jest.fn(), + }, + }, + }, }, isInited: true, + emitPropChange: jest.fn(), }; const mockPropsInst = { @@ -564,3 +571,98 @@ describe('其他导出函数', () => { expect(isValidArrayIndex('2', 1)).toBeFalsy(); }); }); + +describe('setValue with event', () => { + let propInstance; + let mockEmitChange; + let mockEventBusEmit; + let mockEmitPropChange; + + beforeEach(() => { + // Initialize the instance of your class + propInstance = new Prop(mockPropsInst, true, 'stringProp');; + + // Mock necessary methods and properties + mockEmitChange = jest.spyOn(propInstance, 'emitChange'); + propInstance.owner = { + document: { + designer: { + editor: { + eventBus: { + emit: jest.fn(), + }, + }, + }, + }, + emitPropChange: jest.fn(), + }; + mockEventBusEmit = jest.spyOn(propInstance.owner.document.designer.editor.eventBus, 'emit'); + mockEmitPropChange = jest.spyOn(propInstance.owner, 'emitPropChange'); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('should correctly handle string values and emit changes', () => { + const oldValue = propInstance._value; + const newValue = 'new string value'; + + propInstance.setValue(newValue); + + const expectedPartialPropsInfo = expect.objectContaining({ + key: propInstance.key, + newValue, // You can specifically test only certain keys + oldValue, + }); + + expect(propInstance.getValue()).toBe(newValue); + expect(propInstance.type).toBe('literal'); + expect(mockEmitChange).toHaveBeenCalledWith({ oldValue }); + expect(mockEventBusEmit).toHaveBeenCalledWith(GlobalEvent.Node.Prop.InnerChange, expectedPartialPropsInfo); + expect(mockEmitPropChange).toHaveBeenCalledWith(expectedPartialPropsInfo); + }); + + it('should handle object values and set type to map', () => { + const oldValue = propInstance._value; + const newValue = 234; + + const expectedPartialPropsInfo = expect.objectContaining({ + key: propInstance.key, + newValue, // You can specifically test only certain keys + oldValue, + }); + + propInstance.setValue(newValue); + + expect(propInstance.getValue()).toEqual(newValue); + expect(propInstance.type).toBe('literal'); + expect(mockEmitChange).toHaveBeenCalledWith({ oldValue }); + expect(mockEventBusEmit).toHaveBeenCalledWith(GlobalEvent.Node.Prop.InnerChange, expectedPartialPropsInfo); + expect(mockEmitPropChange).toHaveBeenCalledWith(expectedPartialPropsInfo); + }); + + it('should has event when unset call', () => { + const oldValue = propInstance._value; + + propInstance.unset(); + + const expectedPartialPropsInfo = expect.objectContaining({ + key: propInstance.key, + newValue: undefined, // You can specifically test only certain keys + oldValue, + }); + + expect(propInstance.getValue()).toEqual(undefined); + expect(propInstance.type).toBe('unset'); + expect(mockEmitChange).toHaveBeenCalledWith({ + oldValue, + newValue: undefined, + }); + expect(mockEventBusEmit).toHaveBeenCalledWith(GlobalEvent.Node.Prop.InnerChange, expectedPartialPropsInfo); + expect(mockEmitPropChange).toHaveBeenCalledWith(expectedPartialPropsInfo); + + propInstance.unset(); + expect(mockEmitChange).toHaveBeenCalledTimes(1); + }); +}); From ed7befbff01d174a0335f0a1832fd9e313e308ea Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 30 Jan 2024 10:22:43 +0800 Subject: [PATCH 455/469] feat(context-menu): prevent event bubbling when "menus" is empty --- packages/shell/src/components/context-menu.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx index ccd910efc4..8c7ab446ba 100644 --- a/packages/shell/src/components/context-menu.tsx +++ b/packages/shell/src/components/context-menu.tsx @@ -34,7 +34,7 @@ export function ContextMenu({ children, menus, pluginContext }: { ); } - if (!menus || !menus.length) { + if (!menus) { return ( <>{ children }</> ); @@ -53,6 +53,9 @@ export function ContextMenu({ children, menus, pluginContext }: { } ContextMenu.create = (pluginContext: IPublicModelPluginContext, menus: IPublicTypeContextMenuAction[], event: MouseEvent) => { + event.preventDefault(); + event.stopPropagation(); + const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, { pluginContext, }), { From 80bb7102b65ccfc24399e372cff5f3fbaf8258a4 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 30 Jan 2024 14:19:30 +0800 Subject: [PATCH 456/469] feat(command): update default commands --- .../src/inner-plugins/default-command.ts | 44 ++++++++++++++----- packages/types/src/shell/api/command.ts | 4 +- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/packages/engine/src/inner-plugins/default-command.ts b/packages/engine/src/inner-plugins/default-command.ts index b2b899acb0..68d65c5001 100644 --- a/packages/engine/src/inner-plugins/default-command.ts +++ b/packages/engine/src/inner-plugins/default-command.ts @@ -10,10 +10,7 @@ const sampleNodeSchema: IPublicTypePropType = { value: [ { name: 'id', - propType: { - type: 'string', - isRequired: true, - }, + propType: 'string', }, { name: 'componentName', @@ -277,10 +274,12 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { handler: (param: { parentNodeId: string; nodeSchema: IPublicTypeNodeSchema; + index: number; }) => { const { parentNodeId, nodeSchema, + index, } = param; const { project } = ctx; const parentNode = project.currentDocument?.getNodeById(parentNodeId); @@ -296,7 +295,11 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { throw new Error('Invalid node.'); } - project.currentDocument?.insertNode(parentNode, nodeSchema); + if (index < 0 || index > (parentNode.children?.size || 0)) { + throw new Error(`Invalid index '${index}'.`); + } + + project.currentDocument?.insertNode(parentNode, nodeSchema, index); }, parameters: [ { @@ -309,6 +312,11 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { propType: nodeSchemaPropType, description: 'The node to be added.', }, + { + name: 'index', + propType: 'number', + description: 'The index of the node to be added.', + }, ], }); @@ -326,6 +334,14 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { index = 0, } = param; + if (!nodeId) { + throw new Error('Invalid node id.'); + } + + if (!targetNodeId) { + throw new Error('Invalid target node id.'); + } + const node = project.currentDocument?.getNodeById(nodeId); const targetNode = project.currentDocument?.getNodeById(targetNodeId); if (!node) { @@ -350,12 +366,18 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { parameters: [ { name: 'nodeId', - propType: 'string', + propType: { + type: 'string', + isRequired: true, + }, description: 'The id of the node to be moved.', }, { name: 'targetNodeId', - propType: 'string', + propType: { + type: 'string', + isRequired: true, + }, description: 'The id of the target node.', }, { @@ -393,8 +415,8 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { }); command.registerCommand({ - name: 'replace', - description: 'Replace a node with another node.', + name: 'update', + description: 'Update a node.', handler(param: { nodeId: string; nodeSchema: IPublicTypeNodeSchema; @@ -419,12 +441,12 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { { name: 'nodeId', propType: 'string', - description: 'The id of the node to be replaced.', + description: 'The id of the node to be updated.', }, { name: 'nodeSchema', propType: nodeSchemaPropType, - description: 'The node to replace.', + description: 'The node to be updated.', }, ], }); diff --git a/packages/types/src/shell/api/command.ts b/packages/types/src/shell/api/command.ts index 5cbfaa2e10..1f8425dcef 100644 --- a/packages/types/src/shell/api/command.ts +++ b/packages/types/src/shell/api/command.ts @@ -15,12 +15,12 @@ export interface IPublicApiCommand { /** * 通过名称和给定参数执行一个命令,会校验参数是否符合命令定义 */ - executeCommand(name: string, args: IPublicTypeCommandHandlerArgs): void; + executeCommand(name: string, args?: IPublicTypeCommandHandlerArgs): void; /** * 批量执行命令,执行完所有命令后再进行一次重绘,历史记录中只会记录一次 */ - batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[]): void; + batchExecuteCommand(commands: { name: string; args?: IPublicTypeCommandHandlerArgs }[]): void; /** * 列出所有已注册的命令 From 557a462b9f0e90e953862fd5fc7b528d4701a278 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 30 Jan 2024 14:34:53 +0800 Subject: [PATCH 457/469] fix(prop): emit event when delete prop --- .../designer/src/document/node/props/prop.ts | 1 + .../tests/document/node/props/prop.test.ts | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index fd9401314a..d70f0f56ec 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -570,6 +570,7 @@ export class Prop implements IProp, IPropParent { @action remove() { this.parent.delete(this); + this.unset(); } /** diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 8630376b68..ff4147a34a 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -34,11 +34,14 @@ const mockOwner = { }, isInited: true, emitPropChange: jest.fn(), + delete() {}, }; const mockPropsInst = { owner: mockOwner, + delete() {}, }; + mockPropsInst.props = mockPropsInst; describe('Prop 类测试', () => { @@ -595,6 +598,7 @@ describe('setValue with event', () => { }, }, emitPropChange: jest.fn(), + delete() {}, }; mockEventBusEmit = jest.spyOn(propInstance.owner.document.designer.editor.eventBus, 'emit'); mockEmitPropChange = jest.spyOn(propInstance.owner, 'emitPropChange'); @@ -665,4 +669,29 @@ describe('setValue with event', () => { propInstance.unset(); expect(mockEmitChange).toHaveBeenCalledTimes(1); }); + + // remove + it('should has event when remove call', () => { + const oldValue = propInstance._value; + + propInstance.remove(); + + const expectedPartialPropsInfo = expect.objectContaining({ + key: propInstance.key, + newValue: undefined, // You can specifically test only certain keys + oldValue, + }); + + expect(propInstance.getValue()).toEqual(undefined); + // expect(propInstance.type).toBe('unset'); + expect(mockEmitChange).toHaveBeenCalledWith({ + oldValue, + newValue: undefined, + }); + expect(mockEventBusEmit).toHaveBeenCalledWith(GlobalEvent.Node.Prop.InnerChange, expectedPartialPropsInfo); + expect(mockEmitPropChange).toHaveBeenCalledWith(expectedPartialPropsInfo); + + propInstance.remove(); + expect(mockEmitChange).toHaveBeenCalledTimes(1); + }); }); From 43921cea2d21321fa9366e34e27ea15649a7f944 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 30 Jan 2024 18:31:52 +0800 Subject: [PATCH 458/469] fix(workspace): fix workspace.plugins.xxx api is invalid --- packages/shell/src/api/workspace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index fd3e82fa90..f5bc79009f 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -90,7 +90,7 @@ export class Workspace implements IPublicApiWorkspace { } get plugins() { - return new Plugins(this[workspaceSymbol].plugins, true); + return new Plugins(this[workspaceSymbol].plugins, true).toProxy(); } get skeleton() { From de95b87b1e2ef1a7bd90b52e7f3cf8ca22a5f999 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 31 Jan 2024 18:53:23 +0800 Subject: [PATCH 459/469] feat: update ts defined --- packages/types/src/shell/api/workspace.ts | 5 ++++- packages/types/src/shell/type/command.ts | 18 +++--------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index 9e1080b31e..b6e7d84cb7 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -1,8 +1,9 @@ import { IPublicModelWindow } from '../model'; -import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; +import { IPublicApiPlugins, IPublicApiSkeleton, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; export interface IPublicApiWorkspace< Plugins = IPublicApiPlugins, + Skeleton = IPublicApiSkeleton, ModelWindow = IPublicModelWindow, Resource = IPublicModelResource, > { @@ -15,6 +16,8 @@ export interface IPublicApiWorkspace< plugins: Plugins; + skeleton: Skeleton; + /** 当前设计器的编辑窗口 */ windows: ModelWindow[]; diff --git a/packages/types/src/shell/type/command.ts b/packages/types/src/shell/type/command.ts index dd0420def1..0f301bd658 100644 --- a/packages/types/src/shell/type/command.ts +++ b/packages/types/src/shell/type/command.ts @@ -1,22 +1,10 @@ +import { IPublicTypePropType } from './prop-types'; + // 定义命令处理函数的参数类型 export interface IPublicTypeCommandHandlerArgs { [key: string]: any; } -// 定义复杂参数类型的接口 -export interface IPublicTypeCommandPropType { - - /** - * 参数基础类型 - */ - type: string; - - /** - * 参数是否必需(可选) - */ - isRequired?: boolean; -} - // 定义命令参数的接口 export interface IPublicTypeCommandParameter { @@ -28,7 +16,7 @@ export interface IPublicTypeCommandParameter { /** * 参数类型或详细类型描述 */ - propType: string | IPublicTypeCommandPropType; + propType: string | IPublicTypePropType; /** * 参数描述 From 24393211b404575bd81c62007e324ed1dfdca112 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 1 Feb 2024 12:23:31 +0800 Subject: [PATCH 460/469] refactor(plugin-command): add plugin-command package --- .github/workflows/test packages.yml | 18 ++++- packages/engine/src/engine-core.ts | 2 +- packages/plugin-command/README.md | 11 +++ .../__tests__/node-command.test.ts} | 8 +-- packages/plugin-command/build.json | 9 +++ packages/plugin-command/build.test.json | 19 +++++ packages/plugin-command/package.json | 34 +++++++++ .../plugin-command/src/history-command.ts | 43 ++++++++++++ packages/plugin-command/src/index.ts | 23 +++++++ .../src/node-command.ts} | 69 +++---------------- 10 files changed, 171 insertions(+), 65 deletions(-) create mode 100644 packages/plugin-command/README.md rename packages/{engine/tests/inner-plugins/default-command.test.ts => plugin-command/__tests__/node-command.test.ts} (97%) create mode 100644 packages/plugin-command/build.json create mode 100644 packages/plugin-command/build.test.json create mode 100644 packages/plugin-command/package.json create mode 100644 packages/plugin-command/src/history-command.ts create mode 100644 packages/plugin-command/src/index.ts rename packages/{engine/src/inner-plugins/default-command.ts => plugin-command/src/node-command.ts} (88%) diff --git a/.github/workflows/test packages.yml b/.github/workflows/test packages.yml index abb2973708..573a1ade01 100644 --- a/.github/workflows/test packages.yml +++ b/.github/workflows/test packages.yml @@ -121,4 +121,20 @@ jobs: run: npm i && npm run setup:skip-build - name: test - run: cd packages/editor-core && npm test \ No newline at end of file + run: cd packages/editor-core && npm test + + test-plugin-command + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v2 + + - uses: actions/setup-node@v2 + with: + node-version: '14' + + - name: install + run: npm i && npm run setup:skip-build + + - name: test + run: cd packages/plugin-command && npm test \ No newline at end of file diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 778438a3d4..5a2cbbc656 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -66,7 +66,7 @@ import { defaultPanelRegistry } from './inner-plugins/default-panel-registry'; import { shellModelFactory } from './modules/shell-model-factory'; import { builtinHotkey } from './inner-plugins/builtin-hotkey'; import { defaultContextMenu } from './inner-plugins/default-context-menu'; -import { defaultCommand } from './inner-plugins/default-command'; +import { defaultCommand } from '@alilc/lowcode-plugin-command'; import { OutlinePlugin } from '@alilc/lowcode-plugin-outline-pane'; export * from './modules/skeleton-types'; diff --git a/packages/plugin-command/README.md b/packages/plugin-command/README.md new file mode 100644 index 0000000000..8476b47e55 --- /dev/null +++ b/packages/plugin-command/README.md @@ -0,0 +1,11 @@ +# `@alilc/plugin-command` + +> TODO: description + +## Usage + +``` +const pluginCommand = require('@alilc/plugin-command'); + +// TODO: DEMONSTRATE API +``` diff --git a/packages/engine/tests/inner-plugins/default-command.test.ts b/packages/plugin-command/__tests__/node-command.test.ts similarity index 97% rename from packages/engine/tests/inner-plugins/default-command.test.ts rename to packages/plugin-command/__tests__/node-command.test.ts index 0e28c642b8..2e9d21b35e 100644 --- a/packages/engine/tests/inner-plugins/default-command.test.ts +++ b/packages/plugin-command/__tests__/node-command.test.ts @@ -1,5 +1,5 @@ import { checkPropTypes } from '@alilc/lowcode-utils/src/check-prop-types'; -import { nodeSchemaPropType } from '../../src/inner-plugins/default-command'; +import { nodeSchemaPropType } from '../src/node-command'; describe('nodeSchemaPropType', () => { const componentName = 'NodeComponent'; @@ -10,8 +10,8 @@ describe('nodeSchemaPropType', () => { const invalidId = 123; // Not a string expect(checkPropTypes(validId, 'id', getPropType('id'), componentName)).toBe(true); expect(checkPropTypes(invalidId, 'id', getPropType('id'), componentName)).toBe(false); - // isRequired - expect(checkPropTypes(undefined, 'id', getPropType('id'), componentName)).toBe(false); + // is not required + expect(checkPropTypes(undefined, 'id', getPropType('id'), componentName)).toBe(true); }); it('should validate the componentName as a string', () => { @@ -71,7 +71,7 @@ describe('nodeSchemaPropType', () => { const invalidLoop = { type: 'JSExpression', value: 123 }; // Not a string expect(checkPropTypes(validLoop, 'loop', getPropType('loop'), componentName)).toBe(true); expect(checkPropTypes(invalidLoop, 'loop', getPropType('loop'), componentName)).toBe(false); - }) + }); it('should validate the loopArgs as an array', () => { const validLoopArgs = ['item']; diff --git a/packages/plugin-command/build.json b/packages/plugin-command/build.json new file mode 100644 index 0000000000..d0aec10385 --- /dev/null +++ b/packages/plugin-command/build.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + "@alilc/build-plugin-lce", + "build-plugin-fusion", + ["build-plugin-moment-locales", { + "locales": ["zh-cn"] + }] + ] +} diff --git a/packages/plugin-command/build.test.json b/packages/plugin-command/build.test.json new file mode 100644 index 0000000000..9596d43e79 --- /dev/null +++ b/packages/plugin-command/build.test.json @@ -0,0 +1,19 @@ +{ + "plugins": [ + [ + "@alilc/build-plugin-lce", + { + "filename": "editor-preset-vision", + "library": "LowcodeEditor", + "libraryTarget": "umd", + "externals": { + "react": "var window.React", + "react-dom": "var window.ReactDOM", + "prop-types": "var window.PropTypes", + "rax": "var window.Rax" + } + } + ], + "@alilc/lowcode-test-mate/plugin/index.ts" + ] +} diff --git a/packages/plugin-command/package.json b/packages/plugin-command/package.json new file mode 100644 index 0000000000..3c84e265ec --- /dev/null +++ b/packages/plugin-command/package.json @@ -0,0 +1,34 @@ +{ + "name": "@alilc/lowcode-plugin-command", + "version": "1.3.1", + "description": "> TODO: description", + "author": "liujuping <liujup@foxmail.com>", + "homepage": "https://github.com/alibaba/lowcode-engine#readme", + "license": "ISC", + "main": "lib/plugin-command.js", + "directories": { + "lib": "lib", + "test": "__tests__" + }, + "files": [ + "lib" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/alibaba/lowcode-engine.git" + }, + "scripts": { + "test": "build-scripts test --config build.test.json --jest-passWithNoTests", + "build": "build-scripts build" + }, + "bugs": { + "url": "https://github.com/alibaba/lowcode-engine/issues" + }, + "dependencies": { + "@alilc/lowcode-types": "^1.3.1", + "@alilc/lowcode-utils": "^1.3.1" + } +} diff --git a/packages/plugin-command/src/history-command.ts b/packages/plugin-command/src/history-command.ts new file mode 100644 index 0000000000..ea7e491bce --- /dev/null +++ b/packages/plugin-command/src/history-command.ts @@ -0,0 +1,43 @@ +import { IPublicModelPluginContext, IPublicTypePlugin } from '@alilc/lowcode-types'; + +export const historyCommand: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => { + const { command, project } = ctx; + return { + init() { + command.registerCommand({ + name: 'undo', + description: 'Undo the last operation.', + handler: () => { + const state = project.currentDocument?.history.getState() || 0; + const enable = !!(state & 1); + if (!enable) { + throw new Error('Can not undo.'); + } + project.currentDocument?.history.back(); + }, + }); + + command.registerCommand({ + name: 'redo', + description: 'Redo the last operation.', + handler: () => { + const state = project.currentDocument?.history.getState() || 0; + const enable = !!(state & 2); + if (!enable) { + throw new Error('Can not redo.'); + } + project.currentDocument?.history.forward(); + }, + }); + }, + destroy() { + command.unregisterCommand('history:undo'); + command.unregisterCommand('history:redo'); + }, + }; +}; + +historyCommand.pluginName = '___history_command___'; +historyCommand.meta = { + commandScope: 'history', +}; diff --git a/packages/plugin-command/src/index.ts b/packages/plugin-command/src/index.ts new file mode 100644 index 0000000000..8e5d64ebcf --- /dev/null +++ b/packages/plugin-command/src/index.ts @@ -0,0 +1,23 @@ +import { IPublicModelPluginContext, IPublicTypePlugin } from '@alilc/lowcode-types'; +import { nodeCommand } from './node-command'; +import { historyCommand } from './history-command'; + +export const defaultCommand: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => { + const { plugins } = ctx; + + return { + async init() { + await plugins.register(nodeCommand, {}, { autoInit: true }); + await plugins.register(historyCommand, {}, { autoInit: true }); + }, + destroy() { + plugins.delete(nodeCommand.pluginName); + plugins.delete(historyCommand.pluginName); + }, + }; +}; + +defaultCommand.pluginName = '___default_command___'; +defaultCommand.meta = { + commandScope: 'common', +}; diff --git a/packages/engine/src/inner-plugins/default-command.ts b/packages/plugin-command/src/node-command.ts similarity index 88% rename from packages/engine/src/inner-plugins/default-command.ts rename to packages/plugin-command/src/node-command.ts index 68d65c5001..eeda1d1688 100644 --- a/packages/engine/src/inner-plugins/default-command.ts +++ b/packages/plugin-command/src/node-command.ts @@ -1,8 +1,4 @@ -import { - IPublicModelPluginContext, - IPublicTypeNodeSchema, - IPublicTypePropType, -} from '@alilc/lowcode-types'; +import { IPublicModelPluginContext, IPublicTypeNodeSchema, IPublicTypePlugin, IPublicTypePropType } from '@alilc/lowcode-types'; import { isNodeSchema } from '@alilc/lowcode-utils'; const sampleNodeSchema: IPublicTypePropType = { @@ -226,45 +222,7 @@ export const nodeSchemaPropType: IPublicTypePropType = { ], }; -export const historyCommand = (ctx: IPublicModelPluginContext) => { - const { command, project } = ctx; - return { - init() { - command.registerCommand({ - name: 'undo', - description: 'Undo the last operation.', - handler: () => { - const state = project.currentDocument?.history.getState() || 0; - const enable = !!(state & 1); - if (!enable) { - throw new Error('Can not undo.'); - } - project.currentDocument?.history.back(); - }, - }); - - command.registerCommand({ - name: 'redo', - description: 'Redo the last operation.', - handler: () => { - const state = project.currentDocument?.history.getState() || 0; - const enable = !!(state & 2); - if (!enable) { - throw new Error('Can not redo.'); - } - project.currentDocument?.history.forward(); - }, - }); - }, - }; -}; - -historyCommand.pluginName = '___history_command___'; -historyCommand.meta = { - commandScope: 'history', -}; - -export const nodeCommand = (ctx: IPublicModelPluginContext) => { +export const nodeCommand: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => { const { command, project } = ctx; return { init() { @@ -521,6 +479,14 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { ], }); }, + destroy() { + command.unregisterCommand('node:add'); + command.unregisterCommand('node:move'); + command.unregisterCommand('node:remove'); + command.unregisterCommand('node:update'); + command.unregisterCommand('node:updateProps'); + command.unregisterCommand('node:removeProps'); + }, }; }; @@ -529,18 +495,3 @@ nodeCommand.meta = { commandScope: 'node', }; -export const defaultCommand = (ctx: IPublicModelPluginContext) => { - const { plugins } = ctx; - plugins.register(nodeCommand); - plugins.register(historyCommand); - - return { - init() { - }, - }; -}; - -defaultCommand.pluginName = '___default_command___'; -defaultCommand.meta = { - commandScope: 'common', -}; From 5b46d96df77d738249b0170bad222eedc29a1802 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 1 Feb 2024 14:41:55 +0800 Subject: [PATCH 461/469] refactor(plugin-command): add plugin-command package --- scripts/build.sh | 1 + scripts/sync.sh | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/build.sh b/scripts/build.sh index 828bb16d99..751e9094fe 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -10,6 +10,7 @@ lerna run build \ --scope @alilc/lowcode-editor-skeleton \ --scope @alilc/lowcode-designer \ --scope @alilc/lowcode-plugin-designer \ + --scope @alilc/lowcode-plugin-command \ --scope @alilc/lowcode-plugin-outline-pane \ --scope @alilc/lowcode-react-renderer \ --scope @alilc/lowcode-react-simulator-renderer \ diff --git a/scripts/sync.sh b/scripts/sync.sh index e9840eeca6..3edac03845 100755 --- a/scripts/sync.sh +++ b/scripts/sync.sh @@ -13,4 +13,5 @@ tnpm sync @alilc/lowcode-renderer-core tnpm sync @alilc/lowcode-react-renderer tnpm sync @alilc/lowcode-react-simulator-renderer tnpm sync @alilc/lowcode-engine -tnpm sync @alilc/lowcode-workspace \ No newline at end of file +tnpm sync @alilc/lowcode-workspace +tnpm sync @alilc/lowcode-plugin-command \ No newline at end of file From 5657d9c084899e91077008c491284248776ad7d8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 1 Feb 2024 14:49:25 +0800 Subject: [PATCH 462/469] feat: update test package.yaml --- .github/workflows/test packages.yml | 2 +- packages/workspace/src/context/base-context.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test packages.yml b/.github/workflows/test packages.yml index 573a1ade01..45fa665465 100644 --- a/.github/workflows/test packages.yml +++ b/.github/workflows/test packages.yml @@ -123,7 +123,7 @@ jobs: - name: test run: cd packages/editor-core && npm test - test-plugin-command + test-plugin-command: runs-on: ubuntu-latest steps: - name: checkout diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index db33597aea..445677a618 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -96,7 +96,7 @@ export class BasicContext implements IBasicContext { designer: IDesigner; registerInnerPlugins: () => Promise<void>; innerSetters: InnerSetters; - innerSkeleton: InnerSkeleton; + innerSkeleton: ISkeleton; innerHotkey: IHotKey; innerPlugins: ILowCodePluginManager; canvas: IPublicApiCanvas; From 76b2a0504959972b38d75fb97101a0ebe2426cc9 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 1 Feb 2024 16:01:36 +0800 Subject: [PATCH 463/469] docs(command): add command api docs --- docs/docs/api/canvas.md | 2 +- docs/docs/api/command.md | 101 ++++++++++++++++++++++++++++ docs/docs/api/common.md | 2 +- docs/docs/api/commonUI.md | 2 +- docs/docs/api/config.md | 2 +- docs/docs/api/configOptions.md | 2 +- docs/docs/api/event.md | 2 +- docs/docs/api/hotkey.md | 2 +- docs/docs/api/init.md | 2 +- docs/docs/api/logger.md | 2 +- docs/docs/api/material.md | 2 +- docs/docs/api/model/_category_.json | 2 +- docs/docs/api/plugins.md | 2 +- docs/docs/api/project.md | 2 +- docs/docs/api/setters.md | 2 +- docs/docs/api/simulatorHost.md | 2 +- docs/docs/api/skeleton.md | 2 +- docs/docs/api/workspace.md | 2 +- 18 files changed, 118 insertions(+), 17 deletions(-) create mode 100644 docs/docs/api/command.md diff --git a/docs/docs/api/canvas.md b/docs/docs/api/canvas.md index 582f2354b5..865b9ac311 100644 --- a/docs/docs/api/canvas.md +++ b/docs/docs/api/canvas.md @@ -1,6 +1,6 @@ --- title: canvas - 画布 API -sidebar_position: 12 +sidebar_position: 10 --- > **@types** [IPublicApiCanvas](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/canvas.ts)<br/> diff --git a/docs/docs/api/command.md b/docs/docs/api/command.md new file mode 100644 index 0000000000..fc36c8ad89 --- /dev/null +++ b/docs/docs/api/command.md @@ -0,0 +1,101 @@ +--- +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; +``` diff --git a/docs/docs/api/common.md b/docs/docs/api/common.md index 1a70436adf..c278bf2ad8 100644 --- a/docs/docs/api/common.md +++ b/docs/docs/api/common.md @@ -1,6 +1,6 @@ --- title: common - 通用 API -sidebar_position: 11 +sidebar_position: 10 --- > **@types** [IPublicApiCommon](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/common.ts)<br/> diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md index c0bbda588e..45640051f2 100644 --- a/docs/docs/api/commonUI.md +++ b/docs/docs/api/commonUI.md @@ -1,6 +1,6 @@ --- title: commonUI - UI 组件库 -sidebar_position: 11 +sidebar_position: 10 --- ## 简介 diff --git a/docs/docs/api/config.md b/docs/docs/api/config.md index fb631a945f..414cfc979f 100644 --- a/docs/docs/api/config.md +++ b/docs/docs/api/config.md @@ -1,6 +1,6 @@ --- title: config - 配置 API -sidebar_position: 8 +sidebar_position: 5 --- > **@types** [IPublicModelEngineConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/engine-config.ts)<br/> diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md index 67d2fae2c1..5d6e8d7abb 100644 --- a/docs/docs/api/configOptions.md +++ b/docs/docs/api/configOptions.md @@ -1,6 +1,6 @@ --- title: config options - 配置列表 -sidebar_position: 13 +sidebar_position: 5 --- > **@types** [IPublicTypeEngineOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/engine-options.ts)<br/> diff --git a/docs/docs/api/event.md b/docs/docs/api/event.md index 0919b41fd2..c2e86f7106 100644 --- a/docs/docs/api/event.md +++ b/docs/docs/api/event.md @@ -1,6 +1,6 @@ --- title: event - 事件 API -sidebar_position: 7 +sidebar_position: 10 --- > **@types** [IPublicApiEvent](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/event.ts)<br/> diff --git a/docs/docs/api/hotkey.md b/docs/docs/api/hotkey.md index a244b94c27..be6a3033d0 100644 --- a/docs/docs/api/hotkey.md +++ b/docs/docs/api/hotkey.md @@ -1,6 +1,6 @@ --- title: hotkey - 快捷键 API -sidebar_position: 5 +sidebar_position: 10 --- > **@types** [IPublicApiHotkey](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/hotkey.ts)<br/> diff --git a/docs/docs/api/init.md b/docs/docs/api/init.md index 55b116a579..dd84d9c00f 100644 --- a/docs/docs/api/init.md +++ b/docs/docs/api/init.md @@ -1,6 +1,6 @@ --- title: init - 初始化 API -sidebar_position: 10 +sidebar_position: 0 --- > **@since** v1.0.0 diff --git a/docs/docs/api/logger.md b/docs/docs/api/logger.md index 7493f34dc2..38d986258b 100644 --- a/docs/docs/api/logger.md +++ b/docs/docs/api/logger.md @@ -1,6 +1,6 @@ --- title: logger - 日志 API -sidebar_position: 9 +sidebar_position: 10 --- > **@types** [IPublicApiLogger](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/logger.ts)<br/> diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index b6ef070b2c..0e09441275 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -1,6 +1,6 @@ --- title: material - 物料 API -sidebar_position: 2 +sidebar_position: 10 --- > **@types** [IPublicApiMaterial](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/material.ts)<br/> diff --git a/docs/docs/api/model/_category_.json b/docs/docs/api/model/_category_.json index 5b1f74b36f..3afc4f79b5 100644 --- a/docs/docs/api/model/_category_.json +++ b/docs/docs/api/model/_category_.json @@ -1,6 +1,6 @@ { "label": "模型定义 Models", - "position": 14, + "position": 100, "collapsed": false, "collapsible": true } diff --git a/docs/docs/api/plugins.md b/docs/docs/api/plugins.md index e35411d3a8..df025f49e9 100644 --- a/docs/docs/api/plugins.md +++ b/docs/docs/api/plugins.md @@ -1,6 +1,6 @@ --- title: plugins - 插件 API -sidebar_position: 4 +sidebar_position: 2 --- > **@types** [IPublicApiPlugins](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/plugins.ts)<br/> > **@since** v1.0.0 diff --git a/docs/docs/api/project.md b/docs/docs/api/project.md index 49d3193858..54bd1474cf 100644 --- a/docs/docs/api/project.md +++ b/docs/docs/api/project.md @@ -1,6 +1,6 @@ --- title: project - 模型 API -sidebar_position: 3 +sidebar_position: 10 --- ## 模块简介 diff --git a/docs/docs/api/setters.md b/docs/docs/api/setters.md index cc7b6d429c..0d3435b3d3 100644 --- a/docs/docs/api/setters.md +++ b/docs/docs/api/setters.md @@ -1,6 +1,6 @@ --- title: setters - 设置器 API -sidebar_position: 6 +sidebar_position: 10 --- > **@types** [IPublicApiSetters](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/setters.ts)<br/> > **@since** v1.0.0 diff --git a/docs/docs/api/simulatorHost.md b/docs/docs/api/simulatorHost.md index c7f739f6b4..70eaca0220 100644 --- a/docs/docs/api/simulatorHost.md +++ b/docs/docs/api/simulatorHost.md @@ -1,6 +1,6 @@ --- title: simulatorHost - 模拟器 API -sidebar_position: 3 +sidebar_position: 10 --- > **@types** [IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)<br/> > **@since** v1.0.0 diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index 0713546e19..396fad9e9e 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -1,6 +1,6 @@ --- title: skeleton - 面板 API -sidebar_position: 1 +sidebar_position: 10 --- > **@types** [IPublicApiSkeleton](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/skeleton.ts)<br/> > **@since** v1.0.0 diff --git a/docs/docs/api/workspace.md b/docs/docs/api/workspace.md index 6d0714ae09..74f7d6950f 100644 --- a/docs/docs/api/workspace.md +++ b/docs/docs/api/workspace.md @@ -1,6 +1,6 @@ --- title: workspace - 应用级 API -sidebar_position: 12 +sidebar_position: 10 --- > **[@experimental](./#experimental)**<br/> From 501ad872c476faacf2bba8c25963b189e1a7cac3 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 1 Feb 2024 08:17:01 +0000 Subject: [PATCH 464/469] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index ce6a969c1f..7facd9db8b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.30", + "version": "1.2.31", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 19eb91725952d34fc90ba470fc639ad1fe60b102 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 1 Feb 2024 15:47:26 +0800 Subject: [PATCH 465/469] refactor(plugin-command): add plugin-command package --- packages/engine/package.json | 1 + packages/engine/src/engine-core.ts | 6 +++--- packages/plugin-command/jest.config.js | 22 ++++++++++++++++++++++ packages/plugin-command/package.json | 9 +++++++-- packages/plugin-command/src/index.ts | 8 +++++--- 5 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 packages/plugin-command/jest.config.js diff --git a/packages/engine/package.json b/packages/engine/package.json index 4b622eaa4b..fb2b42fd09 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -28,6 +28,7 @@ "@alilc/lowcode-shell": "1.3.1", "@alilc/lowcode-utils": "1.3.1", "@alilc/lowcode-workspace": "1.3.1", + "@alilc/lowcode-plugin-command": "1.3.1", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 5a2cbbc656..4dffa628bd 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -66,7 +66,7 @@ import { defaultPanelRegistry } from './inner-plugins/default-panel-registry'; import { shellModelFactory } from './modules/shell-model-factory'; import { builtinHotkey } from './inner-plugins/builtin-hotkey'; import { defaultContextMenu } from './inner-plugins/default-context-menu'; -import { defaultCommand } from '@alilc/lowcode-plugin-command'; +import { CommandPlugin } from '@alilc/lowcode-plugin-command'; import { OutlinePlugin } from '@alilc/lowcode-plugin-outline-pane'; export * from './modules/skeleton-types'; @@ -84,7 +84,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins await plugins.register(builtinHotkey); await plugins.register(registerDefaults, {}, { autoInit: true }); await plugins.register(defaultContextMenu); - await plugins.register(defaultCommand, {}); + await plugins.register(CommandPlugin, {}); return () => { plugins.delete(OutlinePlugin.pluginName); @@ -94,7 +94,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins plugins.delete(builtinHotkey.pluginName); plugins.delete(registerDefaults.pluginName); plugins.delete(defaultContextMenu.pluginName); - plugins.delete(defaultCommand.pluginName); + plugins.delete(CommandPlugin.pluginName); }; } diff --git a/packages/plugin-command/jest.config.js b/packages/plugin-command/jest.config.js new file mode 100644 index 0000000000..822a526b7d --- /dev/null +++ b/packages/plugin-command/jest.config.js @@ -0,0 +1,22 @@ +const fs = require('fs'); +const { join } = require('path'); +const esModules = [].join('|'); +const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.')); + +const jestConfig = { + transformIgnorePatterns: [ + `/node_modules/(?!${esModules})/`, + ], + moduleFileExtensions: ['ts', 'tsx', 'js', 'json'], + collectCoverage: true, + collectCoverageFrom: [ + 'src/**/*.ts', + 'src/**/*.tsx', + ], +}; + +// 只对本仓库内的 pkg 做 mapping +jestConfig.moduleNameMapper = {}; +jestConfig.moduleNameMapper[`^@alilc/lowcode\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src'; + +module.exports = jestConfig; \ No newline at end of file diff --git a/packages/plugin-command/package.json b/packages/plugin-command/package.json index 3c84e265ec..5cdd99660f 100644 --- a/packages/plugin-command/package.json +++ b/packages/plugin-command/package.json @@ -5,13 +5,15 @@ "author": "liujuping <liujup@foxmail.com>", "homepage": "https://github.com/alibaba/lowcode-engine#readme", "license": "ISC", - "main": "lib/plugin-command.js", + "main": "lib/index.js", + "module": "es/index.js", "directories": { "lib": "lib", "test": "__tests__" }, "files": [ - "lib" + "lib", + "es" ], "publishConfig": { "access": "public" @@ -30,5 +32,8 @@ "dependencies": { "@alilc/lowcode-types": "^1.3.1", "@alilc/lowcode-utils": "^1.3.1" + }, + "devDependencies": { + "@alib/build-scripts": "^0.1.18" } } diff --git a/packages/plugin-command/src/index.ts b/packages/plugin-command/src/index.ts index 8e5d64ebcf..fa6f32b32d 100644 --- a/packages/plugin-command/src/index.ts +++ b/packages/plugin-command/src/index.ts @@ -2,7 +2,7 @@ import { IPublicModelPluginContext, IPublicTypePlugin } from '@alilc/lowcode-typ import { nodeCommand } from './node-command'; import { historyCommand } from './history-command'; -export const defaultCommand: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => { +export const CommandPlugin: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => { const { plugins } = ctx; return { @@ -17,7 +17,9 @@ export const defaultCommand: IPublicTypePlugin = (ctx: IPublicModelPluginContext }; }; -defaultCommand.pluginName = '___default_command___'; -defaultCommand.meta = { +CommandPlugin.pluginName = '___default_command___'; +CommandPlugin.meta = { commandScope: 'common', }; + +export default CommandPlugin; \ No newline at end of file From 86d50e094628602347e09864850d23b49153bb89 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 2 Feb 2024 17:45:25 +0800 Subject: [PATCH 466/469] fix(setter): params is not shell SettingField --- packages/designer/src/designer/setting/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/designer/src/designer/setting/utils.ts b/packages/designer/src/designer/setting/utils.ts index 1e061f20ae..75ed1dfc1a 100644 --- a/packages/designer/src/designer/setting/utils.ts +++ b/packages/designer/src/designer/setting/utils.ts @@ -70,7 +70,7 @@ export class Transducer { } if (isDynamicSetter(setter) && isDynamic) { try { - setter = setter.call(context, context); + setter = setter.call(context.internalToShellField(), context.internalToShellField()); } catch (e) { console.error(e); } } From 44beb2a25ad57cbc4cc2c88c577c5467542a9fd4 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 7 Feb 2024 12:52:56 +0800 Subject: [PATCH 467/469] fix(workspace): fix workspace editorView is undefined --- packages/shell/src/api/material.ts | 8 +++++++- packages/shell/src/model/window.ts | 4 ++-- packages/workspace/src/window.ts | 25 ++++++++++++++++--------- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/packages/shell/src/api/material.ts b/packages/shell/src/api/material.ts index f0c37d8a4d..284b88fbbf 100644 --- a/packages/shell/src/api/material.ts +++ b/packages/shell/src/api/material.ts @@ -3,7 +3,7 @@ import { IDesigner, isComponentMeta, } from '@alilc/lowcode-designer'; -import { IPublicTypeAssetsJson } from '@alilc/lowcode-utils'; +import { IPublicTypeAssetsJson, getLogger } from '@alilc/lowcode-utils'; import { IPublicTypeComponentAction, IPublicTypeComponentMetadata, @@ -21,6 +21,8 @@ import { editorSymbol, designerSymbol } from '../symbols'; import { ComponentMeta as ShellComponentMeta } from '../model'; import { ComponentType } from 'react'; +const logger = getLogger({ level: 'warn', bizName: 'shell-material' }); + const innerEditorSymbol = Symbol('editor'); export class Material implements IPublicApiMaterial { private readonly [innerEditorSymbol]: IPublicModelEditor; @@ -31,6 +33,10 @@ export class Material implements IPublicApiMaterial { } const workspace: InnerWorkspace = globalContext.get('workspace'); if (workspace.isActive) { + if (!workspace.window.editor) { + logger.error('Material api 调用时机出现问题,请检查'); + return this[innerEditorSymbol]; + } return workspace.window.editor; } diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index 2b5e0dd8c3..1bc84e661c 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -48,8 +48,8 @@ export class Window implements IPublicModelWindow { } get currentEditorView() { - if (this[windowSymbol].editorView) { - return new EditorView(this[windowSymbol].editorView).toProxy() as any; + if (this[windowSymbol]._editorView) { + return new EditorView(this[windowSymbol]._editorView).toProxy() as any; } return null; } diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index ce5aab4142..cd64a9b112 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -17,7 +17,7 @@ export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'chan editorViews: Map<string, IViewContext>; - editorView: IViewContext; + _editorView: IViewContext; changeViewName: (name: string, ignoreEmit?: boolean) => void; @@ -54,7 +54,7 @@ export class EditorWindow implements IEditorWindow { url: string | undefined; - @obx.ref editorView: Context; + @obx.ref _editorView: Context; @obx editorViews: Map<string, Context> = new Map<string, Context>(); @@ -62,6 +62,13 @@ export class EditorWindow implements IEditorWindow { sleep: boolean | undefined; + get editorView() { + if (!this._editorView) { + return this.editorViews.values().next().value; + } + return this._editorView; + } + constructor(readonly resource: IResource, readonly workspace: IWorkspace, private config: IWindowCOnfig) { makeObservable(this); this.title = config.title; @@ -75,10 +82,10 @@ export class EditorWindow implements IEditorWindow { updateState(state: WINDOW_STATE): void { switch (state) { case WINDOW_STATE.active: - this.editorView?.setActivate(true); + this._editorView?.setActivate(true); break; case WINDOW_STATE.inactive: - this.editorView?.setActivate(false); + this._editorView?.setActivate(false); break; case WINDOW_STATE.destroyed: break; @@ -146,7 +153,7 @@ export class EditorWindow implements IEditorWindow { for (let i = 0; i < editorViews.length; i++) { const name = editorViews[i].viewName; await this.initViewType(name); - if (!this.editorView) { + if (!this._editorView) { this.changeViewName(name); } } @@ -190,14 +197,14 @@ export class EditorWindow implements IEditorWindow { }; changeViewName = (name: string, ignoreEmit: boolean = true) => { - this.editorView?.setActivate(false); - this.editorView = this.editorViews.get(name)!; + this._editorView?.setActivate(false); + this._editorView = this.editorViews.get(name)!; - if (!this.editorView) { + if (!this._editorView) { return; } - this.editorView.setActivate(true); + this._editorView.setActivate(true); if (!ignoreEmit) { this.emitter.emit('window.change.view.type', name); From bd85ca3ca6adc89a5ed67644f1f14322e512db72 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 23 Feb 2024 01:51:23 +0000 Subject: [PATCH 468/469] chore(release): publish 1.3.2 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 20 +++++++++---------- packages/ignitor/package.json | 2 +- packages/plugin-command/package.json | 6 +++--- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/react-renderer/package.json | 4 ++-- .../react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 ++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 +++++------ 16 files changed, 61 insertions(+), 61 deletions(-) diff --git a/lerna.json b/lerna.json index 7de339c6cd..7fad993f66 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.3.1", + "version": "1.3.2", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index ec7c153c80..97256d3a21 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.3.1", + "version": "1.3.2", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.3.1", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-editor-core": "1.3.2", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 98644ad3d6..55f6d50c39 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.3.1", + "version": "1.3.2", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 7c14943552..63aab7e48b 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.3.1", + "version": "1.3.2", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.3.1", - "@alilc/lowcode-editor-core": "1.3.1", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", + "@alilc/lowcode-editor-core": "1.3.2", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index fb2b42fd09..23b3521213 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.3.1", + "version": "1.3.2", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,16 +19,16 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.3.1", - "@alilc/lowcode-editor-core": "1.3.1", - "@alilc/lowcode-editor-skeleton": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", + "@alilc/lowcode-editor-core": "1.3.2", + "@alilc/lowcode-editor-skeleton": "1.3.2", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.3.1", - "@alilc/lowcode-plugin-outline-pane": "1.3.1", - "@alilc/lowcode-shell": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", - "@alilc/lowcode-workspace": "1.3.1", - "@alilc/lowcode-plugin-command": "1.3.1", + "@alilc/lowcode-plugin-command": "1.3.2", + "@alilc/lowcode-plugin-designer": "1.3.2", + "@alilc/lowcode-plugin-outline-pane": "1.3.2", + "@alilc/lowcode-shell": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", + "@alilc/lowcode-workspace": "1.3.2", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index a32e30783f..0b109a7ad7 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.3.1", + "version": "1.3.2", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-command/package.json b/packages/plugin-command/package.json index 5cdd99660f..4f53e69e36 100644 --- a/packages/plugin-command/package.json +++ b/packages/plugin-command/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-command", - "version": "1.3.1", + "version": "1.3.2", "description": "> TODO: description", "author": "liujuping <liujup@foxmail.com>", "homepage": "https://github.com/alibaba/lowcode-engine#readme", @@ -30,8 +30,8 @@ "url": "https://github.com/alibaba/lowcode-engine/issues" }, "dependencies": { - "@alilc/lowcode-types": "^1.3.1", - "@alilc/lowcode-utils": "^1.3.1" + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2" }, "devDependencies": { "@alib/build-scripts": "^0.1.18" diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 9fb9a75655..ac25097c78 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.3.1", + "version": "1.3.2", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.3.1", - "@alilc/lowcode-editor-core": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", + "@alilc/lowcode-editor-core": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 1539ac6ae3..f50f71cbfe 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.3.1", + "version": "1.3.2", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index b041823e85..625801bc25 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.3.1", + "version": "1.3.2", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.3.1" + "@alilc/lowcode-renderer-core": "1.3.2" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 1361535099..3c3950a124 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.3.1", + "version": "1.3.2", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.3.1", - "@alilc/lowcode-react-renderer": "1.3.1", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", + "@alilc/lowcode-react-renderer": "1.3.2", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index dd48d361f1..199eac1cac 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.3.1", + "version": "1.3.2", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 87f71a5ee6..c2b62e2270 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.3.1", + "version": "1.3.2", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.3.1", - "@alilc/lowcode-editor-core": "1.3.1", - "@alilc/lowcode-editor-skeleton": "1.3.1", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", - "@alilc/lowcode-workspace": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", + "@alilc/lowcode-editor-core": "1.3.2", + "@alilc/lowcode-editor-skeleton": "1.3.2", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", + "@alilc/lowcode-workspace": "1.3.2", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 31dadb5ea0..5651d427d4 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.3.1", + "version": "1.3.2", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index cc363a7292..60605d81e7 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.3.1", + "version": "1.3.2", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-types": "1.3.2", "lodash": "^4.17.21", "mobx": "^6.3.0", "prop-types": "^15.8.1", diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 7af4a7159c..778b8167f8 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.3.1", + "version": "1.3.2", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.3.1", - "@alilc/lowcode-editor-core": "1.3.1", - "@alilc/lowcode-editor-skeleton": "1.3.1", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", + "@alilc/lowcode-editor-core": "1.3.2", + "@alilc/lowcode-editor-skeleton": "1.3.2", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 2892a01d298b73d483f34ec20fcf8334f1f8ea72 Mon Sep 17 00:00:00 2001 From: 1ncounter <1ncounter.100@gmail.com> Date: Tue, 11 Jun 2024 21:07:42 +0800 Subject: [PATCH 469/469] chore: update code owners --- .github/CODEOWNERS | 2 +- .github/workflows/publish engine.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1000fca053..670db7dfbd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,7 +2,7 @@ # These owners will be the default owners for everything in # the repo. Unless a later match takes precedence -* @liujuping @JackLian +* @liujuping @1ncounter /modules/material-parser @akirakai /modules/code-generator @qingniaotonghua diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index dcbf0547e7..ddbefcde55 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest if: >- contains(github.ref, 'refs/heads/release/') && - (github.actor == 'JackLian' || github.actor == 'liujuping') + (github.actor == '1ncounter' || github.actor == 'liujuping') steps: - uses: actions/checkout@v2 - name: Setup Node.js