From ea08173af0b40d1af90c0445328614c000696682 Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 9 Jan 2023 17:18:30 +0800 Subject: [PATCH 01/89] feat: added apis support resource tree in workspace mode --- docs/docs/api/index.md | 4 ++ docs/docs/api/model/plugin-instance.md | 2 +- docs/docs/api/model/resource-type.md | 26 ++++++++ docs/docs/api/model/resource.md | 36 ++++++++++ docs/docs/api/model/window.md | 17 ++++- docs/docs/api/plugins.md | 2 +- docs/docs/api/workspace.md | 66 ++++++++++++++++++- packages/shell/src/api/workspace.ts | 23 +++++-- packages/shell/src/model/index.ts | 4 +- packages/shell/src/model/resource-type.ts | 22 +++++++ packages/shell/src/model/resource.ts | 28 ++++++++ packages/shell/src/model/window.ts | 5 +- packages/shell/src/symbols.ts | 4 +- packages/types/src/shell/api/workspace.ts | 24 +++++-- packages/types/src/shell/model/index.ts | 4 +- .../types/src/shell/model/resource-type.ts | 7 ++ packages/types/src/shell/model/resource.ts | 12 ++++ packages/types/src/shell/model/window.ts | 10 ++- .../types/src/shell/type/resource-options.ts | 20 ++++-- packages/workspace/src/editor-view/context.ts | 4 +- .../workspace/src/editor-window/context.ts | 26 ++++---- packages/workspace/src/index.ts | 3 +- packages/workspace/src/resource-type.ts | 53 +++++++++++++++ packages/workspace/src/resource.ts | 54 +++++---------- packages/workspace/src/workspace.ts | 64 ++++++++++++------ 25 files changed, 419 insertions(+), 101 deletions(-) create mode 100644 docs/docs/api/model/resource-type.md create mode 100644 docs/docs/api/model/resource.md create mode 100644 packages/shell/src/model/resource-type.ts create mode 100644 packages/shell/src/model/resource.ts create mode 100644 packages/types/src/shell/model/resource-type.ts create mode 100644 packages/types/src/shell/model/resource.ts create mode 100644 packages/workspace/src/resource-type.ts diff --git a/docs/docs/api/index.md b/docs/docs/api/index.md index 2bd735c84..993c39e88 100644 --- a/docs/docs/api/index.md +++ b/docs/docs/api/index.md @@ -44,3 +44,7 @@ sidebar_position: 0 2. 事件(events)的命名格式为:on[Will|Did]VerbNoun?,参考 [https://code.visualstudio.com/api/references/vscode-api#events](https://code.visualstudio.com/api/references/vscode-api#events) 3. 基于 Disposable 模式,对于事件的绑定、快捷键的绑定函数,返回值则是解绑函数 4. 对于属性的导出,统一用 .xxx 的 getter 模式,(尽量)不使用 .getXxx() + +## experimental + +说明此模块处于公测阶段, API 可能会发生改变. \ No newline at end of file diff --git a/docs/docs/api/model/plugin-instance.md b/docs/docs/api/model/plugin-instance.md index 9ca872a4f..8f764c68b 100644 --- a/docs/docs/api/model/plugin-instance.md +++ b/docs/docs/api/model/plugin-instance.md @@ -1,5 +1,5 @@ --- -title: plugin-instance +title: PluginInstance sidebar_position: 12 --- diff --git a/docs/docs/api/model/resource-type.md b/docs/docs/api/model/resource-type.md new file mode 100644 index 000000000..327788ce3 --- /dev/null +++ b/docs/docs/api/model/resource-type.md @@ -0,0 +1,26 @@ +--- +title: ResourceType +sidebar_position: 12 +--- + +> **[@experimental](./#experimental)**
+> **@types** [IPublicModelWindow](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/resource-type.ts)
+> **@since** v1.1.0 + +## 变量 + +### description + +资源描述 + +`@type {string}` + +### icon + +资源 icon + +`@type {ReactElement}` + +### name + +`@type {string}` diff --git a/docs/docs/api/model/resource.md b/docs/docs/api/model/resource.md new file mode 100644 index 000000000..fb3e8a6d8 --- /dev/null +++ b/docs/docs/api/model/resource.md @@ -0,0 +1,36 @@ +--- +title: Resource +sidebar_position: 12 +--- + +> **[@experimental](./#experimental)**
+> **@types** [IPublicModelWindow](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/resource.ts)
+> **@since** v1.1.0 + +## 变量 + +### title + +资源标题 + +`@type {string}` + +### icon + +资源 icon + +`@type {ReactElement}` + +### options + +资源配置信息 + +`@type {Object}` + +### resourceType + +资源所属的资源类型 + +`@type {IPublicModelResourceType}` + +关联模型 [IPublicModelResourceType](./resource-type) diff --git a/docs/docs/api/model/window.md b/docs/docs/api/model/window.md index 6a5413883..9d96f20a8 100644 --- a/docs/docs/api/model/window.md +++ b/docs/docs/api/model/window.md @@ -3,6 +3,7 @@ title: Window sidebar_position: 12 --- +> **[@experimental](./#experimental)**
> **@types** [IPublicModelWindow](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/window.ts)
> **@since** v1.1.0 @@ -17,13 +18,25 @@ sidebar_position: 12 窗口唯一 id +`@type {string}` + ### title 窗口标题 -### resourceName +`@type {string}` -窗口资源名字 +### icon + +`@type {ReactElement}` + +### resourceType + +窗口资源类型 + +`@type {IPublicModelResourceType}` + +关联模型 [IPublicModelResourceType](./resource-type) ## 方法签名 diff --git a/docs/docs/api/plugins.md b/docs/docs/api/plugins.md index 1b20bdabe..9b1993b10 100644 --- a/docs/docs/api/plugins.md +++ b/docs/docs/api/plugins.md @@ -222,7 +222,7 @@ your-plugin/package.json } ``` 转换后的结构: -```json +```typescript const debug = (ctx: IPublicModelPluginContext, options: any) => { return {}; } diff --git a/docs/docs/api/workspace.md b/docs/docs/api/workspace.md index 5a9ad2a44..bf0755537 100644 --- a/docs/docs/api/workspace.md +++ b/docs/docs/api/workspace.md @@ -3,10 +3,10 @@ title: workspace - 应用级 API sidebar_position: 12 --- +> **[@experimental](./#experimental)**
> **@types** [IPublicApiWorkspace](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/workspace.ts)
> **@since** v1.1.0 - ## 模块简介 通过该模块可以开发应用级低代码设计器。 @@ -47,6 +47,16 @@ get window(): IPublicModelWindow[] 关联模型 [IPublicModelWindow](./model/window) +### resourceList + +当前设计器的资源列表数据 + +``` +get resourceList(): IPublicModelResource; +``` + +关联模型 [IPublicModelResource](./model/resource) + ## 方法签名 ### registerResourceType @@ -54,7 +64,7 @@ get window(): IPublicModelWindow[] ```typescript /** 注册资源 */ -registerResourceType(resourceName: string, resourceType: 'editor', options: IPublicResourceOptions): void; +registerResourceType(name: string, type: 'editor', options: IPublicResourceOptions): void; ``` 相关类型:[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts) @@ -74,3 +84,55 @@ active 窗口变更事件 ```typescript function onChangeActiveWindow(fn: () => void): void; ``` + +### setResourceList + +设置设计器资源列表数据 + +```typescript +setResourceList(resourceList: IPublicResourceList) {} +``` + +相关类型:[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts) + +### onResourceListChange + +设计器资源列表数据变更事件 + +```typescript +onResourceListChange(fn: (resourceList: IPublicResourceList): void): (): void; +``` + +相关类型:[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts) + +### openEditorWindow + +打开视图窗口 + +```typescript +openEditorWindow(resourceName: string, title: string, options: Object, viewName?: string): void; +``` + +### openEditorWindowById + +通过视图 id 打开窗口 + +```typescript +openEditorWindowById(id: string): void; +``` + +### removeEditorWindow + +移除视图窗口 + +```typescript +removeEditorWindow(resourceName: string, title: string): void; +``` + +### removeEditorWindowById + +通过视图 id 移除窗口 + +```typescript +removeEditorWindowById(id: string): void; +``` \ No newline at end of file diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index 3440871c8..09e1b4ca6 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -1,8 +1,9 @@ -import { IPublicApiWorkspace } from '@alilc/lowcode-types'; +import { IPublicApiWorkspace, IPublicResourceList, IPublicResourceOptions } from '@alilc/lowcode-types'; import { Workspace as InnerWorkSpace } from '@alilc/lowcode-workspace'; import { Plugins } from '@alilc/lowcode-shell'; import { Window } from '../model/window'; import { workspaceSymbol } from '../symbols'; +import { Resource } from '../model'; export class Workspace implements IPublicApiWorkspace { readonly [workspaceSymbol]: InnerWorkSpace; @@ -11,6 +12,18 @@ export class Workspace implements IPublicApiWorkspace { this[workspaceSymbol] = innerWorkspace; } + get resourceList() { + return this[workspaceSymbol].getResourceList().map(d => new Resource(d)); + } + + setResourceList(resourceList: IPublicResourceList) { + this[workspaceSymbol].setResourceList(resourceList); + } + + onResourceListChange(fn: (resourceList: IPublicResourceList) => void): () => void { + return this[workspaceSymbol].onResourceListChange(fn); + } + get isActive() { return this[workspaceSymbol].isActive; } @@ -19,12 +32,12 @@ export class Workspace implements IPublicApiWorkspace { return new Window(this[workspaceSymbol].window); } - registerResourceType(resourceName: string, resourceType: 'editor', options: any): void { - this[workspaceSymbol].registerResourceType(resourceName, resourceType, options); + registerResourceType(name: string, type: 'editor', options: IPublicResourceOptions): void { + this[workspaceSymbol].registerResourceType(name, type, options); } - openEditorWindow(resourceName: string, title: string, viewType?: string) { - this[workspaceSymbol].openEditorWindow(resourceName, title, viewType); + openEditorWindow(resourceName: string, title: string, extra: Object, viewName?: string) { + this[workspaceSymbol].openEditorWindow(resourceName, title, extra, viewName); } openEditorWindowById(id: string) { diff --git a/packages/shell/src/model/index.ts b/packages/shell/src/model/index.ts index 1e0a77775..5f5e50220 100644 --- a/packages/shell/src/model/index.ts +++ b/packages/shell/src/model/index.ts @@ -13,4 +13,6 @@ export * from './prop'; export * from './props'; export * from './selection'; export * from './setting-prop-entry'; -export * from './setting-top-entry'; \ No newline at end of file +export * from './setting-top-entry'; +export * from './resource'; +export * from './resource-type'; \ No newline at end of file diff --git a/packages/shell/src/model/resource-type.ts b/packages/shell/src/model/resource-type.ts new file mode 100644 index 000000000..b5ed549f1 --- /dev/null +++ b/packages/shell/src/model/resource-type.ts @@ -0,0 +1,22 @@ +import { IPublicModelResourceType } from '@alilc/lowcode-types'; +import { ResourceType as InnerResourceType } from '@alilc/lowcode-workspace'; +import { resourceTypeSymbol } from '../symbols'; + +export class ResourceType implements IPublicModelResourceType { + readonly [resourceTypeSymbol]: InnerResourceType; + constructor(resourceType: InnerResourceType) { + this[resourceTypeSymbol] = resourceType; + } + + get name() { + return this[resourceTypeSymbol].name; + } + + get description() { + return this[resourceTypeSymbol].options.description; + } + + get icon() { + return this[resourceTypeSymbol].options.icon; + } +} \ No newline at end of file diff --git a/packages/shell/src/model/resource.ts b/packages/shell/src/model/resource.ts new file mode 100644 index 000000000..df8190549 --- /dev/null +++ b/packages/shell/src/model/resource.ts @@ -0,0 +1,28 @@ +import { IPublicModelResource } from '@alilc/lowcode-types'; +import { Resource as InnerResource } from '@alilc/lowcode-workspace'; +import { resourceSymbol } from '../symbols'; +import { ResourceType } from './resource-type'; + +export class Resource implements IPublicModelResource { + readonly [resourceSymbol]: InnerResource; + + constructor(resource: InnerResource) { + this[resourceSymbol] = resource; + } + + get title() { + return this[resourceSymbol].title; + } + + get icon() { + return this[resourceSymbol].icon; + } + + get options() { + return this[resourceSymbol].options; + } + + get resourceType() { + return new ResourceType(this[resourceSymbol].resourceType); + } +} \ No newline at end of file diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index fee783f53..fcb282490 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -1,6 +1,7 @@ import { windowSymbol } from '../symbols'; import { IPublicModelWindow } from '@alilc/lowcode-types'; import { EditorWindow } from '@alilc/lowcode-workspace'; +import { ResourceType } from './resource-type'; export class Window implements IPublicModelWindow { private readonly [windowSymbol]: EditorWindow; @@ -17,8 +18,8 @@ export class Window implements IPublicModelWindow { return this[windowSymbol].icon; } - get resourceName() { - return this[windowSymbol].resourceName; + get resourceType(): ResourceType { + return new ResourceType(this[windowSymbol].resourceType); } constructor(editorWindow: EditorWindow) { diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index b87e1f24b..cd164f62a 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -28,4 +28,6 @@ export const hotkeySymbol = Symbol('hotkey'); export const pluginsSymbol = Symbol('plugins'); export const workspaceSymbol = Symbol('workspace'); export const windowSymbol = Symbol('window'); -export const pluginInstanceSymbol = Symbol('plugin-instance'); \ No newline at end of file +export const pluginInstanceSymbol = Symbol('plugin-instance'); +export const resourceTypeSymbol = Symbol('resourceType'); +export const resourceSymbol = Symbol('resource'); \ No newline at end of file diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index b9cd29afa..165565fe7 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -1,23 +1,39 @@ import { IPublicModelWindow } from '../model'; import { IPublicResourceOptions } from '../type'; -import { IPublicApiPlugins } from '@alilc/lowcode-types'; +import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList } from '@alilc/lowcode-types'; export interface IPublicApiWorkspace { + /** 是否启用 workspace 模式 */ isActive: boolean; /** 当前设计器窗口 */ window: IPublicModelWindow; + /** 获取资源树列表 */ + get resourceList(): IPublicModelResource[]; + + /** 设置资源树列表 */ + setResourceList(resourceList: IPublicResourceList): void; + + /** 资源树列表更新事件 */ + onResourceListChange(fn: (resourceList: IPublicResourceList) => void): () => void; + /** 注册资源 */ - registerResourceType(resourceName: string, resourceType: 'editor', options: IPublicResourceOptions): void; + registerResourceType(resourceName: string, type: 'editor', options: IPublicResourceOptions): void; /** 打开视图窗口 */ - openEditorWindow(resourceName: string, title: string, viewType?: string): void; + openEditorWindow(resourceName: string, title: string, extra: Object, viewName?: string): void; - /** 移除窗口 */ + /** 通过视图 id 打开窗口 */ + openEditorWindowById(id: string): void; + + /** 移除视图窗口 */ removeEditorWindow(resourceName: string, title: string): void; + /** 通过视图 id 移除窗口 */ + removeEditorWindowById(id: string): void; + plugins: IPublicApiPlugins; /** 当前设计器的编辑窗口 */ diff --git a/packages/types/src/shell/model/index.ts b/packages/types/src/shell/model/index.ts index 5b02d0224..669fdfc99 100644 --- a/packages/types/src/shell/model/index.ts +++ b/packages/types/src/shell/model/index.ts @@ -27,4 +27,6 @@ export * from './engine-config'; export * from './editor'; export * from './preference'; export * from './plugin-instance'; -export * from './sensor'; \ No newline at end of file +export * from './sensor'; +export * from './resource-type'; +export * from './resource'; \ No newline at end of file diff --git a/packages/types/src/shell/model/resource-type.ts b/packages/types/src/shell/model/resource-type.ts new file mode 100644 index 000000000..e8031145e --- /dev/null +++ b/packages/types/src/shell/model/resource-type.ts @@ -0,0 +1,7 @@ +import { ReactElement } from 'react'; + +export interface IPublicModelResourceType { + get description(): string | undefined; + + get icon(): ReactElement | undefined; +} \ No newline at end of file diff --git a/packages/types/src/shell/model/resource.ts b/packages/types/src/shell/model/resource.ts new file mode 100644 index 000000000..23dbfb50f --- /dev/null +++ b/packages/types/src/shell/model/resource.ts @@ -0,0 +1,12 @@ +import { ReactElement } from 'react'; +import { IPublicModelResourceType } from './resource-type'; + +export interface IPublicModelResource { + get title(): string; + + get icon(): ReactElement | undefined; + + get options(): Object; + + get resourceType(): IPublicModelResourceType | undefined; +} \ No newline at end of file diff --git a/packages/types/src/shell/model/window.ts b/packages/types/src/shell/model/window.ts index 1502f2a3c..7a12fc8e6 100644 --- a/packages/types/src/shell/model/window.ts +++ b/packages/types/src/shell/model/window.ts @@ -1,6 +1,9 @@ +import { ReactElement } from 'react'; import { IPublicTypeNodeSchema } from '../type'; +import { IPublicModelResourceType } from './resource-type'; export interface IPublicModelWindow { + /** 当前窗口导入 schema */ importSchema(schema: IPublicTypeNodeSchema): void; @@ -16,6 +19,9 @@ export interface IPublicModelWindow { /** 窗口标题 */ title?: string; - /** 窗口资源名字 */ - resourceName?: string; + /** 窗口 icon */ + icon?: ReactElement; + + /** 窗口资源类型 */ + resourceType?: IPublicModelResourceType; } \ No newline at end of file diff --git a/packages/types/src/shell/type/resource-options.ts b/packages/types/src/shell/type/resource-options.ts index e82db194c..4954aa7fa 100644 --- a/packages/types/src/shell/type/resource-options.ts +++ b/packages/types/src/shell/type/resource-options.ts @@ -1,21 +1,23 @@ export interface IPublicViewFunctions { + /** 视图初始化钩子 */ init?: () => Promise; + /** 资源保存时,会调用视图的钩子 */ save?: () => Promise; } export interface IPublicEditorView { + /** 资源名字 */ viewName: string; + /** 资源类型 */ viewType?: 'editor' | 'webview'; - (ctx: any): IPublicViewFunctions; + (ctx: any, options: any): IPublicViewFunctions; } export interface IPublicResourceOptions { - /** 资源名字 */ - name: string; /** 资源描述 */ description?: string; @@ -41,4 +43,14 @@ export interface IPublicResourceOptions { /** 默认标题 */ defaultTitle?: string; -} \ No newline at end of file +} + +export interface IPublicResourceData { + resourceName: string; + title: string; + options: { + [key: string]: any; + }; +} + +export type IPublicResourceList = IPublicResourceData[]; \ No newline at end of file diff --git a/packages/workspace/src/editor-view/context.ts b/packages/workspace/src/editor-view/context.ts index a845d36c1..12e63b255 100644 --- a/packages/workspace/src/editor-view/context.ts +++ b/packages/workspace/src/editor-view/context.ts @@ -13,13 +13,13 @@ export class Context extends BasicContext { viewType: 'editor' | 'webview'; - constructor(public workspace: InnerWorkspace, public editorWindow: EditorWindow, public editorView: IPublicEditorView) { + constructor(public workspace: InnerWorkspace, public editorWindow: EditorWindow, public editorView: IPublicEditorView, options: Object) { super(workspace, editorView.viewName, editorWindow); this.viewType = editorView.viewType || 'editor'; this.viewName = editorView.viewName; this.instance = editorView(this.innerPlugins._getLowCodePluginContext({ pluginName: 'any', - })); + }), options); makeObservable(this); } diff --git a/packages/workspace/src/editor-window/context.ts b/packages/workspace/src/editor-window/context.ts index 2c1eee719..5e3fb172f 100644 --- a/packages/workspace/src/editor-window/context.ts +++ b/packages/workspace/src/editor-window/context.ts @@ -2,24 +2,20 @@ import { uniqueId } from '@alilc/lowcode-utils'; import { makeObservable, obx } from '@alilc/lowcode-editor-core'; import { Context } from '../editor-view/context'; import { Workspace } from '../workspace'; -import { Resource } from '../resource'; +import { ResourceType } from '../resource-type'; export class EditorWindow { id: string = uniqueId('window'); icon: React.ReactElement | undefined; - constructor(readonly resource: Resource, readonly workspace: Workspace, public title: string | undefined = '') { + constructor(readonly resourceType: ResourceType, readonly workspace: Workspace, public title: string | undefined = '', private options: Object = {}) { makeObservable(this); this.init(); - this.icon = resource.icon; - } - - get resourceName(): string { - return this.resource.options.name; + this.icon = resourceType.icon; } async importSchema(schema: any) { - const newSchema = await this.resource.import(schema); + const newSchema = await this.resourceType.import(schema); if (!newSchema) { return; @@ -33,13 +29,13 @@ export class EditorWindow { async save() { const value: any = {}; - const editorViews = this.resource.editorViews; + const editorViews = this.resourceType.editorViews; for (let i = 0; i < editorViews.length; i++) { const name = editorViews[i].viewName; const saveResult = await this.editorViews.get(name)?.save(); value[name] = saveResult; } - return await this.resource.save(value); + return await this.resourceType.save(value); } async init() { @@ -49,7 +45,7 @@ export class EditorWindow { } initViewTypes = async () => { - const editorViews = this.resource.editorViews; + const editorViews = this.resourceType.editorViews; for (let i = 0; i < editorViews.length; i++) { const name = editorViews[i].viewName; await this.initViewType(name); @@ -60,7 +56,7 @@ export class EditorWindow { }; execViewTypesInit = async () => { - const editorViews = this.resource.editorViews; + const editorViews = this.resourceType.editorViews; for (let i = 0; i < editorViews.length; i++) { const name = editorViews[i].viewName; this.changeViewType(name); @@ -69,7 +65,7 @@ export class EditorWindow { }; setDefaultViewType = () => { - this.changeViewType(this.resource.defaultViewType); + this.changeViewType(this.resourceType.defaultViewType); }; @obx.ref editorView: Context; @@ -77,11 +73,11 @@ export class EditorWindow { @obx editorViews: Map = new Map(); initViewType = async (name: string) => { - const viewInfo = this.resource.getEditorView(name); + const viewInfo = this.resourceType.getEditorView(name); if (this.editorViews.get(name)) { return; } - const editorView = new Context(this.workspace, this, viewInfo as any); + const editorView = new Context(this.workspace, this, viewInfo as any, this.options); this.editorViews.set(name, editorView); }; diff --git a/packages/workspace/src/index.ts b/packages/workspace/src/index.ts index 91dc20a54..8c71771a9 100644 --- a/packages/workspace/src/index.ts +++ b/packages/workspace/src/index.ts @@ -1,4 +1,5 @@ export { Workspace } from './workspace'; -export { Resource } from './resource'; +export { ResourceType } from './resource-type'; export * from './editor-window/context'; export * from './layouts/workbench'; +export { Resource } from './resource'; diff --git a/packages/workspace/src/resource-type.ts b/packages/workspace/src/resource-type.ts new file mode 100644 index 000000000..60a2832ee --- /dev/null +++ b/packages/workspace/src/resource-type.ts @@ -0,0 +1,53 @@ +import { IPublicEditorView, IPublicModelResourceType, IPublicResourceOptions } from '@alilc/lowcode-types'; + +export class ResourceType implements IPublicModelResourceType { + constructor(readonly name: string, readonly type: 'editor' | 'webview', options: IPublicResourceOptions) { + if (options.editorViews) { + options.editorViews.forEach((d: any) => { + this.editorViewMap.set(d.viewName, d); + }); + } + + this.options = options; + } + + get description() { + return this.options.description; + } + + options: IPublicResourceOptions; + + editorViewMap: Map = new Map(); + + init(ctx: any) { + this.options.init(ctx); + } + + get icon() { + return this.options.icon; + } + + async import(schema: any) { + return await this.options.import?.(schema); + } + + getEditorView(name: string) { + return this.editorViewMap.get(name); + } + + get defaultViewType() { + return this.options.defaultViewType || this.editorViewMap.keys().next().value; + } + + get editorViews() { + return Array.from(this.editorViewMap.values()); + } + + async save(value: any) { + return await this.options.save?.(value); + } + + get title() { + return this.options.defaultTitle; + } +} \ No newline at end of file diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index f881caf0f..5c44785ce 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -1,49 +1,29 @@ -import { IPublicEditorView, IPublicResourceOptions } from '@alilc/lowcode-types'; +import { IPublicModelResource, IPublicResourceData } from '@alilc/lowcode-types'; +import { Logger } from '@alilc/lowcode-utils'; +import { ResourceType } from './resource-type'; -export class Resource { - constructor(options: IPublicResourceOptions) { - if (options.editorViews) { - options.editorViews.forEach((d: any) => { - this.editorViewMap.set(d.viewName, d); - }); +const logger = new Logger({ level: 'warn', bizName: 'workspace:resource' }); + +export class Resource implements IPublicModelResource { + constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType) { + if (!resourceType) { + logger.error(`resourceType[${resourceType}] is unValid.`); } - - this.options = options; - } - - options: IPublicResourceOptions; - - editorViewMap: Map = new Map(); - - init(ctx: any) { - this.options.init(ctx); } get icon() { - return this.options.icon; + return this.resourceType?.icon; } - async import(schema: any) { - return await this.options.import?.(schema); - } - - getEditorView(name: string) { - return this.editorViewMap.get(name); - } - - get defaultViewType() { - return this.options.defaultViewType || this.editorViewMap.keys().next().value; - } - - get editorViews() { - return Array.from(this.editorViewMap.values()); - } - - async save(value: any) { - return await this.options.save?.(value); + get type() { + return this.resourceData.resourceName; } get title() { - return this.options.defaultTitle; + return this.resourceData.title; + } + + get options() { + return this.resourceData.options; } } \ No newline at end of file diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 05d2e666a..ca7265cb3 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -1,10 +1,11 @@ import { Designer } from '@alilc/lowcode-designer'; import { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; import { Plugins } from '@alilc/lowcode-shell'; -import { IPublicApiWorkspace, IPublicResourceOptions } from '@alilc/lowcode-types'; +import { IPublicApiWorkspace, IPublicResourceList, IPublicResourceOptions } from '@alilc/lowcode-types'; import { BasicContext } from './base-context'; import { EditorWindow } from './editor-window/context'; import { Resource } from './resource'; +import { ResourceType } from './resource-type'; enum event { ChangeWindow = 'change_window', @@ -12,6 +13,8 @@ enum event { ChangeActiveWindow = 'change_active_window', } +const CHANGE_EVENT = 'resource.list.change'; + export class Workspace implements IPublicApiWorkspace { private context: BasicContext; @@ -42,7 +45,7 @@ export class Workspace implements IPublicApiWorkspace { if (!this.defaultResource) { return; } - const title = this.defaultResource.title; + const title = this.defaultResource.description; this.window = new EditorWindow(this.defaultResource, this, title); this.editorWindowMap.set(this.window.id, this.window); this.windows.push(this.window); @@ -50,7 +53,6 @@ export class Workspace implements IPublicApiWorkspace { this.emitChangeActiveWindow(); } - private _isActive = false; get isActive() { @@ -67,12 +69,14 @@ export class Workspace implements IPublicApiWorkspace { @obx.ref window: EditorWindow; - private resources: Map = new Map(); + private resourceTypeMap: Map = new Map(); - async registerResourceType(resourceName: string, resourceType: 'editor' | 'webview', options: IPublicResourceOptions): Promise { - if (resourceType === 'editor') { - const resource = new Resource(options); - this.resources.set(resourceName, resource); + private resourceList: Resource[] = []; + + async registerResourceType(resourceName: string, type: 'editor' | 'webview', options: IPublicResourceOptions): Promise { + if (type === 'editor') { + const resourceType = new ResourceType(resourceName, type, options); + this.resourceTypeMap.set(resourceName, resourceType); if (!this.window && this.defaultResource) { this.initWindow(); @@ -80,17 +84,37 @@ export class Workspace implements IPublicApiWorkspace { } } - get defaultResource(): Resource | null { - if (this.resources.size > 1) { - return this.resources.values().next().value; + getResourceList() { + return this.resourceList; + } + + setResourceList(resourceList: IPublicResourceList) { + this.resourceList = resourceList.map(d => new Resource(d, this.getResourceType(d.resourceName))); + this.emitter.emit(CHANGE_EVENT, resourceList); + } + + onResourceListChange(fn: (resourceList: IPublicResourceList) => void): () => void { + this.emitter.on(CHANGE_EVENT, fn); + return () => { + this.emitter.off(CHANGE_EVENT, fn); + }; + } + + getResourceType(resourceName: string): ResourceType { + return this.resourceTypeMap.get(resourceName)!; + } + + get defaultResource(): ResourceType | null { + if (this.resourceTypeMap.size > 1) { + return this.resourceTypeMap.values().next().value; } return null; } removeResourceType(resourceName: string) { - if (this.resources.has(resourceName)) { - this.resources.delete(resourceName); + if (this.resourceTypeMap.has(resourceName)) { + this.resourceTypeMap.delete(resourceName); } } @@ -110,7 +134,7 @@ export class Workspace implements IPublicApiWorkspace { } removeEditorWindow(resourceName: string, title: string) { - const index = this.windows.findIndex(d => (d.resourceName === resourceName && d.title)); + const index = this.windows.findIndex(d => (d.resourceType.name === resourceName && d.title)); this.remove(index); } @@ -122,19 +146,19 @@ export class Workspace implements IPublicApiWorkspace { } } - openEditorWindow(resourceName: string, title: string, viewType?: string) { - const resource = this.resources.get(resourceName); - if (!resource) { - console.error(`${resourceName} is not available`); + openEditorWindow(name: string, title: string, options: Object, viewType?: string) { + const resourceType = this.resourceTypeMap.get(name); + if (!resourceType) { + console.error(`${name} is not available`); return; } - const filterWindows = this.windows.filter(d => (d.resourceName === resourceName && d.title == title)); + const filterWindows = this.windows.filter(d => (d.resourceType.name === name && d.title == title)); if (filterWindows && filterWindows.length) { this.window = filterWindows[0]; this.emitChangeActiveWindow(); return; } - this.window = new EditorWindow(resource, this, title); + this.window = new EditorWindow(resourceType, this, title, options); this.windows.push(this.window); this.editorWindowMap.set(this.window.id, this.window); this.emitChangeWindow(); From fec8805261305e260f185cd43441d05af1349580 Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 9 Jan 2023 18:07:05 +0800 Subject: [PATCH 02/89] docs(history): optimize api doc for model/history, and fix related lint issues --- docs/docs/api/model/history.md | 94 +++++++++++++++++--- packages/designer/src/document/history.ts | 27 ++++-- packages/editor-core/src/utils/preference.ts | 12 +-- packages/shell/src/model/history.ts | 8 +- packages/types/src/shell/model/history.ts | 27 ++++-- 5 files changed, 127 insertions(+), 41 deletions(-) diff --git a/docs/docs/api/model/history.md b/docs/docs/api/model/history.md index 5864febea..db6800850 100644 --- a/docs/docs/api/model/history.md +++ b/docs/docs/api/model/history.md @@ -12,47 +12,113 @@ sidebar_position: 5 ## 方法签名 ### go -go(cursor: number) - 历史记录跳转到指定位置 +```typescript +/** + * 历史记录跳转到指定位置 + * go to a specific history + * @param cursor + */ +go(cursor: number): void; +``` + ### back -back() - 历史记录后退 +```typescript +/** + * 历史记录后退 + * go backward in history + */ +back(): void; +``` + ### forward forward() 历史记录前进 + +```typescript +/** + * 历史记录前进 + * go forward in history + */ +forward(): void; +``` + ### savePoint -savePoint() - 保存当前状态 -### isSavePoint -isSavePoint() +```typescript +/** + * 保存当前状态 + * do save current change as a record in history + */ +savePoint(): void; +``` + +### isSavePoint 当前是否是「保存点」,即是否有状态变更但未保存 +```typescript +/** + * 当前是否是「保存点」,即是否有状态变更但未保存 + * check if there is unsaved change for history + */ +isSavePoint(): boolean; +``` + ### getState -getState() - 获取 state,判断当前是否为「可回退」、「可前进」的状态 +```typescript +/** + * 获取 state,判断当前是否为「可回退」、「可前进」的状态 + * get flags in number which indicat current change state + * + * | 1 | 1 | 1 | + * | -------- | -------- | -------- | + * | modified | redoable | undoable | + * eg: + * 7 means : modified && redoable && undoable + * 5 means : modified && undoable + */ +getState(): number; +``` + ## 事件 ### onChangeState -onChangeState(func: () => any) - 监听 state 变更事件 +```typescript +/** + * 监听 state 变更事件 + * monitor on stateChange event + * @param func + */ +onChangeState(func: () => any): IPublicTypeDisposable; +``` + +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + ### onChangeCursor -onChangeCursor(func: () => any) - 监听历史记录游标位置变更事件 + +```typescript +/** + * 监听历史记录游标位置变更事件 + * monitor on cursorChange event + * @param func + */ +onChangeCursor(func: () => any): IPublicTypeDisposable; +``` + +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) \ No newline at end of file diff --git a/packages/designer/src/document/history.ts b/packages/designer/src/document/history.ts index fa62bc5cd..5d52f0dd3 100644 --- a/packages/designer/src/document/history.ts +++ b/packages/designer/src/document/history.ts @@ -1,5 +1,8 @@ import { reaction, untracked, globalContext, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { IPublicTypeNodeSchema, IPublicModelHistory } from '@alilc/lowcode-types'; +import { Logger } from '@alilc/lowcode-utils'; + +const logger = new Logger({ level: 'warn', bizName: 'history' }); export interface Serialization { serialize(data: K): T; @@ -30,11 +33,15 @@ export class History implements IHistory { }, }; - setSerialization(serialization: Serialization) { - this.currentSerialization = serialization; + get hotData() { + return this.session.data; } - constructor(dataFn: () => T | null, private redoer: (data: T) => void, private timeGap: number = 1000) { + constructor( + dataFn: () => T | null, + private redoer: (data: T) => void, + private timeGap: number = 1000, + ) { this.session = new Session(0, null, this.timeGap); this.records = [this.session]; @@ -68,8 +75,8 @@ export class History implements IHistory { }, { fireImmediately: true }); } - get hotData() { - return this.session.data; + setSerialization(serialization: Serialization) { + this.currentSerialization = serialization; } isSavePoint(): boolean { @@ -84,16 +91,18 @@ export class History implements IHistory { this.asleep = false; } - go(cursor: number) { + go(originalCursor: number) { this.session.end(); - const currentCursor = this.session.cursor; + let cursor = originalCursor; cursor = +cursor; if (cursor < 0) { cursor = 0; } else if (cursor >= this.records.length) { cursor = this.records.length - 1; } + + const currentCursor = this.session.cursor; if (cursor === currentCursor) { return; } @@ -106,7 +115,7 @@ export class History implements IHistory { this.redoer(this.currentSerialization.unserialize(hotData)); this.emitter.emit('cursor', hotData); } catch (e) /* istanbul ignore next */ { - console.error(e); + logger.error(e); } this.wakeup(); @@ -174,6 +183,7 @@ export class History implements IHistory { } return state; } + /** * 监听 state 变更事件 * @param func @@ -209,6 +219,7 @@ export class History implements IHistory { this.emitter.removeAllListeners(); this.records = []; } + /** * * @deprecated diff --git a/packages/editor-core/src/utils/preference.ts b/packages/editor-core/src/utils/preference.ts index 0ee852bd7..6f17a8f63 100644 --- a/packages/editor-core/src/utils/preference.ts +++ b/packages/editor-core/src/utils/preference.ts @@ -2,15 +2,12 @@ import store from 'store'; import { getLogger } from './logger'; import { IPublicModelPreference } from '@alilc/lowcode-types'; -const logger = getLogger({ level: 'log', bizName: 'Preference' }); +const logger = getLogger({ level: 'warn', bizName: 'Preference' }); const STORAGE_KEY_PREFIX = 'ale'; - /** * used to store user preferences, such as pinned status of a pannel. * save to local storage. - * - * @class PreferenceStore */ export default class Preference implements IPublicModelPreference { getStorageKey(key: string, module?: string): string { @@ -24,7 +21,7 @@ export default class Preference implements IPublicModelPreference { return; } const storageKey = this.getStorageKey(key, module); - logger.log('storageKey:', storageKey, 'set with value:', value); + logger.debug('storageKey:', storageKey, 'set with value:', value); store.set(storageKey, value); } @@ -35,16 +32,15 @@ export default class Preference implements IPublicModelPreference { } const storageKey = this.getStorageKey(key, module); const result = store.get(storageKey); - logger.log('storageKey:', storageKey, 'get with result:', result); + logger.debug('storageKey:', storageKey, 'get with result:', result); return result; } + /** * check if local storage contain certain key * * @param {string} key * @param {string} module - * @returns {boolean} - * @memberof Preference */ contains(key: string, module: string): boolean { if (!key || typeof key !== 'string' || key.length === 0) { diff --git a/packages/shell/src/model/history.ts b/packages/shell/src/model/history.ts index c6fa962cf..e872847de 100644 --- a/packages/shell/src/model/history.ts +++ b/packages/shell/src/model/history.ts @@ -1,6 +1,6 @@ import { DocumentModel as InnerDocumentModel } from '@alilc/lowcode-designer'; import { historySymbol, documentSymbol } from '../symbols'; -import { IPublicModelHistory } from '@alilc/lowcode-types'; +import { IPublicModelHistory, IPublicTypeDisposable } from '@alilc/lowcode-types'; export class History implements IPublicModelHistory { private readonly [documentSymbol]: InnerDocumentModel; @@ -54,7 +54,7 @@ export class History implements IPublicModelHistory { * 获取 state,判断当前是否为「可回退」、「可前进」的状态 * @returns */ - getState(): any { + getState(): number { return this[historySymbol].getState(); } @@ -63,7 +63,7 @@ export class History implements IPublicModelHistory { * @param func * @returns */ - onChangeState(func: () => any): () => void { + onChangeState(func: () => any): IPublicTypeDisposable { return this[historySymbol].onStateChange(func); } @@ -72,7 +72,7 @@ export class History implements IPublicModelHistory { * @param func * @returns */ - onChangeCursor(func: () => any): () => void { + onChangeCursor(func: () => any): IPublicTypeDisposable { return this[historySymbol].onCursor(func); } } diff --git a/packages/types/src/shell/model/history.ts b/packages/types/src/shell/model/history.ts index 1c0020de3..eb183ab77 100644 --- a/packages/types/src/shell/model/history.ts +++ b/packages/types/src/shell/model/history.ts @@ -1,49 +1,62 @@ +import { IPublicTypeDisposable } from '../type'; + export interface IPublicModelHistory { /** * 历史记录跳转到指定位置 + * go to a specific history * @param cursor */ go(cursor: number): void; /** * 历史记录后退 + * go backward in history */ back(): void; /** * 历史记录前进 + * go forward in history */ forward(): void; /** * 保存当前状态 + * do save current change as a record in history */ savePoint(): void; /** * 当前是否是「保存点」,即是否有状态变更但未保存 - * @returns + * check if there is unsaved change for history */ isSavePoint(): boolean; /** * 获取 state,判断当前是否为「可回退」、「可前进」的状态 - * @returns + * get flags in number which indicat current change state + * + * | 1 | 1 | 1 | + * | -------- | -------- | -------- | + * | modified | redoable | undoable | + * eg: + * 7 means : modified && redoable && undoable + * 5 means : modified && undoable */ - getState(): any; + getState(): number; /** * 监听 state 变更事件 + * monitor on stateChange event * @param func - * @returns */ - onChangeState(func: () => any): () => void; + onChangeState(func: () => any): IPublicTypeDisposable; /** * 监听历史记录游标位置变更事件 + * monitor on cursorChange event * @param func - * @returns */ - onChangeCursor(func: () => any): () => void; + onChangeCursor(func: () => any): IPublicTypeDisposable; } From ee8a63d8d236f3896ff63ad7b091579214be4fb6 Mon Sep 17 00:00:00 2001 From: JackLian Date: Tue, 10 Jan 2023 09:12:35 +0800 Subject: [PATCH 03/89] chore: publish docs 1.0.14 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 797a1e3e0..4102563dc 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.13", + "version": "1.0.14", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From f6771fefac2ad70615eefb95829f6c57c1ece08b Mon Sep 17 00:00:00 2001 From: JackLian Date: Tue, 10 Jan 2023 14:47:07 +0800 Subject: [PATCH 04/89] docs(detecting): optimize api doc for model/detecting, and fix related lint issues --- docs/docs/api/model/detecting.md | 61 +++++-- packages/designer/src/designer/detecting.ts | 7 +- .../designer/src/document/document-model.ts | 161 +++++++++--------- packages/shell/src/model/detecting.ts | 10 +- packages/types/src/shell/model/detecting.ts | 19 ++- 5 files changed, 157 insertions(+), 101 deletions(-) diff --git a/docs/docs/api/model/detecting.md b/docs/docs/api/model/detecting.md index 2cc0ea18d..7a4886ea4 100644 --- a/docs/docs/api/model/detecting.md +++ b/docs/docs/api/model/detecting.md @@ -9,29 +9,63 @@ sidebar_position: 6 画布节点悬停模型 +## 变量 + +### current + +当前 hover 的节点 + +`@type {IPublicModelNode | null}` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + +**@since v1.0.16** + +### enable + +是否启用 + +`@type {boolean}` + + ## 方法签名 ### capture -capture(id: string) - hover 指定节点 +```typescript +/** + * hover 指定节点 + * capture node with nodeId + * @param id 节点 id + */ +capture(id: string): void; +``` + ### release -release(id: string) - hover 离开指定节点 +```typescript +/** + * hover 离开指定节点 + * release node with nodeId + * @param id 节点 id + */ +release(id: string): void; +``` + ### leave -leave() - 清空 hover 态 -### current -当前 hover 的节点 - -**@since v1.0.16** +```typescript +/** + * 清空 hover 态 + * clear all hover state + */ +leave(): void; +``` ### onDetectingChange hover 节点变化事件 @@ -42,6 +76,11 @@ hover 节点变化事件 * set callback which will be called when hovering object changed. * @since v1.1.0 */ -onDetectingChange(fn: (node: IPublicModelNode) => void): () => void; +onDetectingChange(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; ``` + +相关类型: +- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) +- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + **@since v1.1.0** \ No newline at end of file diff --git a/packages/designer/src/designer/detecting.ts b/packages/designer/src/designer/detecting.ts index d3d14106c..b7ada8138 100644 --- a/packages/designer/src/designer/detecting.ts +++ b/packages/designer/src/designer/detecting.ts @@ -2,8 +2,13 @@ import { makeObservable, obx, IEventBus, createModuleEventBus } from '@alilc/low import { IPublicModelDetecting, IPublicModelNode, IPublicModelDocumentModel } from '@alilc/lowcode-types'; const DETECTING_CHANGE_EVENT = 'detectingChange'; -export interface IDetecting extends IPublicModelDetecting { +export interface IDetecting extends Omit< IPublicModelDetecting, 'capture' | 'release' | 'leave' > { + capture(node: IPublicModelNode | null): void; + + release(node: IPublicModelNode | null): void; + + leave(document: IPublicModelDocumentModel | undefined): void; } export class Detecting implements IDetecting { diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 9d5b05175..ffd0807ae 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -39,6 +39,10 @@ export interface IDocumentModel extends IPublicModelDocumentModel { readonly designer: Designer; + /** + * 根据 id 获取节点 + */ + getNode(id: string): INode | null; } export class DocumentModel implements IDocumentModel { @@ -118,16 +122,85 @@ export class DocumentModel implements IDocumentModel { @obx.ref private _drillDownNode: Node | null = null; - drillDown(node: Node | null) { - this._drillDownNode = node; - } - private _modalNode?: INode; private _blank?: boolean; private inited = false; + @obx.shallow private willPurgeSpace: Node[] = []; + + get modalNode() { + return this._modalNode; + } + + get currentRoot() { + return this.modalNode || this.focusNode; + } + + @obx.shallow private activeNodes?: Node[]; + + @obx.ref private _dropLocation: IDropLocation | null = null; + + set dropLocation(loc: IPublicModelDropLocation | null) { + this._dropLocation = loc; + // pub event + this.designer.editor.eventBus.emit( + 'document.dropLocation.changed', + { document: this, location: loc }, + ); + } + + /** + * 投放插入位置标记 + */ + get dropLocation() { + return this._dropLocation; + } + + /** + * 导出 schema 数据 + */ + get schema(): IPublicTypeRootSchema { + return this.rootNode?.schema as any; + } + + @obx.ref private _opened = false; + + @obx.ref private _suspensed = false; + + /** + * 是否为非激活状态 + */ + get suspensed(): boolean { + return this._suspensed || !this._opened; + } + + /** + * 与 suspensed 相反,是否为激活状态,这个函数可能用的更多一点 + */ + get active(): boolean { + return !this._suspensed; + } + + /** + * @deprecated 兼容 + */ + get actived(): boolean { + return this.active; + } + + /** + * 是否打开 + */ + get opened() { + return this._opened; + } + + get root() { + return this.rootNode; + } + constructor(project: Project, schema?: IPublicTypeRootSchema) { makeObservable(this); this.project = project; @@ -162,6 +235,10 @@ export class DocumentModel implements IDocumentModel { this.inited = true; } + drillDown(node: Node | null) { + this._drillDownNode = node; + } + onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): () => void { this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_CHILDREN_CHANGE, fn); @@ -178,16 +255,6 @@ export class DocumentModel implements IDocumentModel { }; } - @obx.shallow private willPurgeSpace: Node[] = []; - - get modalNode() { - return this._modalNode; - } - - get currentRoot() { - return this.modalNode || this.focusNode; - } - addWillPurge(node: Node) { this.willPurgeSpace.push(node); } @@ -204,7 +271,7 @@ export class DocumentModel implements IDocumentModel { } /** - * 生成唯一id + * 生成唯一 id */ nextId(possibleId: string | undefined) { let id = possibleId; @@ -218,7 +285,7 @@ export class DocumentModel implements IDocumentModel { /** * 根据 id 获取节点 */ - getNode(id: string): Node | null { + getNode(id: string): INode | null { return this._nodesMap.get(id) || null; } @@ -237,8 +304,6 @@ export class DocumentModel implements IDocumentModel { return node ? !node.isPurged : false; } - @obx.shallow private activeNodes?: Node[]; - /** * 根据 schema 创建一个节点 */ @@ -338,24 +403,6 @@ export class DocumentModel implements IDocumentModel { this._nodesMap.delete(node.id); } - @obx.ref private _dropLocation: IDropLocation | null = null; - - set dropLocation(loc: IPublicModelDropLocation | null) { - this._dropLocation = loc; - // pub event - this.designer.editor.eventBus.emit( - 'document.dropLocation.changed', - { document: this, location: loc }, - ); - } - - /** - * 投放插入位置标记 - */ - get dropLocation() { - return this._dropLocation; - } - /** * 包裹当前选区中的节点 */ @@ -378,13 +425,6 @@ export class DocumentModel implements IDocumentModel { return null; } - /** - * 导出 schema 数据 - */ - get schema(): IPublicTypeRootSchema { - return this.rootNode?.schema as any; - } - @action import(schema: IPublicTypeRootSchema, checkId = false) { const drillDownNodeId = this._drillDownNode?.id; @@ -449,37 +489,6 @@ export class DocumentModel implements IDocumentModel { ); } - @obx.ref private _opened = false; - - @obx.ref private _suspensed = false; - - /** - * 是否为非激活状态 - */ - get suspensed(): boolean { - return this._suspensed || !this._opened; - } - - /** - * 与 suspensed 相反,是否为激活状态,这个函数可能用的更多一点 - */ - get active(): boolean { - return !this._suspensed; - } - - /** - * @deprecated 兼容 - */ - get actived(): boolean { - return this.active; - } - - /** - * 是否打开 - */ - get opened() { - return this._opened; - } /** * 切换激活,只有打开的才能激活 @@ -617,10 +626,6 @@ export class DocumentModel implements IDocumentModel { return this.history; } - get root() { - return this.rootNode; - } - /** * @deprecated */ diff --git a/packages/shell/src/model/detecting.ts b/packages/shell/src/model/detecting.ts index 4bfa83614..f99423eae 100644 --- a/packages/shell/src/model/detecting.ts +++ b/packages/shell/src/model/detecting.ts @@ -1,10 +1,10 @@ -import { Node } from './node'; +import { Node as ShellNode } from './node'; import { Detecting as InnerDetecting, - DocumentModel as InnerDocumentModel, + IDocumentModel as InnerDocumentModel, } from '@alilc/lowcode-designer'; import { documentSymbol, detectingSymbol } from '../symbols'; -import { IPublicModelDetecting, IPublicModelNode } from '@alilc/lowcode-types'; +import { IPublicModelDetecting, IPublicModelNode, IPublicTypeDisposable } from '@alilc/lowcode-types'; export class Detecting implements IPublicModelDetecting { private readonly [documentSymbol]: InnerDocumentModel; @@ -26,7 +26,7 @@ export class Detecting implements IPublicModelDetecting { * 当前 hover 的节点 */ get current() { - return Node.create(this[detectingSymbol].current); + return ShellNode.create(this[detectingSymbol].current); } /** @@ -52,7 +52,7 @@ export class Detecting implements IPublicModelDetecting { this[detectingSymbol].leave(this[documentSymbol]); } - onDetectingChange(fn: (node: IPublicModelNode) => void): () => void { + onDetectingChange(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable { return this[detectingSymbol].onDetectingChange(fn); } } \ No newline at end of file diff --git a/packages/types/src/shell/model/detecting.ts b/packages/types/src/shell/model/detecting.ts index 8e82f7449..d828ace32 100644 --- a/packages/types/src/shell/model/detecting.ts +++ b/packages/types/src/shell/model/detecting.ts @@ -1,39 +1,46 @@ import { IPublicModelNode } from './'; +import { IPublicTypeDisposable } from '../type'; export interface IPublicModelDetecting { /** - * 控制大纲树 hover 时是否出现悬停效果 + * 是否启用 + * check if current detecting is enabled + * @since v1.1.0 */ get enable(): boolean; /** * 当前 hover 的节点 + * get current hovering node * @since v1.0.16 */ - get current(): any; + get current(): IPublicModelNode | null; /** * hover 指定节点 + * capture node with nodeId * @param id 节点 id */ - capture(id: string): any; + capture(id: string): void; /** * hover 离开指定节点 + * release node with nodeId * @param id 节点 id */ - release(id: string): any; + release(id: string): void; /** * 清空 hover 态 + * clear all hover state */ - leave(): any; + leave(): void; /** * hover 节点变化事件 * set callback which will be called when hovering object changed. * @since v1.1.0 */ - onDetectingChange(fn: (node: IPublicModelNode) => void): () => void; + onDetectingChange(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; } From d3cc39ec9c03145944d7c9c4c627f7d6e7cea981 Mon Sep 17 00:00:00 2001 From: JackLian Date: Tue, 10 Jan 2023 19:20:17 +0800 Subject: [PATCH 05/89] docs(selection): optimize api doc for model/selection, and fix related lint issues --- docs/docs/api/model/detecting.md | 3 +- docs/docs/api/model/selection.md | 114 +++++++++++++++--- .../designer/src/document/document-model.ts | 14 ++- packages/designer/src/document/selection.ts | 14 ++- packages/shell/src/model/node.ts | 79 ++++++------ packages/shell/src/model/selection.ts | 41 ++++--- packages/types/src/shell/model/history.ts | 2 +- packages/types/src/shell/model/selection.ts | 20 ++- 8 files changed, 201 insertions(+), 86 deletions(-) diff --git a/docs/docs/api/model/detecting.md b/docs/docs/api/model/detecting.md index 7a4886ea4..15e1cfca7 100644 --- a/docs/docs/api/model/detecting.md +++ b/docs/docs/api/model/detecting.md @@ -67,6 +67,7 @@ release(id: string): void; leave(): void; ``` +## 事件 ### onDetectingChange hover 节点变化事件 @@ -81,6 +82,6 @@ onDetectingChange(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; 相关类型: - [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) -- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) +- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) **@since v1.1.0** \ No newline at end of file diff --git a/docs/docs/api/model/selection.md b/docs/docs/api/model/selection.md index 77b33fa60..529a3e5a2 100644 --- a/docs/docs/api/model/selection.md +++ b/docs/docs/api/model/selection.md @@ -14,49 +14,110 @@ sidebar_position: 6 返回选中的节点 id +`@type {string[]}` + +### node +返回选中的节点(如多个节点只返回第一个) + +`@type {IPublicModelNode | null}` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + +**@since v1.1.0** + ## 方法签名 ### select -select(id: string) - 选中指定节点(覆盖方式) +```typescript +/** +* 选中指定节点(覆盖方式) +* select node with id, this will override current selection +* @param id +*/ +select(id: string): void; +``` + ### selectAll -selectAll(ids: string[]) - 批量选中指定节点们 +```typescript +/** +* 批量选中指定节点们 +* select node with ids, this will override current selection +* +* @param ids +*/ +selectAll(ids: string[]): void; +``` + ### remove -remove(id: string) - **取消选中**选中的指定节点,不会删除组件 +```typescript +/** +* 移除选中的指定节点 +* remove node from selection with node id +* @param id +*/ +remove(id: string): void; +``` + ### clear -clear() - **取消选中**所有选中节点,不会删除组件 +```typescript +/** +* 清除所有选中节点 +* clear current selection +*/ +clear(): void; +``` + ### has -has(id: string) - 判断是否选中了指定节点 +```typescript +/** +* 判断是否选中了指定节点 +* check if node with specific id is selected +* @param id +*/ +has(id: string): boolean; +``` + ### add -add(id: string) - 选中指定节点(增量方式) +```typescript +/** +* 选中指定节点(增量方式) +* add node with specific id to selection +* @param id +*/ +add(id: string): void; +``` + ### getNodes -getNodes() - 获取选中的节点实例 +```typescript +/** +* 获取选中的节点实例 +* get selected nodes +*/ +getNodes(): IPublicModelNode[]; +``` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + ### getTopNodes 获取选区的顶层节点 例如选中的节点为: @@ -67,19 +128,34 @@ getNodes() getNodes 返回的是 [DivA、ChildrenA、DivB],getTopNodes 返回的是 [DivA、DivB],其中 ChildrenA 由于是二层节点,getTopNodes 不会返回 +```typescript +/** +* 获取选区的顶层节点 +* get seleted top nodes +* for example: +* getNodes() returns [A, subA, B], then +* getTopNodes() will return [A, B], subA will be removed +* @since v1.0.16 +*/ +getTopNodes(includeRoot?: boolean): IPublicModelNode[]; +``` + **@since v1.0.16** +## 事件 ### onSelectionChange 注册 selection 变化事件回调 ```typescript /** - * 注册 selection 变化事件回调 - * set callback which will be called when selection is changed - * @since v1.1.0 - */ -onSelectionChange(fn: (ids: string[]) => void): () => void; +* 注册 selection 变化事件回调 +* set callback which will be called when selection is changed +* @since v1.1.0 +*/ +onSelectionChange(fn: (ids: string[]) => void): IPublicTypeDisposable; ``` +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + **@since v1.1.0** \ No newline at end of file diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index ffd0807ae..8bccde2ef 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -8,7 +8,6 @@ import { IPublicTypeDragNodeObject, IPublicTypeDragNodeDataObject, IPublicModelDocumentModel, - IPublicModelSelection, IPublicModelHistory, IPublicModelModalNodesManager, IPublicModelNode, @@ -22,7 +21,7 @@ import { ISimulatorHost } from '../simulator'; import { ComponentMeta } from '../component-meta'; import { IDropLocation, Designer } from '../designer'; import { Node, insertChildren, insertChild, isNode, RootNode, INode } from './node/node'; -import { Selection } from './selection'; +import { Selection, ISelection } from './selection'; import { History } from './history'; import { ModalNodesManager } from './node'; import { uniqueId, isPlainObject, compatStage, isJSExpression, isDOMText, isNodeSchema, isDragNodeObject, isDragNodeDataObject } from '@alilc/lowcode-utils'; @@ -35,10 +34,16 @@ export type GetDataType = T extends undefined ? R : any : T; -export interface IDocumentModel extends IPublicModelDocumentModel { + +export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'selection' > { readonly designer: Designer; + /** + * 选区控制 + */ + readonly selection: ISelection; + /** * 根据 id 获取节点 */ @@ -59,7 +64,7 @@ export class DocumentModel implements IDocumentModel { /** * 选区控制 */ - readonly selection: IPublicModelSelection = new Selection(this); + readonly selection: ISelection = new Selection(this); /** * 操作记录控制 @@ -489,7 +494,6 @@ export class DocumentModel implements IDocumentModel { ); } - /** * 切换激活,只有打开的才能激活 * 不激活,打开之后切换到另外一个时发生,比如 tab 视图,切换到另外一个标签页 diff --git a/packages/designer/src/document/selection.ts b/packages/designer/src/document/selection.ts index 22b8b4ecd..bcbf778ea 100644 --- a/packages/designer/src/document/selection.ts +++ b/packages/designer/src/document/selection.ts @@ -1,10 +1,20 @@ import { obx, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; -import { Node, comparePosition, PositionNO } from './node/node'; +import { Node, INode, comparePosition, PositionNO } from './node/node'; import { DocumentModel } from './document-model'; import { IPublicModelSelection } from '@alilc/lowcode-types'; -export interface ISelection extends IPublicModelSelection { +export interface ISelection extends Omit< IPublicModelSelection, 'getNodes' | 'getTopNodes' > { + /** + * 获取选中的节点实例 + * @returns + */ + getNodes(): INode[]; + + /** + * 获取顶层选区节点,场景:拖拽时,建立蒙层,只蒙在最上层 + */ + getTopNodes(includeRoot?: boolean): INode[]; } export class Selection implements ISelection { diff --git a/packages/shell/src/model/node.ts b/packages/shell/src/model/node.ts index eca07bb24..d9f86c8a8 100644 --- a/packages/shell/src/model/node.ts +++ b/packages/shell/src/model/node.ts @@ -19,12 +19,12 @@ import { IPublicModelSettingTopEntry, IPublicModelExclusiveGroup, } from '@alilc/lowcode-types'; -import { Prop } from './prop'; -import { Props } from './props'; -import { DocumentModel } from './document-model'; -import { NodeChildren } from './node-children'; -import { ComponentMeta } from './component-meta'; -import { SettingTopEntry } from './setting-top-entry'; +import { Prop as ShellProp } from './prop'; +import { Props as ShellProps } from './props'; +import { DocumentModel as ShellDocumentModel } from './document-model'; +import { NodeChildren as ShellNodeChildren } from './node-children'; +import { ComponentMeta as ShellComponentMeta } from './component-meta'; +import { SettingTopEntry as ShellSettingTopEntry } from './setting-top-entry'; import { documentSymbol, nodeSymbol } from '../symbols'; import { ReactElement } from 'react'; @@ -36,27 +36,6 @@ export class Node implements IPublicModelNode { private _id: string; - constructor(node: IPublicModelNode) { - this[nodeSymbol] = node; - this[documentSymbol] = node.document; - - this._id = this[nodeSymbol].id; - } - - static create(node: IPublicModelNode | null | undefined): IPublicModelNode | null { - if (!node) { - return null; - } - // @ts-ignore 直接返回已挂载的 shell node 实例 - if (node[shellNodeSymbol]) { - return (node as any)[shellNodeSymbol]; - } - const shellNode = new Node(node); - // @ts-ignore 挂载 shell node 实例 - node[shellNodeSymbol] = shellNode; - return shellNode; - } - /** * 节点 id */ @@ -257,7 +236,7 @@ export class Node implements IPublicModelNode { * 节点的物料元数据 */ get componentMeta(): IPublicModelComponentMeta | null { - return ComponentMeta.create(this[nodeSymbol].componentMeta); + return ShellComponentMeta.create(this[nodeSymbol].componentMeta); } /** @@ -265,7 +244,7 @@ export class Node implements IPublicModelNode { * @returns */ get document(): IPublicModelDocumentModel | null { - return DocumentModel.create(this[documentSymbol]); + return ShellDocumentModel.create(this[documentSymbol]); } /** @@ -297,7 +276,7 @@ export class Node implements IPublicModelNode { * @returns */ get children(): IPublicModelNodeChildren | null { - return NodeChildren.create(this[nodeSymbol].children); + return ShellNodeChildren.create(this[nodeSymbol].children); } /** @@ -311,14 +290,14 @@ export class Node implements IPublicModelNode { * 当前节点为插槽节点时,返回节点对应的属性实例 */ get slotFor(): IPublicModelProp | null { - return Prop.create(this[nodeSymbol].slotFor); + return ShellProp.create(this[nodeSymbol].slotFor); } /** * 返回节点的属性集 */ get props(): IPublicModelProps | null { - return Props.create(this[nodeSymbol].props); + return ShellProps.create(this[nodeSymbol].props); } /** @@ -336,7 +315,28 @@ export class Node implements IPublicModelNode { } get settingEntry(): IPublicModelSettingTopEntry { - return SettingTopEntry.create(this[nodeSymbol].settingEntry as any); + return ShellSettingTopEntry.create(this[nodeSymbol].settingEntry as any); + } + + constructor(node: IPublicModelNode) { + this[nodeSymbol] = node; + this[documentSymbol] = node.document; + + this._id = this[nodeSymbol].id; + } + + static create(node: InnerNode | null | undefined): IPublicModelNode | null { + if (!node) { + return null; + } + // @ts-ignore 直接返回已挂载的 shell node 实例 + if (node[shellNodeSymbol]) { + return (node as any)[shellNodeSymbol]; + } + const shellNode = new Node(node); + // @ts-ignore 挂载 shell node 实例 + node[shellNodeSymbol] = shellNode; + return shellNode; } /** @@ -445,7 +445,7 @@ export class Node implements IPublicModelNode { * @returns */ getProp(path: string, createIfNone = true): IPublicModelProp | null { - return Prop.create(this[nodeSymbol].getProp(path, createIfNone)); + return ShellProp.create(this[nodeSymbol].getProp(path, createIfNone)); } /** @@ -465,7 +465,7 @@ export class Node implements IPublicModelNode { * @returns */ getExtraProp(path: string, createIfNone?: boolean): IPublicModelProp | null { - return Prop.create(this[nodeSymbol].getExtraProp(path, createIfNone)); + return ShellProp.create(this[nodeSymbol].getExtraProp(path, createIfNone)); } /** @@ -591,12 +591,13 @@ export class Node implements IPublicModelNode { remove(): void { this[nodeSymbol].remove(); } + /** * @deprecated * 设置为磁贴布局节点 */ set isRGLContainer(flag: boolean) { - this[nodeSymbol].isRGLContainer = flag; + this[nodeSymbol].isRGLContainerNode = flag; } /** @@ -605,14 +606,14 @@ export class Node implements IPublicModelNode { * @returns Boolean */ get isRGLContainer() { - return this[nodeSymbol].isRGLContainer; + return this[nodeSymbol].isRGLContainerNode; } /** * 设置为磁贴布局节点 */ set isRGLContainerNode(flag: boolean) { - this[nodeSymbol].isRGLContainer = flag; + this[nodeSymbol].isRGLContainerNode = flag; } /** @@ -620,7 +621,7 @@ export class Node implements IPublicModelNode { * @returns Boolean */ get isRGLContainerNode() { - return this[nodeSymbol].isRGLContainer; + return this[nodeSymbol].isRGLContainerNode; } internalToShellNode() { diff --git a/packages/shell/src/model/selection.ts b/packages/shell/src/model/selection.ts index 92f0453ee..ff2124bec 100644 --- a/packages/shell/src/model/selection.ts +++ b/packages/shell/src/model/selection.ts @@ -1,19 +1,17 @@ import { - DocumentModel as InnerDocumentModel, - Node as InnerNode, - Selection as InnerSelection, + IDocumentModel as InnerDocumentModel, + INode as InnerNode, + ISelection as InnerSelection, } from '@alilc/lowcode-designer'; -import { Node } from './node'; -import { selectionSymbol, documentSymbol } from '../symbols'; -import { IPublicModelSelection, IPublicModelNode } from '@alilc/lowcode-types'; +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 [documentSymbol]: InnerDocumentModel; constructor(document: InnerDocumentModel) { this[selectionSymbol] = document.selection; - this[documentSymbol] = document; } /** @@ -83,8 +81,16 @@ export class Selection implements IPublicModelSelection { * 获取选中的节点实例 * @returns */ - getNodes(): Array { - return this[selectionSymbol].getNodes().map((node: InnerNode) => Node.create(node)); + getNodes(): IPublicModelNode[] { + const innerNodes = this[selectionSymbol].getNodes(); + const nodes: IPublicModelNode[] = []; + innerNodes.forEach((node: InnerNode) => { + const shellNode = ShellNode.create(node); + if (shellNode) { + nodes.push(shellNode); + } + }); + return nodes; } /** @@ -94,12 +100,19 @@ export class Selection implements IPublicModelSelection { * getTopNodes() will return [A, B], subA will be removed * @returns */ - getTopNodes(includeRoot: boolean = false): Array { - return this[selectionSymbol].getTopNodes(includeRoot).map((node: InnerNode) => Node.create(node)); + getTopNodes(includeRoot: boolean = false): IPublicModelNode[] { + const innerNodes = this[selectionSymbol].getTopNodes(includeRoot); + const nodes: IPublicModelNode[] = []; + innerNodes.forEach((node: InnerNode) => { + const shellNode = ShellNode.create(node); + if (shellNode) { + nodes.push(shellNode); + } + }); + return nodes; } - - onSelectionChange(fn: (ids: string[]) => void): () => void { + onSelectionChange(fn: (ids: string[]) => void): IPublicTypeDisposable { return this[selectionSymbol].onSelectionChange(fn); } } diff --git a/packages/types/src/shell/model/history.ts b/packages/types/src/shell/model/history.ts index eb183ab77..9d75295ab 100644 --- a/packages/types/src/shell/model/history.ts +++ b/packages/types/src/shell/model/history.ts @@ -40,7 +40,7 @@ export interface IPublicModelHistory { * | 1 | 1 | 1 | * | -------- | -------- | -------- | * | modified | redoable | undoable | - * eg: + * eg. * 7 means : modified && redoable && undoable * 5 means : modified && undoable */ diff --git a/packages/types/src/shell/model/selection.ts b/packages/types/src/shell/model/selection.ts index bfc0b75ce..3b2fdb2f5 100644 --- a/packages/types/src/shell/model/selection.ts +++ b/packages/types/src/shell/model/selection.ts @@ -1,66 +1,76 @@ import { IPublicModelNode } from './'; +import { IPublicTypeDisposable } from '../type'; export interface IPublicModelSelection { /** * 返回选中的节点 id + * get ids of selected nodes */ get selected(): string[]; /** - * return selected Node instance + * 返回选中的节点(如多个节点只返回第一个) + * return selected Node instance,return the first one if multiple nodes are selected + * @since v1.1.0 */ get node(): IPublicModelNode | null; /** * 选中指定节点(覆盖方式) + * select node with id, this will override current selection * @param id */ select(id: string): void; /** * 批量选中指定节点们 + * select node with ids, this will override current selection + * * @param ids */ selectAll(ids: string[]): void; /** * 移除选中的指定节点 + * remove node from selection with node id * @param id */ remove(id: string): void; /** * 清除所有选中节点 + * clear current selection */ clear(): void; /** * 判断是否选中了指定节点 + * check if node with specific id is selected * @param id - * @returns */ has(id: string): boolean; /** * 选中指定节点(增量方式) + * add node with specific id to selection * @param id */ add(id: string): void; /** * 获取选中的节点实例 - * @returns + * get selected nodes */ getNodes(): IPublicModelNode[]; /** * 获取选区的顶层节点 + * get seleted top nodes * for example: * getNodes() returns [A, subA, B], then * getTopNodes() will return [A, B], subA will be removed * @since v1.0.16 - * @returns */ getTopNodes(includeRoot?: boolean): IPublicModelNode[]; @@ -69,5 +79,5 @@ export interface IPublicModelSelection { * set callback which will be called when selection is changed * @since v1.1.0 */ - onSelectionChange(fn: (ids: string[]) => void): () => void; + onSelectionChange(fn: (ids: string[]) => void): IPublicTypeDisposable; } From 7d526d1e836356cc820a7c9aca5981929ced0793 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 10 Jan 2023 10:49:36 +0800 Subject: [PATCH 06/89] feat: modify the usage of resource registration --- docs/docs/api/model/resource-type.md | 26 -------- docs/docs/api/model/resource.md | 28 ++++++--- docs/docs/api/model/window.md | 8 +-- docs/docs/api/workspace.md | 4 +- packages/designer/src/designer/designer.ts | 51 ++++++++-------- packages/shell/src/api/workspace.ts | 6 +- packages/shell/src/model/index.ts | 3 +- packages/shell/src/model/resource-type.ts | 22 ------- packages/shell/src/model/resource.ts | 12 +++- packages/shell/src/model/window.ts | 10 ++-- packages/types/src/shell/api/workspace.ts | 19 +++--- packages/types/src/shell/model/index.ts | 1 - .../types/src/shell/model/resource-type.ts | 7 --- packages/types/src/shell/model/resource.ts | 8 ++- packages/types/src/shell/model/window.ts | 22 +++---- .../src/shell/type/editor-view-config.ts | 8 +++ packages/types/src/shell/type/editor-view.ts | 12 ++++ packages/types/src/shell/type/index.ts | 8 ++- .../types/src/shell/type/resource-list.ts | 10 ++++ .../types/src/shell/type/resource-options.ts | 56 ----------------- .../src/shell/type/resource-type-config.ts | 31 ++++++++++ .../types/src/shell/type/resource-type.ts | 10 ++++ packages/workspace/src/editor-view/context.ts | 42 ++++++------- .../workspace/src/editor-window/context.ts | 28 ++++----- packages/workspace/src/index.ts | 1 - packages/workspace/src/layouts/top-area.tsx | 4 +- packages/workspace/src/resource-type.ts | 53 +++------------- packages/workspace/src/resource.ts | 55 +++++++++++++++-- packages/workspace/src/workspace.ts | 60 ++++++++++--------- 29 files changed, 297 insertions(+), 308 deletions(-) delete mode 100644 docs/docs/api/model/resource-type.md delete mode 100644 packages/shell/src/model/resource-type.ts delete mode 100644 packages/types/src/shell/model/resource-type.ts create mode 100644 packages/types/src/shell/type/editor-view-config.ts create mode 100644 packages/types/src/shell/type/editor-view.ts create mode 100644 packages/types/src/shell/type/resource-list.ts delete mode 100644 packages/types/src/shell/type/resource-options.ts create mode 100644 packages/types/src/shell/type/resource-type-config.ts create mode 100644 packages/types/src/shell/type/resource-type.ts diff --git a/docs/docs/api/model/resource-type.md b/docs/docs/api/model/resource-type.md deleted file mode 100644 index 327788ce3..000000000 --- a/docs/docs/api/model/resource-type.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: ResourceType -sidebar_position: 12 ---- - -> **[@experimental](./#experimental)**
-> **@types** [IPublicModelWindow](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/resource-type.ts)
-> **@since** v1.1.0 - -## 变量 - -### description - -资源描述 - -`@type {string}` - -### icon - -资源 icon - -`@type {ReactElement}` - -### name - -`@type {string}` diff --git a/docs/docs/api/model/resource.md b/docs/docs/api/model/resource.md index fb3e8a6d8..33a6e3119 100644 --- a/docs/docs/api/model/resource.md +++ b/docs/docs/api/model/resource.md @@ -15,6 +15,24 @@ sidebar_position: 12 `@type {string}` +### name + +资源名字 + +`@type {string}` + +### type + +资源类型 + +`@type {string}` + +### category + +资源分类 + +`@type {string}` + ### icon 资源 icon @@ -25,12 +43,4 @@ sidebar_position: 12 资源配置信息 -`@type {Object}` - -### resourceType - -资源所属的资源类型 - -`@type {IPublicModelResourceType}` - -关联模型 [IPublicModelResourceType](./resource-type) +`@type {Object}` \ No newline at end of file diff --git a/docs/docs/api/model/window.md b/docs/docs/api/model/window.md index 9d96f20a8..f70c33e4d 100644 --- a/docs/docs/api/model/window.md +++ b/docs/docs/api/model/window.md @@ -30,13 +30,13 @@ sidebar_position: 12 `@type {ReactElement}` -### resourceType +### resource -窗口资源类型 +窗口对应资源 -`@type {IPublicModelResourceType}` +`@type {IPublicModelResource}` -关联模型 [IPublicModelResourceType](./resource-type) +关联模型 [IPublicModelResource](./resource) ## 方法签名 diff --git a/docs/docs/api/workspace.md b/docs/docs/api/workspace.md index bf0755537..138693cfa 100644 --- a/docs/docs/api/workspace.md +++ b/docs/docs/api/workspace.md @@ -64,10 +64,10 @@ get resourceList(): IPublicModelResource; ```typescript /** 注册资源 */ -registerResourceType(name: string, type: 'editor', options: IPublicResourceOptions): void; +registerResourceType(resourceTypeModel: IPublicTypeResourceType): void; ``` -相关类型:[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts) +相关类型:[IPublicTypeResourceType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-type.ts) ### onChangeWindows diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index bf98a812a..6e4b3c63e 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -39,12 +39,14 @@ import { ComponentActions } from '../component-actions'; const logger = new Logger({ level: 'warn', bizName: 'designer' }); export interface DesignerProps { + [key: string]: any; editor: IPublicModelEditor; shellModelFactory: IShellModelFactory; className?: string; style?: object; defaultSchema?: IPublicTypeProjectSchema; hotkeys?: object; + viewName?: string; simulatorProps?: object | ((document: DocumentModel) => object); simulatorComponent?: ComponentType; dragGhostComponent?: ComponentType; @@ -55,8 +57,6 @@ export interface DesignerProps { onDragstart?: (e: ILocateEvent) => void; onDrag?: (e: ILocateEvent) => void; onDragend?: (e: { dragObject: IPublicModelDragObject; copy: boolean }, loc?: DropLocation) => void; - viewName?: string; - [key: string]: any; } export interface IDesigner { @@ -71,7 +71,9 @@ export interface IDesigner { } export class Designer implements IDesigner { - dragon: Dragon; + public dragon: Dragon; + + public viewName: string | undefined; readonly componentActions = new ComponentActions(); @@ -87,6 +89,24 @@ export class Designer implements IDesigner { readonly shellModelFactory: IShellModelFactory; + private _dropLocation?: DropLocation; + + private propsReducers = new Map(); + + private _lostComponentMetasMap = new Map(); + + private props?: DesignerProps; + + private oobxList: OffsetObserver[] = []; + + @obx.ref private _componentMetasMap = new Map(); + + @obx.ref private _simulatorComponent?: ComponentType; + + @obx.ref private _simulatorProps?: object | ((project: Project) => object); + + @obx.ref private _suspensed = false; + get currentDocument() { return this.project.currentDocument; } @@ -99,8 +119,6 @@ export class Designer implements IDesigner { return this.currentDocument?.selection; } - viewName: string | undefined; - constructor(props: DesignerProps) { makeObservable(this); const { editor, viewName, shellModelFactory } = props; @@ -234,8 +252,6 @@ export class Designer implements IDesigner { this.editor.eventBus.emit(`designer.${event}`, ...args); } - private _dropLocation?: DropLocation; - get dropLocation() { return this._dropLocation; } @@ -270,8 +286,6 @@ export class Designer implements IDesigner { return new Scroller(scrollable); } - private oobxList: OffsetObserver[] = []; - createOffsetObserver(nodeInstance: INodeSelector): OffsetObserver | null { const oobx = createOffsetObserver(nodeInstance); this.clearOobxList(); @@ -342,8 +356,6 @@ export class Designer implements IDesigner { return { target, index }; } - private props?: DesignerProps; - setProps(nextProps: DesignerProps) { const props = this.props ? { ...this.props, ...nextProps } : nextProps; if (this.props) { @@ -421,14 +433,10 @@ export class Designer implements IDesigner { return this.props?.[key]; } - @obx.ref private _simulatorComponent?: ComponentType; - @computed get simulatorComponent(): ComponentType | undefined { return this._simulatorComponent; } - @obx.ref private _simulatorProps?: object | ((project: Project) => object); - @computed get simulatorProps(): object { if (typeof this._simulatorProps === 'function') { return this._simulatorProps(this.project); @@ -451,8 +459,6 @@ export class Designer implements IDesigner { }; } - @obx.ref private _suspensed = false; - get suspensed(): boolean { return this._suspensed; } @@ -473,16 +479,15 @@ export class Designer implements IDesigner { this.project.load(schema); } - @obx.ref private _componentMetasMap = new Map(); - - private _lostComponentMetasMap = new Map(); - buildComponentMetasMap(metas: IPublicTypeComponentMetadata[]) { metas.forEach((data) => this.createComponentMeta(data)); } - createComponentMeta(data: IPublicTypeComponentMetadata): ComponentMeta { + createComponentMeta(data: IPublicTypeComponentMetadata): ComponentMeta | null { const key = data.componentName; + if (!key) { + return null; + } let meta = this._componentMetasMap.get(key); if (meta) { meta.setMetadata(data); @@ -552,8 +557,6 @@ export class Designer implements IDesigner { return maps; } - private propsReducers = new Map(); - transformProps(props: IPublicTypeCompositeObject | IPublicTypePropsList, node: Node, stage: IPublicEnumTransformStage) { if (Array.isArray(props)) { // current not support, make this future diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index 09e1b4ca6..f32b403b1 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -1,4 +1,4 @@ -import { IPublicApiWorkspace, IPublicResourceList, IPublicResourceOptions } from '@alilc/lowcode-types'; +import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types'; import { Workspace as InnerWorkSpace } from '@alilc/lowcode-workspace'; import { Plugins } from '@alilc/lowcode-shell'; import { Window } from '../model/window'; @@ -32,8 +32,8 @@ export class Workspace implements IPublicApiWorkspace { return new Window(this[workspaceSymbol].window); } - registerResourceType(name: string, type: 'editor', options: IPublicResourceOptions): void { - this[workspaceSymbol].registerResourceType(name, type, options); + registerResourceType(resourceTypeModel: IPublicTypeResourceType): void { + this[workspaceSymbol].registerResourceType(resourceTypeModel); } openEditorWindow(resourceName: string, title: string, extra: Object, viewName?: string) { diff --git a/packages/shell/src/model/index.ts b/packages/shell/src/model/index.ts index 5f5e50220..d0e45cc94 100644 --- a/packages/shell/src/model/index.ts +++ b/packages/shell/src/model/index.ts @@ -14,5 +14,4 @@ export * from './props'; export * from './selection'; export * from './setting-prop-entry'; export * from './setting-top-entry'; -export * from './resource'; -export * from './resource-type'; \ No newline at end of file +export * from './resource'; \ No newline at end of file diff --git a/packages/shell/src/model/resource-type.ts b/packages/shell/src/model/resource-type.ts deleted file mode 100644 index b5ed549f1..000000000 --- a/packages/shell/src/model/resource-type.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { IPublicModelResourceType } from '@alilc/lowcode-types'; -import { ResourceType as InnerResourceType } from '@alilc/lowcode-workspace'; -import { resourceTypeSymbol } from '../symbols'; - -export class ResourceType implements IPublicModelResourceType { - readonly [resourceTypeSymbol]: InnerResourceType; - constructor(resourceType: InnerResourceType) { - this[resourceTypeSymbol] = resourceType; - } - - get name() { - return this[resourceTypeSymbol].name; - } - - get description() { - return this[resourceTypeSymbol].options.description; - } - - get icon() { - return this[resourceTypeSymbol].options.icon; - } -} \ No newline at end of file diff --git a/packages/shell/src/model/resource.ts b/packages/shell/src/model/resource.ts index df8190549..0ca3f2445 100644 --- a/packages/shell/src/model/resource.ts +++ b/packages/shell/src/model/resource.ts @@ -22,7 +22,15 @@ export class Resource implements IPublicModelResource { return this[resourceSymbol].options; } - get resourceType() { - return new ResourceType(this[resourceSymbol].resourceType); + get name() { + return this[resourceSymbol].resourceType.name; + } + + get type() { + return this[resourceSymbol].resourceType.type; + } + + get category() { + return this[resourceSymbol].category; } } \ No newline at end of file diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index fcb282490..8645e3e09 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -1,13 +1,13 @@ import { windowSymbol } from '../symbols'; -import { IPublicModelWindow } from '@alilc/lowcode-types'; +import { IPublicModelResource, IPublicModelWindow } from '@alilc/lowcode-types'; import { EditorWindow } from '@alilc/lowcode-workspace'; -import { ResourceType } from './resource-type'; +import { Resource } from './resource'; export class Window implements IPublicModelWindow { private readonly [windowSymbol]: EditorWindow; get id() { - return this[windowSymbol].id; + return this[windowSymbol]?.id; } get title() { @@ -18,8 +18,8 @@ export class Window implements IPublicModelWindow { return this[windowSymbol].icon; } - get resourceType(): ResourceType { - return new ResourceType(this[windowSymbol].resourceType); + get resource(): IPublicModelResource { + return new Resource(this[windowSymbol].resource); } constructor(editorWindow: EditorWindow) { diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index 165565fe7..ca4b3cc34 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -1,6 +1,5 @@ import { IPublicModelWindow } from '../model'; -import { IPublicResourceOptions } from '../type'; -import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList } from '@alilc/lowcode-types'; +import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types'; export interface IPublicApiWorkspace { @@ -10,6 +9,11 @@ export interface IPublicApiWorkspace { /** 当前设计器窗口 */ window: IPublicModelWindow; + plugins: IPublicApiPlugins; + + /** 当前设计器的编辑窗口 */ + windows: IPublicModelWindow[]; + /** 获取资源树列表 */ get resourceList(): IPublicModelResource[]; @@ -20,7 +24,7 @@ export interface IPublicApiWorkspace { onResourceListChange(fn: (resourceList: IPublicResourceList) => void): () => void; /** 注册资源 */ - registerResourceType(resourceName: string, type: 'editor', options: IPublicResourceOptions): void; + registerResourceType(resourceTypeModel: IPublicTypeResourceType): void; /** 打开视图窗口 */ openEditorWindow(resourceName: string, title: string, extra: Object, viewName?: string): void; @@ -34,14 +38,9 @@ export interface IPublicApiWorkspace { /** 通过视图 id 移除窗口 */ removeEditorWindowById(id: string): void; - plugins: IPublicApiPlugins; - - /** 当前设计器的编辑窗口 */ - windows: IPublicModelWindow[]; - /** 窗口新增/删除的事件 */ - onChangeWindows: (fn: () => void) => void; + onChangeWindows(fn: () => void): void; /** active 窗口变更事件 */ - onChangeActiveWindow: (fn: () => void) => void; + onChangeActiveWindow(fn: () => void): void; } \ 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 669fdfc99..e59216faa 100644 --- a/packages/types/src/shell/model/index.ts +++ b/packages/types/src/shell/model/index.ts @@ -28,5 +28,4 @@ export * from './editor'; export * from './preference'; export * from './plugin-instance'; export * from './sensor'; -export * from './resource-type'; export * from './resource'; \ No newline at end of file diff --git a/packages/types/src/shell/model/resource-type.ts b/packages/types/src/shell/model/resource-type.ts deleted file mode 100644 index e8031145e..000000000 --- a/packages/types/src/shell/model/resource-type.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ReactElement } from 'react'; - -export interface IPublicModelResourceType { - get description(): string | undefined; - - get icon(): ReactElement | undefined; -} \ No newline at end of file diff --git a/packages/types/src/shell/model/resource.ts b/packages/types/src/shell/model/resource.ts index 23dbfb50f..cfa48f189 100644 --- a/packages/types/src/shell/model/resource.ts +++ b/packages/types/src/shell/model/resource.ts @@ -2,11 +2,15 @@ import { ReactElement } from 'react'; import { IPublicModelResourceType } from './resource-type'; export interface IPublicModelResource { - get title(): string; + get title(): string | undefined; get icon(): ReactElement | undefined; get options(): Object; - get resourceType(): IPublicModelResourceType | undefined; + get name(): string | undefined; + + get type(): string | undefined; + + get category(): string | undefined; } \ No newline at end of file diff --git a/packages/types/src/shell/model/window.ts b/packages/types/src/shell/model/window.ts index 7a12fc8e6..741ac1c8e 100644 --- a/packages/types/src/shell/model/window.ts +++ b/packages/types/src/shell/model/window.ts @@ -1,18 +1,9 @@ import { ReactElement } from 'react'; import { IPublicTypeNodeSchema } from '../type'; -import { IPublicModelResourceType } from './resource-type'; +import { IPublicModelResource } from './resource'; export interface IPublicModelWindow { - /** 当前窗口导入 schema */ - importSchema(schema: IPublicTypeNodeSchema): void; - - /** 修改当前窗口视图类型 */ - changeViewType(viewName: string): void; - - /** 调用当前窗口视图保存钩子 */ - save(): Promise; - /** 窗口 id */ id: string; @@ -23,5 +14,14 @@ export interface IPublicModelWindow { icon?: ReactElement; /** 窗口资源类型 */ - resourceType?: IPublicModelResourceType; + resource?: IPublicModelResource; + + /** 当前窗口导入 schema */ + importSchema(schema: IPublicTypeNodeSchema): void; + + /** 修改当前窗口视图类型 */ + changeViewType(viewName: string): void; + + /** 调用当前窗口视图保存钩子 */ + save(): Promise; } \ No newline at end of file diff --git a/packages/types/src/shell/type/editor-view-config.ts b/packages/types/src/shell/type/editor-view-config.ts new file mode 100644 index 000000000..2b36a718a --- /dev/null +++ b/packages/types/src/shell/type/editor-view-config.ts @@ -0,0 +1,8 @@ +export interface IPublicEditorViewConfig { + + /** 视图初始化钩子 */ + init?: () => Promise; + + /** 资源保存时,会调用视图的钩子 */ + save?: () => Promise; +} \ No newline at end of file diff --git a/packages/types/src/shell/type/editor-view.ts b/packages/types/src/shell/type/editor-view.ts new file mode 100644 index 000000000..2357a48f5 --- /dev/null +++ b/packages/types/src/shell/type/editor-view.ts @@ -0,0 +1,12 @@ +import { IPublicEditorViewConfig } from './editor-view-config'; + +export interface IPublicTypeEditorView { + + /** 资源名字 */ + viewName: string; + + /** 资源类型 */ + viewType?: 'editor' | 'webview'; + + (ctx: any, options: any): IPublicEditorViewConfig; +} \ 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 9a44dade4..f66094f3d 100644 --- a/packages/types/src/shell/type/index.ts +++ b/packages/types/src/shell/type/index.ts @@ -73,7 +73,7 @@ export * from './tip-config'; export * from './widget-config-area'; export * from './hotkey-callback'; export * from './plugin-register-options'; -export * from './resource-options'; +export * from './resource-list'; export * from './engine-options'; export * from './on-change-options'; export * from './slot-schema'; @@ -82,4 +82,8 @@ export * from './node-instance'; export * from './editor-value-key'; export * from './editor-get-options'; export * from './editor-get-result'; -export * from './editor-register-options'; \ No newline at end of file +export * from './editor-register-options'; +export * from './editor-view'; +export * from './resource-type'; +export * from './resource-type-config'; +export * from './editor-view-config'; \ No newline at end of file diff --git a/packages/types/src/shell/type/resource-list.ts b/packages/types/src/shell/type/resource-list.ts new file mode 100644 index 000000000..e5fbcba7e --- /dev/null +++ b/packages/types/src/shell/type/resource-list.ts @@ -0,0 +1,10 @@ +export interface IPublicResourceData { + resourceName: string; + title: string; + category: string; + options: { + [key: string]: any; + }; +} + +export type IPublicResourceList = IPublicResourceData[]; \ No newline at end of file diff --git a/packages/types/src/shell/type/resource-options.ts b/packages/types/src/shell/type/resource-options.ts deleted file mode 100644 index 4954aa7fa..000000000 --- a/packages/types/src/shell/type/resource-options.ts +++ /dev/null @@ -1,56 +0,0 @@ -export interface IPublicViewFunctions { - - /** 视图初始化钩子 */ - init?: () => Promise; - - /** 资源保存时,会调用视图的钩子 */ - save?: () => Promise; -} - -export interface IPublicEditorView { - - /** 资源名字 */ - viewName: string; - - /** 资源类型 */ - viewType?: 'editor' | 'webview'; - (ctx: any, options: any): IPublicViewFunctions; -} - -export interface IPublicResourceOptions { - - /** 资源描述 */ - description?: string; - - /** 资源 icon 标识 */ - icon?: React.ReactElement; - - /** 默认视图类型 */ - defaultViewType: string; - - /** 资源视图 */ - editorViews: IPublicEditorView[]; - - /** save 钩子 */ - save?: (schema: { - [viewName: string]: any; - }) => Promise; - - /** import 钩子 */ - import?: (schema: any) => Promise<{ - [viewName: string]: any; - }>; - - /** 默认标题 */ - defaultTitle?: string; -} - -export interface IPublicResourceData { - resourceName: string; - title: string; - options: { - [key: string]: any; - }; -} - -export type IPublicResourceList = IPublicResourceData[]; \ No newline at end of file diff --git a/packages/types/src/shell/type/resource-type-config.ts b/packages/types/src/shell/type/resource-type-config.ts new file mode 100644 index 000000000..93534fea2 --- /dev/null +++ b/packages/types/src/shell/type/resource-type-config.ts @@ -0,0 +1,31 @@ +import { IPublicTypeEditorView } from './editor-view'; + +export interface IPublicResourceTypeConfig { + + /** 资源描述 */ + description?: string; + + /** 资源 icon 标识 */ + icon?: React.ReactElement; + + /** 默认视图类型 */ + defaultViewType: string; + + /** 资源视图 */ + editorViews: IPublicTypeEditorView[]; + + init?: () => void; + + /** save 钩子 */ + save?: (schema: { + [viewName: string]: any; + }) => Promise; + + /** import 钩子 */ + import?: (schema: any) => Promise<{ + [viewName: string]: any; + }>; + + /** 默认标题 */ + defaultTitle?: string; +} diff --git a/packages/types/src/shell/type/resource-type.ts b/packages/types/src/shell/type/resource-type.ts new file mode 100644 index 000000000..64ec85c79 --- /dev/null +++ b/packages/types/src/shell/type/resource-type.ts @@ -0,0 +1,10 @@ +import { IPublicModelPluginContext } from '../model'; +import { IPublicResourceTypeConfig } from './resource-type-config'; + +export interface IPublicTypeResourceType { + resourceName: string; + + resourceType: string; + + (ctx: IPublicModelPluginContext): IPublicResourceTypeConfig; +} \ No newline at end of file diff --git a/packages/workspace/src/editor-view/context.ts b/packages/workspace/src/editor-view/context.ts index 12e63b255..b991532fb 100644 --- a/packages/workspace/src/editor-view/context.ts +++ b/packages/workspace/src/editor-view/context.ts @@ -1,5 +1,5 @@ import { makeObservable, obx } from '@alilc/lowcode-editor-core'; -import { IPublicEditorView, IPublicViewFunctions } from '@alilc/lowcode-types'; +import { IPublicEditorViewConfig, IPublicTypeEditorView } from '@alilc/lowcode-types'; import { flow } from 'mobx'; import { Workspace as InnerWorkspace } from '../workspace'; import { BasicContext } from '../base-context'; @@ -9,31 +9,12 @@ import { getWebviewPlugin } from '../inner-plugins/webview'; export class Context extends BasicContext { viewName = 'editor-view'; - instance: IPublicViewFunctions; + instance: IPublicEditorViewConfig; viewType: 'editor' | 'webview'; - constructor(public workspace: InnerWorkspace, public editorWindow: EditorWindow, public editorView: IPublicEditorView, options: Object) { - super(workspace, editorView.viewName, editorWindow); - this.viewType = editorView.viewType || 'editor'; - this.viewName = editorView.viewName; - this.instance = editorView(this.innerPlugins._getLowCodePluginContext({ - pluginName: 'any', - }), options); - makeObservable(this); - } - @obx _activate = false; - setActivate = (_activate: boolean) => { - this._activate = _activate; - this.innerHotkey.activate(this._activate); - }; - - get active() { - return this._activate; - } - @obx isInit: boolean = false; init = flow(function* (this: any) { @@ -48,6 +29,25 @@ export class Context extends BasicContext { this.isInit = true; }); + constructor(public workspace: InnerWorkspace, public editorWindow: EditorWindow, public editorView: IPublicTypeEditorView, options: Object) { + super(workspace, editorView.viewName, editorWindow); + this.viewType = editorView.viewType || 'editor'; + this.viewName = editorView.viewName; + this.instance = editorView(this.innerPlugins._getLowCodePluginContext({ + pluginName: 'any', + }), options); + makeObservable(this); + } + + setActivate = (_activate: boolean) => { + this._activate = _activate; + this.innerHotkey.activate(this._activate); + }; + + get active() { + return this._activate; + } + async save() { return await this.instance?.save?.(); } diff --git a/packages/workspace/src/editor-window/context.ts b/packages/workspace/src/editor-window/context.ts index 5e3fb172f..680647587 100644 --- a/packages/workspace/src/editor-window/context.ts +++ b/packages/workspace/src/editor-window/context.ts @@ -2,20 +2,24 @@ import { uniqueId } from '@alilc/lowcode-utils'; import { makeObservable, obx } from '@alilc/lowcode-editor-core'; import { Context } from '../editor-view/context'; import { Workspace } from '../workspace'; -import { ResourceType } from '../resource-type'; +import { Resource } from '../resource'; export class EditorWindow { id: string = uniqueId('window'); icon: React.ReactElement | undefined; - constructor(readonly resourceType: ResourceType, readonly workspace: Workspace, public title: string | undefined = '', private options: Object = {}) { + @obx.ref editorView: Context; + + @obx editorViews: Map = new Map(); + + constructor(readonly resource: Resource, readonly workspace: Workspace, public title: string | undefined = '', private options: Object = {}) { makeObservable(this); this.init(); - this.icon = resourceType.icon; + this.icon = resource.icon; } async importSchema(schema: any) { - const newSchema = await this.resourceType.import(schema); + const newSchema = await this.resource.import(schema); if (!newSchema) { return; @@ -29,13 +33,13 @@ export class EditorWindow { async save() { const value: any = {}; - const editorViews = this.resourceType.editorViews; + const editorViews = this.resource.editorViews; for (let i = 0; i < editorViews.length; i++) { const name = editorViews[i].viewName; const saveResult = await this.editorViews.get(name)?.save(); value[name] = saveResult; } - return await this.resourceType.save(value); + return await this.resource.save(value); } async init() { @@ -45,7 +49,7 @@ export class EditorWindow { } initViewTypes = async () => { - const editorViews = this.resourceType.editorViews; + const editorViews = this.resource.editorViews; for (let i = 0; i < editorViews.length; i++) { const name = editorViews[i].viewName; await this.initViewType(name); @@ -56,7 +60,7 @@ export class EditorWindow { }; execViewTypesInit = async () => { - const editorViews = this.resourceType.editorViews; + const editorViews = this.resource.editorViews; for (let i = 0; i < editorViews.length; i++) { const name = editorViews[i].viewName; this.changeViewType(name); @@ -65,15 +69,11 @@ export class EditorWindow { }; setDefaultViewType = () => { - this.changeViewType(this.resourceType.defaultViewType); + this.changeViewType(this.resource.defaultViewType); }; - @obx.ref editorView: Context; - - @obx editorViews: Map = new Map(); - initViewType = async (name: string) => { - const viewInfo = this.resourceType.getEditorView(name); + const viewInfo = this.resource.getEditorView(name); if (this.editorViews.get(name)) { return; } diff --git a/packages/workspace/src/index.ts b/packages/workspace/src/index.ts index 8c71771a9..2f6da97a8 100644 --- a/packages/workspace/src/index.ts +++ b/packages/workspace/src/index.ts @@ -1,5 +1,4 @@ export { Workspace } from './workspace'; -export { ResourceType } from './resource-type'; export * from './editor-window/context'; export * from './layouts/workbench'; export { Resource } from './resource'; diff --git a/packages/workspace/src/layouts/top-area.tsx b/packages/workspace/src/layouts/top-area.tsx index 457e928d2..cecaee2a7 100644 --- a/packages/workspace/src/layouts/top-area.tsx +++ b/packages/workspace/src/layouts/top-area.tsx @@ -48,9 +48,7 @@ class Contents extends Component<{ area: Area; itemClassName?: string }> { right.push(content); } }); - if (!center || !center.length) { - return null; - } + return (
{left}
diff --git a/packages/workspace/src/resource-type.ts b/packages/workspace/src/resource-type.ts index 60a2832ee..b52183068 100644 --- a/packages/workspace/src/resource-type.ts +++ b/packages/workspace/src/resource-type.ts @@ -1,53 +1,14 @@ -import { IPublicEditorView, IPublicModelResourceType, IPublicResourceOptions } from '@alilc/lowcode-types'; +import { IPublicTypeResourceType } from '@alilc/lowcode-types'; -export class ResourceType implements IPublicModelResourceType { - constructor(readonly name: string, readonly type: 'editor' | 'webview', options: IPublicResourceOptions) { - if (options.editorViews) { - options.editorViews.forEach((d: any) => { - this.editorViewMap.set(d.viewName, d); - }); - } - - this.options = options; +export class ResourceType { + constructor(readonly resourceTypeModel: IPublicTypeResourceType) { } - get description() { - return this.options.description; + get name() { + return this.resourceTypeModel.resourceName; } - options: IPublicResourceOptions; - - editorViewMap: Map = new Map(); - - init(ctx: any) { - this.options.init(ctx); - } - - get icon() { - return this.options.icon; - } - - async import(schema: any) { - return await this.options.import?.(schema); - } - - getEditorView(name: string) { - return this.editorViewMap.get(name); - } - - get defaultViewType() { - return this.options.defaultViewType || this.editorViewMap.keys().next().value; - } - - get editorViews() { - return Array.from(this.editorViewMap.values()); - } - - async save(value: any) { - return await this.options.save?.(value); - } - - get title() { - return this.options.defaultTitle; + get type() { + return this.resourceTypeModel.resourceType; } } \ No newline at end of file diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index 5c44785ce..9753339f0 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -1,29 +1,72 @@ -import { IPublicModelResource, IPublicResourceData } from '@alilc/lowcode-types'; +import { IPublicTypeEditorView, IPublicModelResource, IPublicResourceData, IPublicResourceTypeConfig } from '@alilc/lowcode-types'; import { Logger } from '@alilc/lowcode-utils'; +import { BasicContext } from './base-context'; import { ResourceType } from './resource-type'; +import { Workspace as InnerWorkSpace } from './workspace'; const logger = new Logger({ level: 'warn', bizName: 'workspace:resource' }); export class Resource implements IPublicModelResource { - constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType) { + resourceTypeInstance: IPublicResourceTypeConfig; + + editorViewMap: Map = new Map(); + + constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, workspace: InnerWorkSpace) { + this.resourceTypeInstance = resourceType.resourceTypeModel(new BasicContext(workspace, ''), {}); + if (this.resourceTypeInstance.editorViews) { + this.resourceTypeInstance.editorViews.forEach((d: any) => { + this.editorViewMap.set(d.viewName, d); + }); + } if (!resourceType) { logger.error(`resourceType[${resourceType}] is unValid.`); } } + get name() { + return this.resourceType.name; + } + + get description() { + return this.resourceTypeInstance?.description; + } + get icon() { - return this.resourceType?.icon; + return this.resourceTypeInstance?.icon; } get type() { - return this.resourceData.resourceName; + return this.resourceType.type; } - get title() { - return this.resourceData.title; + get title(): string | undefined { + return this.resourceData.title || this.resourceTypeInstance.defaultTitle; } get options() { return this.resourceData.options; } + + get category() { + return this.resourceData?.category; + } + + async import(schema: any) { + return await this.resourceTypeInstance.import?.(schema); + } + async save(value: any) { + return await this.resourceTypeInstance.save?.(value); + } + + get editorViews() { + return this.resourceTypeInstance.editorViews; + } + + get defaultViewType() { + return this.resourceTypeInstance.defaultViewType; + } + + getEditorView(name: string) { + return this.editorViewMap.get(name); + } } \ No newline at end of file diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index ca7265cb3..c4462a71a 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -1,7 +1,7 @@ import { Designer } from '@alilc/lowcode-designer'; import { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; import { Plugins } from '@alilc/lowcode-shell'; -import { IPublicApiWorkspace, IPublicResourceList, IPublicResourceOptions } from '@alilc/lowcode-types'; +import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types'; import { BasicContext } from './base-context'; import { EditorWindow } from './editor-window/context'; import { Resource } from './resource'; @@ -16,7 +16,7 @@ enum event { const CHANGE_EVENT = 'resource.list.change'; export class Workspace implements IPublicApiWorkspace { - private context: BasicContext; + context: BasicContext; private emitter: IEventBus = createModuleEventBus('workspace'); @@ -28,6 +28,18 @@ export class Workspace implements IPublicApiWorkspace { return this.context.innerPlugins; } + private _isActive = false; + + windows: EditorWindow[] = []; + + editorWindowMap: Map = new Map(); + + @obx.ref window: EditorWindow; + + private resourceTypeMap: Map = new Map(); + + private resourceList: Resource[] = []; + constructor( readonly registryInnerPlugin: (designer: Designer, editor: Editor, plugins: Plugins) => Promise, readonly shellModelFactory: any, @@ -42,19 +54,18 @@ export class Workspace implements IPublicApiWorkspace { } initWindow() { - if (!this.defaultResource) { + if (!this.defaultResourceType) { return; } - const title = this.defaultResource.description; - this.window = new EditorWindow(this.defaultResource, this, title); + const title = this.defaultResourceType.name; + const resource = new Resource({}, this.defaultResourceType, this); + this.window = new EditorWindow(resource, this, title); this.editorWindowMap.set(this.window.id, this.window); this.windows.push(this.window); this.emitChangeWindow(); this.emitChangeActiveWindow(); } - private _isActive = false; - get isActive() { return this._isActive; } @@ -63,22 +74,12 @@ export class Workspace implements IPublicApiWorkspace { this._isActive = value; } - windows: EditorWindow[] = []; + async registerResourceType(resourceTypeModel: IPublicTypeResourceType): Promise { + if (resourceTypeModel.resourceType === 'editor') { + const resourceType = new ResourceType(resourceTypeModel); + this.resourceTypeMap.set(resourceTypeModel.resourceName, resourceType); - editorWindowMap: Map = new Map(); - - @obx.ref window: EditorWindow; - - private resourceTypeMap: Map = new Map(); - - private resourceList: Resource[] = []; - - async registerResourceType(resourceName: string, type: 'editor' | 'webview', options: IPublicResourceOptions): Promise { - if (type === 'editor') { - const resourceType = new ResourceType(resourceName, type, options); - this.resourceTypeMap.set(resourceName, resourceType); - - if (!this.window && this.defaultResource) { + if (!this.window && this.defaultResourceType) { this.initWindow(); } } @@ -89,7 +90,7 @@ export class Workspace implements IPublicApiWorkspace { } setResourceList(resourceList: IPublicResourceList) { - this.resourceList = resourceList.map(d => new Resource(d, this.getResourceType(d.resourceName))); + this.resourceList = resourceList.map(d => new Resource(d, this.getResourceType(d.resourceName), this)); this.emitter.emit(CHANGE_EVENT, resourceList); } @@ -104,9 +105,9 @@ export class Workspace implements IPublicApiWorkspace { return this.resourceTypeMap.get(resourceName)!; } - get defaultResource(): ResourceType | null { - if (this.resourceTypeMap.size > 1) { - return this.resourceTypeMap.values().next().value; + get defaultResourceType(): ResourceType | null { + if (this.resourceTypeMap.size >= 1) { + return Array.from(this.resourceTypeMap.values())[0]; } return null; @@ -134,7 +135,7 @@ export class Workspace implements IPublicApiWorkspace { } removeEditorWindow(resourceName: string, title: string) { - const index = this.windows.findIndex(d => (d.resourceType.name === resourceName && d.title)); + const index = this.windows.findIndex(d => (d.resource.name === resourceName && d.title)); this.remove(index); } @@ -152,13 +153,14 @@ export class Workspace implements IPublicApiWorkspace { console.error(`${name} is not available`); return; } - const filterWindows = this.windows.filter(d => (d.resourceType.name === name && d.title == title)); + const filterWindows = this.windows.filter(d => (d.resource.name === name && d.title == title)); if (filterWindows && filterWindows.length) { this.window = filterWindows[0]; this.emitChangeActiveWindow(); return; } - this.window = new EditorWindow(resourceType, this, title, options); + const resource = new Resource({}, resourceType, this); + this.window = new EditorWindow(resource, this, title, options); this.windows.push(this.window); this.editorWindowMap.set(this.window.id, this.window); this.emitChangeWindow(); From e5bfc58be8c01445a376cb1212f07122dfe5d1b8 Mon Sep 17 00:00:00 2001 From: JackLian Date: Wed, 11 Jan 2023 10:06:42 +0800 Subject: [PATCH 07/89] docs: optimize api doc for model/modal-node-manager, and fix related lint issues --- docs/docs/api/canvas.md | 2 +- docs/docs/api/common.md | 2 +- docs/docs/api/config.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/detecting.md | 4 +- docs/docs/api/model/document-model.md | 4 +- docs/docs/api/model/dragon.md | 4 +- docs/docs/api/model/drop-location.md | 4 +- docs/docs/api/model/history.md | 2 +- docs/docs/api/model/modal-nodes-manager.md | 72 +++++++-- docs/docs/api/model/node-children.md | 4 +- docs/docs/api/model/node.md | 4 +- docs/docs/api/model/plugin-instance.md | 24 +-- docs/docs/api/model/prop.md | 4 +- docs/docs/api/model/props.md | 4 +- docs/docs/api/model/resource.md | 2 +- docs/docs/api/model/selection.md | 4 +- docs/docs/api/model/window.md | 4 +- docs/docs/api/plugins.md | 2 +- docs/docs/api/project.md | 2 +- docs/docs/api/setters.md | 2 +- docs/docs/api/skeleton.md | 2 +- docs/docs/api/workspace.md | 2 +- .../designer/src/document/document-model.ts | 4 +- .../src/document/node/modal-nodes-manager.ts | 46 +++--- packages/designer/src/document/node/node.ts | 144 ++++++++++-------- .../shell/src/model/modal-nodes-manager.ts | 29 ++-- .../src/shell/model/modal-nodes-manager.ts | 13 +- 32 files changed, 231 insertions(+), 171 deletions(-) diff --git a/docs/docs/api/canvas.md b/docs/docs/api/canvas.md index 8340bd348..344223bcb 100644 --- a/docs/docs/api/canvas.md +++ b/docs/docs/api/canvas.md @@ -42,7 +42,7 @@ get dragon(): IPublicModelDragon | null; get activeTracker(): IPublicModelActiveTracker | null; ``` -## 方法签名 +## 方法 ### createLocation 创建一个文档插入位置对象,该对象用来描述一个即将插入的节点在文档中的位置 diff --git a/docs/docs/api/common.md b/docs/docs/api/common.md index a6b21974d..e5bfa8629 100644 --- a/docs/docs/api/common.md +++ b/docs/docs/api/common.md @@ -20,7 +20,7 @@ sidebar_position: 11 #### skeletonCabin 面板扩展相关,详见下方方法签名 -## 方法签名 +## 方法 ### utils #### isNodeSchema 是否为合法的 schema 结构 diff --git a/docs/docs/api/config.md b/docs/docs/api/config.md index fee26d436..ea4c7dbfc 100644 --- a/docs/docs/api/config.md +++ b/docs/docs/api/config.md @@ -10,7 +10,7 @@ sidebar_position: 8 ## 模块简介 配置模块,负责配置的读、写等操作。 -## 方法签名 +## 方法 ### get 获取指定 key 的值 diff --git a/docs/docs/api/event.md b/docs/docs/api/event.md index be3c768e0..0eb8b9738 100644 --- a/docs/docs/api/event.md +++ b/docs/docs/api/event.md @@ -10,7 +10,7 @@ sidebar_position: 7 ## 模块简介 负责事件处理 API,支持自定义监听事件、触发事件。 -## 方法签名 +## 方法 ### on 监听事件 diff --git a/docs/docs/api/hotkey.md b/docs/docs/api/hotkey.md index a8c717342..a244b94c2 100644 --- a/docs/docs/api/hotkey.md +++ b/docs/docs/api/hotkey.md @@ -9,7 +9,7 @@ sidebar_position: 5 ## 模块简介 绑定快捷键 API,可以自定义项目快捷键使用。 -## 方法签名 +## 方法 ### bind 绑定快捷键 diff --git a/docs/docs/api/init.md b/docs/docs/api/init.md index 185e76355..f8bf2cdbe 100644 --- a/docs/docs/api/init.md +++ b/docs/docs/api/init.md @@ -8,7 +8,7 @@ sidebar_position: 10 ## 模块简介 提供 init 等方法 -## 方法签名 +## 方法 #### 1. init 初始化引擎 diff --git a/docs/docs/api/logger.md b/docs/docs/api/logger.md index 68681438b..7493f34dc 100644 --- a/docs/docs/api/logger.md +++ b/docs/docs/api/logger.md @@ -12,7 +12,7 @@ sidebar_position: 9 > 注:日志级别可以通过 url query 动态调整,详见下方[查看示例](#查看示例)。
> 参考 [zen-logger](https://web.npm.alibaba-inc.com/package/zen-logger) 实现进行封装 -## 方法签名 +## 方法 日志记录方法 diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index c060b9bef..0732c568e 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -22,7 +22,7 @@ get componentsMap(): { [key: string]: IPublicTypeNpmInfo | ComponentType | ``` 相关类型:[IPublicTypeNpmInfo](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/npm-info.ts) -## 方法签名 +## 方法 ### 资产包 #### setAssets diff --git a/docs/docs/api/model/detecting.md b/docs/docs/api/model/detecting.md index 15e1cfca7..c7a20ddcb 100644 --- a/docs/docs/api/model/detecting.md +++ b/docs/docs/api/model/detecting.md @@ -9,7 +9,7 @@ sidebar_position: 6 画布节点悬停模型 -## 变量 +## 属性 ### current @@ -28,7 +28,7 @@ sidebar_position: 6 `@type {boolean}` -## 方法签名 +## 方法 ### capture hover 指定节点 diff --git a/docs/docs/api/model/document-model.md b/docs/docs/api/model/document-model.md index 9e5064371..c9f338609 100644 --- a/docs/docs/api/model/document-model.md +++ b/docs/docs/api/model/document-model.md @@ -9,7 +9,7 @@ sidebar_position: 0 文档模型 -## 变量 +## 属性 ### id @@ -95,7 +95,7 @@ sidebar_position: 0 **@since v1.1.0** -## 方法签名 +## 方法 ### getNodeById 根据 nodeId 返回 [Node](./node) 实例 diff --git a/docs/docs/api/model/dragon.md b/docs/docs/api/model/dragon.md index 82884224b..995fd1b1f 100644 --- a/docs/docs/api/model/dragon.md +++ b/docs/docs/api/model/dragon.md @@ -18,7 +18,7 @@ import { IPublicModelDragon } from '@alilc/lowcode-types'; **@since** v1.1.0 -## 变量 +## 属性 ### dragging @@ -31,7 +31,7 @@ import { IPublicModelDragon } from '@alilc/lowcode-types'; get dragging(): boolean; ``` -## 方法签名 +## 方法 ### onDragstart diff --git a/docs/docs/api/model/drop-location.md b/docs/docs/api/model/drop-location.md index 37497741c..853da842c 100644 --- a/docs/docs/api/model/drop-location.md +++ b/docs/docs/api/model/drop-location.md @@ -11,7 +11,7 @@ sidebar_position: 13 拖拽放置位置模型 -## 变量 +## 属性 ### target @@ -37,7 +37,7 @@ sidebar_position: 13 相关类型:[IPublicModelLocateEvent](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/location-event.ts) -## 方法签名 +## 方法 ### clone diff --git a/docs/docs/api/model/history.md b/docs/docs/api/model/history.md index db6800850..b8c4d791b 100644 --- a/docs/docs/api/model/history.md +++ b/docs/docs/api/model/history.md @@ -9,7 +9,7 @@ sidebar_position: 5 操作历史记录模型 -## 方法签名 +## 方法 ### go 历史记录跳转到指定位置 diff --git a/docs/docs/api/model/modal-nodes-manager.md b/docs/docs/api/model/modal-nodes-manager.md index ed89ce31b..acff26734 100644 --- a/docs/docs/api/model/modal-nodes-manager.md +++ b/docs/docs/api/model/modal-nodes-manager.md @@ -9,40 +9,86 @@ sidebar_position: 7 模态节点管理器模型 -## 方法签名 +## 方法 ### setNodes -setNodes() - 设置模态节点,触发内部事件 +```typescript +/** + * 设置模态节点,触发内部事件 + * set modal nodes, trigger internal events + */ +setNodes(): void; +``` + ### getModalNodes -getModalNodes() - 获取模态节点(们) +```typescript +/** + * 获取模态节点(们) + * get modal nodes + */ +getModalNodes(): IPublicModelNode[]; +``` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + ### getVisibleModalNode -getVisibleModalNode() - 获取当前可见的模态节点 +```typescript +/** + * 获取当前可见的模态节点 + * get current visible modal node + */ +getVisibleModalNode(): IPublicModelNode | null; +``` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + ### hideModalNodes -hideModalNodes() - 隐藏模态节点(们) +```typescript +/** + * 隐藏模态节点(们) + * hide modal nodes + */ +hideModalNodes(): void; +``` + ### setVisible -setVisible(node: Node) - 设置指定节点为可见态 +```typescript +/** + * 设置指定节点为可见态 + * set specfic model node as visible + * @param node Node + */ +setVisible(node: IPublicModelNode): void; +``` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + ### setInvisible -setInvisible(node: Node) - 设置指定节点为不可见态 + +```typescript +/** + * 设置指定节点为不可见态 + * set specfic model node as invisible + * @param node Node + */ +setInvisible(node: IPublicModelNode): void; +``` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) diff --git a/docs/docs/api/model/node-children.md b/docs/docs/api/model/node-children.md index 2e8769411..10488a733 100644 --- a/docs/docs/api/model/node-children.md +++ b/docs/docs/api/model/node-children.md @@ -8,7 +8,7 @@ sidebar_position: 2 ## 基本介绍 节点孩子模型 -## 变量 +## 属性 ### owner 返回当前 children 实例所属的节点实例 @@ -41,7 +41,7 @@ children 内的节点实例数 **@since v1.1.0** -## 方法签名 +## 方法 ### delete 删除指定节点 diff --git a/docs/docs/api/model/node.md b/docs/docs/api/model/node.md index 60678ad34..fbc88034b 100644 --- a/docs/docs/api/model/node.md +++ b/docs/docs/api/model/node.md @@ -9,7 +9,7 @@ sidebar_position: 1 节点模型 -## 变量 +## 属性 ### id 节点 id @@ -263,7 +263,7 @@ sidebar_position: 1 **@since v1.1.0** -## 方法签名 +## 方法 ### getRect diff --git a/docs/docs/api/model/plugin-instance.md b/docs/docs/api/model/plugin-instance.md index 8f764c68b..14ce38837 100644 --- a/docs/docs/api/model/plugin-instance.md +++ b/docs/docs/api/model/plugin-instance.md @@ -17,38 +17,24 @@ sidebar_position: 12 插件名字 -```typescript -get name(): string; -``` +`@type {string}` ### dep 插件依赖 -```typescript -get dep(): string[]; -``` +`@type {string[]}` ### disabled 插件是否禁用 -```typescript -get disabled(): boolean - -set disabled(disabled: boolean): void; - -``` +`@type {boolean}` ### meta 插件 meta 信息 -```typescript -get meta(): IPublicTypePluginMeta - -``` - -- [IPublicTypePluginMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/plugin-meta.ts) - +`@type {IPublicTypePluginMeta}` +相关类型:[IPublicTypePluginMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/plugin-meta.ts) diff --git a/docs/docs/api/model/prop.md b/docs/docs/api/model/prop.md index e619cdc33..d9b0d14f4 100644 --- a/docs/docs/api/model/prop.md +++ b/docs/docs/api/model/prop.md @@ -9,7 +9,7 @@ sidebar_position: 3 属性模型 -## 变量 +## 属性 ### id @@ -46,7 +46,7 @@ key 值 相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) -## 方法签名 +## 方法 ### setValue diff --git a/docs/docs/api/model/props.md b/docs/docs/api/model/props.md index f76919d49..9bd6eaa66 100644 --- a/docs/docs/api/model/props.md +++ b/docs/docs/api/model/props.md @@ -9,7 +9,7 @@ sidebar_position: 4 属性集模型 -## 变量 +## 属性 ### id id @@ -32,7 +32,7 @@ id 相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) -## 方法签名 +## 方法 ### getProp 获取指定 path 的属性模型实例 diff --git a/docs/docs/api/model/resource.md b/docs/docs/api/model/resource.md index 33a6e3119..30b1e9f41 100644 --- a/docs/docs/api/model/resource.md +++ b/docs/docs/api/model/resource.md @@ -7,7 +7,7 @@ sidebar_position: 12 > **@types** [IPublicModelWindow](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/resource.ts)
> **@since** v1.1.0 -## 变量 +## 属性 ### title diff --git a/docs/docs/api/model/selection.md b/docs/docs/api/model/selection.md index 529a3e5a2..9fc2e3a1c 100644 --- a/docs/docs/api/model/selection.md +++ b/docs/docs/api/model/selection.md @@ -9,7 +9,7 @@ sidebar_position: 6 画布节点选中模型 -## 变量 +## 属性 ### selected 返回选中的节点 id @@ -25,7 +25,7 @@ sidebar_position: 6 **@since v1.1.0** -## 方法签名 +## 方法 ### select 选中指定节点(覆盖方式) diff --git a/docs/docs/api/model/window.md b/docs/docs/api/model/window.md index f70c33e4d..7814ae6ea 100644 --- a/docs/docs/api/model/window.md +++ b/docs/docs/api/model/window.md @@ -12,7 +12,7 @@ sidebar_position: 12 低代码设计器窗口模型 -## 变量 +## 属性 ### id @@ -38,7 +38,7 @@ sidebar_position: 12 关联模型 [IPublicModelResource](./resource) -## 方法签名 +## 方法 ### importSchema 当前窗口导入 schema, 会调用当前窗口对应资源的 import 钩子 diff --git a/docs/docs/api/plugins.md b/docs/docs/api/plugins.md index 9b1993b10..58be1fde0 100644 --- a/docs/docs/api/plugins.md +++ b/docs/docs/api/plugins.md @@ -8,7 +8,7 @@ sidebar_position: 4 ## 模块简介 插件管理器,提供编排模块中管理插件的能力。 -## 方法签名 +## 方法 ### register 注册插件 diff --git a/docs/docs/api/project.md b/docs/docs/api/project.md index 15fb3cb7e..0c7213aac 100644 --- a/docs/docs/api/project.md +++ b/docs/docs/api/project.md @@ -69,7 +69,7 @@ get simulatorHost(): IPublicApiSimulatorHost | null; 相关类型:[IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts) -## 方法签名 +## 方法 ### openDocument 打开一个 document diff --git a/docs/docs/api/setters.md b/docs/docs/api/setters.md index 3c5fd9f75..92d24f4e1 100644 --- a/docs/docs/api/setters.md +++ b/docs/docs/api/setters.md @@ -8,7 +8,7 @@ sidebar_position: 6 ## 模块简介 负责注册设置器、管理设置器的 API。注册自定义设置器之后可以在物料中进行使用。 -## 方法签名 +## 方法 ### getSetter 获取指定 setter diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index 5ad82accf..e7ae391eb 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -135,7 +135,7 @@ skeleton.add({ }); ``` -## 方法签名 +## 方法 ### add diff --git a/docs/docs/api/workspace.md b/docs/docs/api/workspace.md index 138693cfa..81301d110 100644 --- a/docs/docs/api/workspace.md +++ b/docs/docs/api/workspace.md @@ -57,7 +57,7 @@ get resourceList(): IPublicModelResource; 关联模型 [IPublicModelResource](./model/resource) -## 方法签名 +## 方法 ### registerResourceType 注册资源 diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 8bccde2ef..cb345cc82 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -753,7 +753,7 @@ export class DocumentModel implements IDocumentModel { })); } - onNodeCreate(func: (node: Node) => void) { + onNodeCreate(func: (node: INode) => void) { const wrappedFunc = wrapWithEventSwitch(func); this.emitter.on('nodecreate', wrappedFunc); return () => { @@ -761,7 +761,7 @@ export class DocumentModel implements IDocumentModel { }; } - onNodeDestroy(func: (node: Node) => void) { + onNodeDestroy(func: (node: INode) => void) { const wrappedFunc = wrapWithEventSwitch(func); this.emitter.on('nodedestroy', wrappedFunc); return () => { diff --git a/packages/designer/src/document/node/modal-nodes-manager.ts b/packages/designer/src/document/node/modal-nodes-manager.ts index 68bca607b..585b52f5f 100644 --- a/packages/designer/src/document/node/modal-nodes-manager.ts +++ b/packages/designer/src/document/node/modal-nodes-manager.ts @@ -1,15 +1,15 @@ -import { Node } from './node'; +import { INode, Node } 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: Node) { +export function getModalNodes(node: INode | Node) { if (!node) return []; let nodes: any = []; if (node.componentMeta.isModal) { nodes.push(node); } - const children = node.getChildren(); + const { children } = node; if (children) { children.forEach((child) => { nodes = nodes.concat(getModalNodes(child)); @@ -20,14 +20,17 @@ export function getModalNodes(node: Node) { export interface IModalNodesManager extends IPublicModelModalNodesManager { + getModalNodes(): INode[]; + + getVisibleModalNode(): INode | null; } export class ModalNodesManager implements IModalNodesManager { - public willDestroy: any; + willDestroy: any; private page: DocumentModel; - private modalNodes: Node[]; + private modalNodes: INode[]; private nodeRemoveEvents: any; @@ -45,26 +48,27 @@ export class ModalNodesManager implements IModalNodesManager { ]; } - getModalNodes() { + getModalNodes(): INode[] { return this.modalNodes; } - getVisibleModalNode() { - return this.getModalNodes().find((node: Node) => node.getVisible()); + getVisibleModalNode(): INode | null { + const visibleNode = this.getModalNodes().find((node: INode) => node.getVisible()); + return visibleNode || null; } hideModalNodes() { - this.modalNodes.forEach((node: Node) => { + this.modalNodes.forEach((node: INode) => { node.setVisible(false); }); } - setVisible(node: Node) { + setVisible(node: INode) { this.hideModalNodes(); node.setVisible(true); } - setInvisible(node: Node) { + setInvisible(node: INode) { node.setVisible(false); } @@ -82,7 +86,7 @@ export class ModalNodesManager implements IModalNodesManager { }; } - private addNode(node: Node) { + private addNode(node: INode) { if (node.componentMeta.isModal) { this.hideModalNodes(); this.modalNodes.push(node); @@ -92,7 +96,7 @@ export class ModalNodesManager implements IModalNodesManager { } } - private removeNode(node: Node) { + private removeNode(node: INode) { if (node.componentMeta.isModal) { const index = this.modalNodes.indexOf(node); if (index >= 0) { @@ -106,24 +110,24 @@ export class ModalNodesManager implements IModalNodesManager { } } - private addNodeEvent(node: Node) { - this.nodeRemoveEvents[node.getId()] = + private addNodeEvent(node: INode) { + this.nodeRemoveEvents[node.id] = node.onVisibleChange(() => { this.emitter.emit('visibleChange'); }); } - private removeNodeEvent(node: Node) { - if (this.nodeRemoveEvents[node.getId()]) { - this.nodeRemoveEvents[node.getId()](); - delete this.nodeRemoveEvents[node.getId()]; + private removeNodeEvent(node: INode) { + if (this.nodeRemoveEvents[node.id]) { + this.nodeRemoveEvents[node.id](); + delete this.nodeRemoveEvents[node.id]; } } setNodes() { - const nodes = getModalNodes(this.page.getRoot()!); + const nodes = getModalNodes(this.page.rootNode!); this.modalNodes = nodes; - this.modalNodes.forEach((node: Node) => { + this.modalNodes.forEach((node: INode) => { this.addNodeEvent(node); }); diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index ef837a329..8a7e9732a 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -36,6 +36,11 @@ export interface NodeStatus { export interface INode extends IPublicModelNode { + /** + * 当前节点子集 + */ + get children(): INodeChildren | null; + setVisible(flag: boolean): void; getVisible(): boolean; @@ -70,6 +75,10 @@ export interface INode extends IPublicModelNode { internalSetSlotFor(slotFor: Prop | null | undefined): void; addSlot(slotNode: INode): void; + + get componentMeta(): ComponentMeta; + + onVisibleChange(func: (flag: boolean) => any): () => void; } /** @@ -204,6 +213,74 @@ export class Node isInited = false; + _settingEntry: SettingTopEntry; + + get settingEntry(): SettingTopEntry { + if (this._settingEntry) return this._settingEntry; + this._settingEntry = this.document.designer.createSettingEntry([this]); + return this._settingEntry; + } + + private autoruns?: Array<() => void>; + + private _isRGLContainer = false; + + set isRGLContainer(status: boolean) { + this._isRGLContainer = status; + } + + get isRGLContainer(): boolean { + return !!this._isRGLContainer; + } + + set isRGLContainerNode(status: boolean) { + this._isRGLContainer = status; + } + + get isRGLContainerNode(): boolean { + return !!this._isRGLContainer; + } + + private _slotFor?: Prop | null = null; + + @obx.shallow _slots: INode[] = []; + + get slots() { + return this._slots; + } + + /* istanbul ignore next */ + @obx.ref private _conditionGroup: IPublicModelExclusiveGroup | null = null; + + /* istanbul ignore next */ + get conditionGroup(): IPublicModelExclusiveGroup | null { + return this._conditionGroup; + } + + private purged = false; + + /** + * 是否已销毁 + */ + get isPurged() { + return this.purged; + } + + private purging: boolean = false; + + /** + * 是否正在销毁 + */ + get isPurging() { + return this.purging; + } + + @obx.shallow status: NodeStatus = { + inPlaceEditing: false, + locking: false, + pseudo: false, + }; + constructor(readonly document: IDocumentModel, nodeSchema: Schema, options: any = {}) { makeObservable(this); const { componentName, id, children, props, ...extras } = nodeSchema; @@ -237,14 +314,6 @@ export class Node }); } - _settingEntry: SettingTopEntry; - - get settingEntry(): SettingTopEntry { - if (this._settingEntry) return this._settingEntry; - this._settingEntry = this.document.designer.createSettingEntry([this]); - return this._settingEntry; - } - /** * 节点初始化期间就把内置的一些 prop 初始化好,避免后续不断构造实例导致 reaction 执行多次 */ @@ -268,8 +337,6 @@ export class Node return this.document.designer.transformProps(props, this, IPublicEnumTransformStage.Upgrade); } - private autoruns?: Array<() => void>; - private setupAutoruns() { const autoruns = this.componentMeta.getMetadata().configure.advanced?.autoruns; if (!autoruns || autoruns.length < 1) { @@ -296,24 +363,6 @@ export class Node return children || []; } - private _isRGLContainer = false; - - set isRGLContainer(status: boolean) { - this._isRGLContainer = status; - } - - get isRGLContainer(): boolean { - return !!this._isRGLContainer; - } - - set isRGLContainerNode(status: boolean) { - this._isRGLContainer = status; - } - - get isRGLContainerNode(): boolean { - return !!this._isRGLContainer; - } - isContainer(): boolean { return this.isContainerNode; } @@ -449,8 +498,6 @@ export class Node } } - private _slotFor?: Prop | null = null; - internalSetSlotFor(slotFor: Prop | null | undefined) { this._slotFor = slotFor; } @@ -536,24 +583,10 @@ export class Node return this.props.export(IPublicEnumTransformStage.Serilize).props || null; } - @obx.shallow _slots: INode[] = []; - hasSlots() { return this._slots.length > 0; } - get slots() { - return this._slots; - } - - /* istanbul ignore next */ - @obx.ref private _conditionGroup: IPublicModelExclusiveGroup | null = null; - - /* istanbul ignore next */ - get conditionGroup(): IPublicModelExclusiveGroup | null { - return this._conditionGroup; - } - /* istanbul ignore next */ setConditionGroup(grp: IPublicModelExclusiveGroup | string | null) { if (!grp) { @@ -929,15 +962,6 @@ export class Node this.children?.delete(node); } - private purged = false; - - /** - * 是否已销毁 - */ - get isPurged() { - return this.purged; - } - /** * 销毁 */ @@ -952,18 +976,10 @@ export class Node // this.document.destroyNode(this); } - private purging: boolean = false; internalPurgeStart() { this.purging = true; } - /** - * 是否正在销毁 - */ - get isPurging() { - return this.purging; - } - /** * 是否可执行某action */ @@ -1044,12 +1060,6 @@ export class Node this.children?.mergeChildren(remover, adder, sorter); } - @obx.shallow status: NodeStatus = { - inPlaceEditing: false, - locking: false, - pseudo: false, - }; - /** * @deprecated */ diff --git a/packages/shell/src/model/modal-nodes-manager.ts b/packages/shell/src/model/modal-nodes-manager.ts index 71c94666c..b1e27596f 100644 --- a/packages/shell/src/model/modal-nodes-manager.ts +++ b/packages/shell/src/model/modal-nodes-manager.ts @@ -1,6 +1,9 @@ -import { ModalNodesManager as InnerModalNodesManager } from '@alilc/lowcode-designer'; +import { + IModalNodesManager as InnerModalNodesManager, + INode as InnerNode, +} from '@alilc/lowcode-designer'; import { IPublicModelModalNodesManager, IPublicModelNode } from '@alilc/lowcode-types'; -import { Node } from './node'; +import { Node as ShellNode } from './node'; import { nodeSymbol, modalNodesManagerSymbol } from '../symbols'; export class ModalNodesManager implements IPublicModelModalNodesManager { @@ -28,18 +31,24 @@ export class ModalNodesManager implements IPublicModelModalNodesManager { /** * 获取模态节点(们) - * @returns */ - getModalNodes(): any { - return this[modalNodesManagerSymbol].getModalNodes().map((node) => Node.create(node)); + getModalNodes(): IPublicModelNode[] { + const innerNodes = this[modalNodesManagerSymbol].getModalNodes(); + const shellNodes: IPublicModelNode[] = []; + innerNodes?.forEach((node: InnerNode) => { + const shellNode = ShellNode.create(node); + if (shellNode) { + shellNodes.push(shellNode); + } + }); + return shellNodes; } /** * 获取当前可见的模态节点 - * @returns */ - getVisibleModalNode(): any { - return Node.create(this[modalNodesManagerSymbol].getVisibleModalNode()); + getVisibleModalNode(): IPublicModelNode | null { + return ShellNode.create(this[modalNodesManagerSymbol].getVisibleModalNode()); } /** @@ -54,7 +63,7 @@ export class ModalNodesManager implements IPublicModelModalNodesManager { * @param node Node */ setVisible(node: IPublicModelNode): void { - this[modalNodesManagerSymbol].setVisible(node[nodeSymbol]); + this[modalNodesManagerSymbol].setVisible((node as any)[nodeSymbol]); } /** @@ -62,6 +71,6 @@ export class ModalNodesManager implements IPublicModelModalNodesManager { * @param node Node */ setInvisible(node: IPublicModelNode): void { - this[modalNodesManagerSymbol].setInvisible(node[nodeSymbol]); + this[modalNodesManagerSymbol].setInvisible((node as any)[nodeSymbol]); } } \ No newline at end of file diff --git a/packages/types/src/shell/model/modal-nodes-manager.ts b/packages/types/src/shell/model/modal-nodes-manager.ts index d24a3d037..bfbba50ec 100644 --- a/packages/types/src/shell/model/modal-nodes-manager.ts +++ b/packages/types/src/shell/model/modal-nodes-manager.ts @@ -1,36 +1,41 @@ import { IPublicModelNode } from './'; export interface IPublicModelModalNodesManager { + /** * 设置模态节点,触发内部事件 + * set modal nodes, trigger internal events */ setNodes(): void; /** * 获取模态节点(们) - * @returns + * get modal nodes */ - getModalNodes(): any; + getModalNodes(): IPublicModelNode[]; /** * 获取当前可见的模态节点 - * @returns + * get current visible modal node */ - getVisibleModalNode(): any; + getVisibleModalNode(): IPublicModelNode | null; /** * 隐藏模态节点(们) + * hide modal nodes */ hideModalNodes(): void; /** * 设置指定节点为可见态 + * set specfic model node as visible * @param node Node */ setVisible(node: IPublicModelNode): void; /** * 设置指定节点为不可见态 + * set specfic model node as invisible * @param node Node */ setInvisible(node: IPublicModelNode): void; From 5624202586a65ff6f0247a94c4bc99311c95df9c Mon Sep 17 00:00:00 2001 From: eternalsky Date: Wed, 11 Jan 2023 16:03:25 +0800 Subject: [PATCH 08/89] feat: add docs for Parts --- docs/config/sidebars.js | 2 +- docs/docs/guide/expand/editor/cli.md | 2 +- .../guide/expand/editor/parts/_category_.json | 4 + .../guide/expand/editor/parts/partsIntro.md | 18 ++ .../guide/expand/editor/parts/partsassets.md | 267 ++++++++++++++++++ .../guide/expand/editor/parts/partslcc.md | 92 ++++++ .../{partsIntro.md => parts/prototype.md} | 37 +-- .../guide/expand/editor/pluginContextMenu.md | 5 +- docs/docs/guide/expand/editor/pluginWidget.md | 37 +-- docs/docs/guide/expand/editor/setter.md | 2 +- 10 files changed, 421 insertions(+), 45 deletions(-) create mode 100644 docs/docs/guide/expand/editor/parts/_category_.json create mode 100644 docs/docs/guide/expand/editor/parts/partsIntro.md create mode 100644 docs/docs/guide/expand/editor/parts/partsassets.md create mode 100644 docs/docs/guide/expand/editor/parts/partslcc.md rename docs/docs/guide/expand/editor/{partsIntro.md => parts/prototype.md} (78%) diff --git a/docs/config/sidebars.js b/docs/config/sidebars.js index 95a79962f..77a2e1f22 100644 --- a/docs/config/sidebars.js +++ b/docs/config/sidebars.js @@ -39,7 +39,7 @@ module.exports = { type: 'category', label: '扩展编辑器', collapsed: false, - items: getDocsFromDir('guide/expand/editor'), + items: getDocsFromDir('guide/expand/editor', [{ dir: 'guide/expand/editor/parts', label: 'Parts·造物' }]), }, { type: 'category', diff --git a/docs/docs/guide/expand/editor/cli.md b/docs/docs/guide/expand/editor/cli.md index 74b9fa821..60f44ce87 100644 --- a/docs/docs/guide/expand/editor/cli.md +++ b/docs/docs/guide/expand/editor/cli.md @@ -1,6 +1,6 @@ --- title: 低代码生态脚手架 & 调试机制 -sidebar_position: 7 +sidebar_position: 8 --- ## 脚手架简述 diff --git a/docs/docs/guide/expand/editor/parts/_category_.json b/docs/docs/guide/expand/editor/parts/_category_.json new file mode 100644 index 000000000..005a3caf6 --- /dev/null +++ b/docs/docs/guide/expand/editor/parts/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Parts 造物", + "position": 1 +} diff --git a/docs/docs/guide/expand/editor/parts/partsIntro.md b/docs/docs/guide/expand/editor/parts/partsIntro.md new file mode 100644 index 000000000..a6fc6e881 --- /dev/null +++ b/docs/docs/guide/expand/editor/parts/partsIntro.md @@ -0,0 +1,18 @@ +--- +title: 介绍 +sidebar_position: 1 +--- +## 介绍 +![](https://gw.alicdn.com/imgextra/i2/O1CN01Gyq6AZ1nOENPTVXX7_!!6000000005079-2-tps-256-104.png) + + +「Parts·造物」是基于开源低代码引擎打造的次时代物料研发和集成工具,一方面作为低代码引擎搭建低代码平台的一个样板展示开源生态下的各个组件如何集合在一起形成生产力,另一方面也可以生产低代码平台所需的物料。 + +目前「Parts·造物」主要提供两大产品功能: + 1. React 组件导入低代码引擎:通过在线可视化的「物料描述」配置,任意工具开发的 React 组件都可以快速完成对低代码引擎的适配,导入到低代码引擎项目中进行使用。不必额外开发新的组件。 + 2. 低代码生产组件:通过低代码的形式生产组件,极低上手门槛,提供丰富的原子组件用于组合,完善的调试预览和组件生命周期控制。生产的组件既可以在低代码引擎项目中使用,也可以出码后在普通源码项目中使用。 + + +## 联系我们 + + diff --git a/docs/docs/guide/expand/editor/parts/partsassets.md b/docs/docs/guide/expand/editor/parts/partsassets.md new file mode 100644 index 000000000..a8525f64c --- /dev/null +++ b/docs/docs/guide/expand/editor/parts/partsassets.md @@ -0,0 +1,267 @@ +--- +title: 资产包管理 +sidebar_position: 4 +--- + +## 介绍 + +通过前述介绍,相信大家已经了解如何使用 「[Parts·造物](https://parts.lowcode-engine.cn/)」 来将已有的 React 组件快速接入低代码引擎,以及生产低代码组件。 + +大家在使用的过程中,可能会希望构建出来的资产包可以后续随时访问下载,或者希望构建资产包时各个组件的版本等信息可以持久化起来并且能够多人维护。 + +通过「[Parts·造物](https://parts.lowcode-engine.cn/)」的 `资产包` 管理功能帮助大家解决这个问题 + +![image.png](https://img.alicdn.com/imgextra/i3/O1CN01Fkaznh1zWj9wYKpcH_!!6000000006722-2-tps-1702-628.png) + +## 新建资产包 + +首先,我们在 我的资产包 tab 中点击 `新建资产包` +![image.png](https://img.alicdn.com/imgextra/i1/O1CN01qe8zfO1ilysebSfD5_!!6000000004454-2-tps-3064-1432.png) + +- 填写资产包名称 +- 配置资产包管理员,管理员拥有该资产包的所有权限,初始默认为资产包的创建者,还可以添加其他人作为管理员, +- 配置资产包描述(可选) +- 点击 `确定`, 即可完成资产包的创建 + +接下来需要为资产包添加一个或者多个组件。 + +## 添加组件 + +第二步:新建完资产包以后,我们就可以为其添加组件了,如果是新建资产包流程,新建完成之后会自动弹出组件配置的弹窗,当然,你可可以通过点击资产包卡片的方式打开组件配置的弹窗。 +![image.png](https://img.alicdn.com/imgextra/i3/O1CN01kqymdB1nkDQclPk7F_!!6000000005127-2-tps-965-261.png) + +- 点击弹窗中 `添加组件` 按钮,在弹出的组件选择面板中,选中需要添加的组件并点击 `下一步`。 + ![image.png](https://img.alicdn.com/imgextra/i1/O1CN014Baihf1r742Qi1Wel_!!6000000005583-2-tps-1856-1520.png) +- 进入组件版本以及描述协议版本选择界面,选择所需要的正确版本,点击 `安装` 即可完成一个组件的添加。 + ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01Y7aWWi1MMPDVlidgz_!!6000000001420-2-tps-1668-1462.png) + +## 构建资产包 + +添加完组件以后就点击 `保存并构建资产包` 进入资产包构建配置弹窗 +![image.png](https://img.alicdn.com/imgextra/i4/O1CN01iZf4Ue1PlXnyKYxnK_!!6000000001881-2-tps-1288-670.png) + +- `开启缓存` : 可充分利用之前的构建结果缓存来加速资产包的生成,我们会将每个组件的构建结果以 包名和版本号为 key 进行缓存。 +- `任务描述` : 当前构建任务的一些描述信息。 + +点击 `确认` 按钮 会自动跳转到当前资产包的构建历史界面: +![image.png](https://img.alicdn.com/imgextra/i2/O1CN01krDaFc1TuTztMPssI_!!6000000002442-2-tps-1726-696.png) +构建历史界面会显示当前资产包所有的构建历史记录,表格状态栏展示了构建的状态:`成功`,`失败`,`正在运行` 三种状态, 操作列可以在构建成功时复制或者下载资产包结果 + +## 使用资产包 +你可以在 [lowcode-demo](https://github.com/alibaba/lowcode-demo) 中直接引用,可直接替换demo中原来的资产包文件: +例如,在 [demo-lowcode-component](https://github.com/alibaba/lowcode-demo/tree/main/demo-lowcode-component) 中,直接用你的资产包文件替换文件[assets.json](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/services/assets.json),即可快速使用自己的物料了。 + +### 在编辑器中使用资产包 +在使用含有低代码组件的资产包注意 注意引擎版本必须大于等于 `1.1.0-beta.9`。 +然后直接替换 [lowcode-demo](https://github.com/alibaba/lowcode-demo) demo 中的 `assets.json` 文件即可。 + +### 在预览中使用资产包 +在预览中使用资产包的整体思路是从 `资产包` 中提取并转换出 `ReactRenderer` 渲染所需要的 react 组件列表(`components` 参数),然后将 `schema` 以及 `components` 传入到 `ReactRenderer` 中进行渲染,需要注意的是,在 `资产包` 的转换过程中,我们也需要将 `低代码组件` 转换成 react 组件, 具体逻辑可以参考下 [demo-lowcode-component](https://github.com/alibaba/lowcode-demo/tree/main/demo-lowcode-component) 中 `src/parse-assets.ts` 文件的实现。 +基于资产包进行预览的整体逻辑如下: [详见](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/preview.tsx): +```ts +import ReactDOM from 'react-dom'; +import React, { useState } from 'react'; +import { Loading } from '@alifd/next'; +import ReactRenderer from '@alilc/lowcode-react-renderer'; +import { createFetchHandler } from '@alilc/lowcode-datasource-fetch-handler'; +import { + getProjectSchemaFromLocalStorage, +} from './services/mockService'; +import assets from './services/assets.json'; +import { parseAssets } from './parse-assets'; + +const getScenarioName = function () { + if (location.search) { + return new URLSearchParams(location.search.slice(1)).get('scenarioName') || 'index'; + } + return 'index'; +}; + +const SamplePreview = () => { + const [data, setData] = useState({}); + async function init() { + const scenarioName = getScenarioName(); + const projectSchema = getProjectSchemaFromLocalStorage(scenarioName); + const { componentsMap: componentsMapArray, componentsTree } = projectSchema; + const schema = componentsTree[0]; + const componentsMap: any = {}; + componentsMapArray.forEach((component: any) => { + componentsMap[component.componentName] = component; + }); + + // 特别提醒重点注意!!!:从资产包中解析出所有的 react 组件列表 + const { components } = await parseAssets(assets); + + setData({ + schema, + components, + }); + } + + const { schema, components } = data; + + if (!schema || !components) { + init(); + return ; + } + + return ( +
+ +
+ ); +}; + +ReactDOM.render(, document.getElementById('ice-container')); +``` + +从资产包中解析 react 组件列表的逻辑如下, [详见](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/parse-assets.ts): +```ts +import { ComponentDescription, ComponentSchema, RemoteComponentDescription } from '@alilc/lowcode-types'; +import { buildComponents, AssetsJson, AssetLoader } from '@alilc/lowcode-utils'; +import ReactRenderer from '@alilc/lowcode-react-renderer'; +import { injectComponents } from '@alilc/lowcode-plugin-inject'; +import React, { createElement } from 'react'; + +export async function parseAssets(assets: AssetsJson) { + const { components: rawComponents, packages } = assets; + const libraryAsset = []; + const libraryMap = {}; + const packagesMap = {}; + packages.forEach(pkg => { + const { package: _package, library, urls, renderUrls, id } = pkg; + if (_package) { + libraryMap[id || _package] = library; + } + packagesMap[id || _package] = pkg; + if (renderUrls) { + libraryAsset.push(renderUrls); + } else if (urls) { + libraryAsset.push(urls); + } + }); + const assetLoader = new AssetLoader(); + await assetLoader.load(libraryAsset); + let newComponents = rawComponents; + if (rawComponents && rawComponents.length) { + const componentDescriptions: ComponentDescription[] = []; + const remoteComponentDescriptions: RemoteComponentDescription[] = []; + rawComponents.forEach((component: any) => { + if (!component) { + return; + } + if (component.exportName && component.url) { + remoteComponentDescriptions.push(component); + } else { + componentDescriptions.push(component); + } + }); + newComponents = [...componentDescriptions]; + + // 如果有远程组件描述协议,则自动加载并补充到资产包中,同时出发 designer.incrementalAssetsReady 通知组件面板更新数据 + if (remoteComponentDescriptions && remoteComponentDescriptions.length) { + await Promise.all( + remoteComponentDescriptions.map(async (component: any) => { + const { exportName, url, npm } = component; + await (new AssetLoader()).load(url); + function setAssetsComponent(component: any, extraNpmInfo: any = {}) { + const components = component.components; + if (Array.isArray(components)) { + components.forEach(d => { + newComponents = newComponents.concat({ + npm: { + ...npm, + ...extraNpmInfo, + }, + ...d, + } || []); + }); + return; + } + newComponents = newComponents.concat({ + npm: { + ...npm, + ...extraNpmInfo, + }, + ...component.components, + } || []); + } + + function setArrayAssets(value: any[], preExportName: string = '', preSubName: string = '') { + value.forEach((d: any, i: number) => { + const exportName = [preExportName, i.toString()].filter(d => !!d).join('.'); + const subName = [preSubName, i.toString()].filter(d => !!d).join('.'); + Array.isArray(d) ? setArrayAssets(d, exportName, subName) : setAssetsComponent(d, { + exportName, + subName, + }); + }); + } + if (window[exportName]) { + if (Array.isArray(window[exportName])) { + setArrayAssets(window[exportName] as any); + } else { + setAssetsComponent(window[exportName] as any); + } + } + return window[exportName]; + }), + ); + } + } + const lowcodeComponentsArray = []; + const proCodeComponentsMap = newComponents.reduce((acc, cur) => { + if ((cur.devMode || '').toLowerCase() === 'lowcode') { + lowcodeComponentsArray.push(cur); + } else { + acc[cur.componentName] = { + ...(cur.reference || cur.npm), + componentName: cur.componentName, + }; + } + return acc; + }, {}) + + function genLowCodeComponentsMap(components) { + const lowcodeComponentsMap = {}; + lowcodeComponentsArray.forEach((lowcode) => { + const id = lowcode.reference?.id; + const schema = packagesMap[id]?.schema; + const comp = genLowcodeComp(schema, {...components, ...lowcodeComponentsMap}); + lowcodeComponentsMap[lowcode.componentName] = comp; + }); + return lowcodeComponentsMap; + } + let components = await injectComponents(buildComponents(libraryMap, proCodeComponentsMap)); + const lowCodeComponents = genLowCodeComponentsMap(components); + return { + components: { ...components, ...lowCodeComponents } + } +} + +function genLowcodeComp(schema: ComponentSchema, components: any) { + return class LowcodeComp extends React.Component { + render(): React.ReactNode { + return createElement(ReactRenderer, { + ...this.props, + schema, + components, + designMode: '', + }); + } + }; +} +``` +## 联系我们 + + \ No newline at end of file diff --git a/docs/docs/guide/expand/editor/parts/partslcc.md b/docs/docs/guide/expand/editor/parts/partslcc.md new file mode 100644 index 000000000..39f5dd46f --- /dev/null +++ b/docs/docs/guide/expand/editor/parts/partslcc.md @@ -0,0 +1,92 @@ +--- +title: 低代码组件 +sidebar_position: 2 +--- +## 什么是低代码组件 +我们先了解一下什么是低代码组件,为什么要用低代码组件。 + +低代码组件是通过可视化的方式生产的组件,这些组件既可以用于低代码搭建体系,也可以用于ProCode开发体系(后续迭代)。 + +那么为什么我们要使用低代码的形式来开发组件: +* 首先轻快,低代码组件只需通过浏览器秒级完成初始化工作,不需要ProCode繁重的环境准备;环境一致(低代码环境),同时能够保证物料的开发环境和真实的运行环境是一致的,不会存在开发和运行环境不一致的问题。 +* 其次通用能力可视化方式抽象,提升研发效能,比如获取远程数据、视图开发、依赖管理、生命周期、事件绑定等功能。 + +低代码组件不是用来替代 ProCode 的开发方式,而是让开发者可以从ProCode中重复的工作脱离出来,抽象更多业务垂直的能力,从而起到提效的作用。 + +## 创建组件 + +环境准备:我们可以通过Parts提供的通用[低代码组件开发环境](https://parts.lowcode-engine.cn/material#/)开发。 + +点击开发新组件 --> 填写组件标题 --> 填写组件名称 --> 点击确定,完成组件创建工作。 + +![](https://img.alicdn.com/imgextra/i2/O1CN01OTQRew25y6WxuONIx_!!6000000007594-2-tps-3396-1696.png) + +## 组件开发 + +一张图速览低代码组件开发的功能模块,其中大部分功能可以参考[低代码引擎文档](https://lowcode-engine.cn/site/docs/guide/quickStart/intro)。 + +![](https://img.alicdn.com/imgextra/i1/O1CN01gx96E121qzv4smV2v_!!6000000007037-2-tps-3456-1930.png) + +### 依赖管理 + +依赖管理用于管理低代码组件本身的依赖(类似于dependencies)。步骤:点击添加组件 --> 选择安装的组件 --> 保存并构建 (需要等待几分钟构建)。 + +![](https://img.alicdn.com/imgextra/i4/O1CN01wC9JPK1J9dKLca9wK_!!6000000000986-2-tps-1438-819.png) + +### 属性定义 + +用于定义组件接收外部传入的propTypes,组件内部可以通过this.props.${属性名称}的方式获取属性值。 + +属性定义前建议先阅读 [物料描述详解](https://lowcode-engine.cn/site/docs/guide/expand/editor/metaSpec)、[预置设置器](https://lowcode-engine.cn/site/docs/guide/appendix/setters)。 + +![](https://img.alicdn.com/imgextra/i2/O1CN01wesIJA1nL1eSPrk7U_!!6000000005072-2-tps-1438-821.png) + +![](https://img.alicdn.com/imgextra/i3/O1CN01FZIRwv1es9lGplgIB_!!6000000003926-2-tps-1438-821.png) + +### 生命周期 + +低代码组件的开发支持componentDidMount、componentDidUpdate、componentDidCatch、componentWillUnmount几个生命周期 + +![](https://img.alicdn.com/imgextra/i4/O1CN010bnrxJ1oLlujlfFqj_!!6000000005209-2-tps-1438-819.png) + +### 组件调试 + +我们提供了一套线上实时调试的方案,只需点击右上角的调试按钮,就能自动创建一个低代码应用,在这个应用中可以实时调试当前的低代码组件。 + +![](https://img.alicdn.com/imgextra/i2/O1CN01Tk96vp1xrDeNeIUJD_!!6000000006496-2-tps-1438-820.png) + +在低代码应用中使用,组件面板 --> 低代码组件, 找到对应的低代码组件拖入画布即可。 + +![](https://img.alicdn.com/imgextra/i2/O1CN01oGHLea1lzDAhZQQVO_!!6000000004889-2-tps-1438-819.png) + +### 组件发布 + +同时我们提供了组件发布的功能,用于组件版本管理,点击右上角的发布按钮即可发布组件 + +![](https://img.alicdn.com/imgextra/i2/O1CN017suVAD1NXEC8zQgO1_!!6000000001579-2-tps-1438-821.png) + +## 组件使用 + +组件的消费是通过资产包来管理的,详情请参考 [资产包管理](./partsassets)。 + +## 组件导出 + +开发好的低代码组件可以导出成为 React 组件,脱离低代码引擎独立使用。同时导出功能也为您的组件留出一份备份,您可以放心使用本产品的服务,而不用担心万一出现的不能服务的场景。 + +在物料列表页面,低代码组件会有一个导出的动作。 + +![](https://img.alicdn.com/imgextra/i2/O1CN016oUByO21spVHZvvw2_!!6000000007041-2-tps-1395-413.png) + +点击导出后,就会开启导出低代码组件的过程。这个过程持续 10s+,导出完成后会为您自动下载对应的 zip 包。 + +![](https://img.alicdn.com/imgextra/i1/O1CN01lctpIo1aDcEvu75Mo_!!6000000003296-2-tps-1399-512.png) + +zip 包解压后可以看到一个完整的组件脚手架工程,您可以在这个工程里继续开发调试,或者发布到合适的 npm 源中。 + +![](https://img.alicdn.com/imgextra/i1/O1CN010aAjsf1xYRPZBAh7d_!!6000000006455-2-tps-2154-1072.png) + +注意:目前导出功能暂不支持 低代码组件嵌套。 + +## 联系我们 + + \ No newline at end of file diff --git a/docs/docs/guide/expand/editor/partsIntro.md b/docs/docs/guide/expand/editor/parts/prototype.md similarity index 78% rename from docs/docs/guide/expand/editor/partsIntro.md rename to docs/docs/guide/expand/editor/parts/prototype.md index 174afc37a..71a4f3d01 100644 --- a/docs/docs/guide/expand/editor/partsIntro.md +++ b/docs/docs/guide/expand/editor/parts/prototype.md @@ -1,5 +1,5 @@ --- -title: 利用 Parts 造物快速使用 react 组件 +title: React 组件导入 sidebar_position: 3 --- ## 介绍 @@ -50,10 +50,8 @@ sidebar_position: 3 ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01klci7y1IUPflKpeVB_!!6000000000896-2-tps-1193-704.png) #### 给组件增加物料描述 -选中刚刚新增的 BlockPicker 组件,然后给它增加描述: - - 打开左侧 Setter 面板 -- 按照组件的属性拖入需要 Setter 类型(如图中组件的 width 属性,拖入数字 Setter) +- 按照组件的属性拖入需要 Setter 类型 (如图中组件的width属性,拖入数字Setter) - 各种 Setter 的介绍可以参看这篇文档:[预置设置器列表](/site/docs/guide/appendix/setters) - 配置属性的基本信息(如图所示) - 配置完成后点击右上角的保存 @@ -102,31 +100,22 @@ sidebar_position: 3 - 点击确定发布完成 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01uwa8RH1QDwM7FN31k_!!6000000001943-2-tps-1431-734.png) - -## 资产包构建 - +## 资产包 第三步:物料描述发布完成后,接下来我们就需要构建出可用的资产包用于低代码应用中。 #### 资产包构建 +有两种方式可以构建资产包: +- 一种是通过 [`我的资产包`] 资产包管理模块进行整个资产包生命周期的管理,当然也包括资产包的构建,可参考 [资产包管理](./partsassets) +- 一种是通过 [`我的物料`] 组件物料管理模块的 `资产包构建` 进行构建, 具体操作如下: -- 选择需要构建的组件 -- 点击构建资产包按钮 -- 选择刚刚的物料描述配置 -- 开始构建,构建完成后你将得到一份 json 文件(里面包含了物料描述和 umd 包),就可以到项目中使用了 - -![image.png](https://img.alicdn.com/imgextra/i3/O1CN01Oc73aw1TH5vlJx9oj_!!6000000002356-2-tps-1431-770.png) + - 选择需要构建的组件 + - 点击构建资产包按钮 + - 选择刚刚的物料描述配置 + - 开始构建,构建完成后你将得到一份json文件(里面包含了物料描述和umd包),就可以到项目中使用了 #### 资产包使用 +详情请参考 [资产包管理](./partsassets#使用资产包) -**方式一、在 **[**lowcode-demo**](https://github.com/alibaba/lowcode-demo)**中直接引用,可直接替换 demo 中原来的资产包文件:** +## 联系我们 -例如,在 basic-fusion demo 中,直接用你的资产包文件替换文件[assets.json](https://github.com/alibaba/lowcode-demo/blob/main/demo-basic-fusion/src/services/assets.json),即可快速使用自己的物料了。 - -**方式二、将新的资产包内容和现有的资产包内容融合:** - -将上面构建完成的资产包与你项目中的[assets.json 文件](https://github.com/alibaba/lowcode-demo/blob/main/demo-basic-fusion/src/services/assets.json)合并,主要合并 packages 和 components。 - -- packages 中是构建好的 umd 包; -- components 中是上面配置好的[物料描述](https://lowcode-engine.cn/material),你也可以在基础上二次加工; - -![image.png](https://img.alicdn.com/imgextra/i3/O1CN01m7QkDN1P7hL86mjyH_!!6000000001794-2-tps-1140-744.png) + diff --git a/docs/docs/guide/expand/editor/pluginContextMenu.md b/docs/docs/guide/expand/editor/pluginContextMenu.md index 2f1ab737c..e9dbdf3c4 100644 --- a/docs/docs/guide/expand/editor/pluginContextMenu.md +++ b/docs/docs/guide/expand/editor/pluginContextMenu.md @@ -2,7 +2,9 @@ title: 插件扩展 - 编排扩展 sidebar_position: 6 --- + ## 场景一:扩展选中节点操作项 + ### 增加节点操作项 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01J7PrJc1S86XNDBIFQ_!!6000000002201-2-tps-1240-292.png) @@ -31,7 +33,7 @@ const addHelloAction = (ctx: IPublicModelPluginContext) => { }, important: true, }); - } + }, }; }; addHelloAction.pluginName = 'addHelloAction'; @@ -68,6 +70,7 @@ await plugins.register(removeCopyAction); 具体 API 参考:[API 文档](/site/docs/api/material#removebuiltincomponentaction) ## 实际案例 + ### 区块管理 - 仓库地址:[https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins) diff --git a/docs/docs/guide/expand/editor/pluginWidget.md b/docs/docs/guide/expand/editor/pluginWidget.md index c319bb2a3..7efaffcf0 100644 --- a/docs/docs/guide/expand/editor/pluginWidget.md +++ b/docs/docs/guide/expand/editor/pluginWidget.md @@ -2,6 +2,7 @@ title: 插件扩展 - 面板扩展 sidebar_position: 5 --- + ## 插件简述 插件功能赋予低代码引擎更高的灵活性,低代码引擎的生态提供了一些官方的插件,但是无法满足所有人的需求,所以提供了强大的插件定制功能。 @@ -23,7 +24,7 @@ import { IPublicModelPluginContext } from '@alilc/lowcode-types'; const pluginA = (ctx: IPublicModelPluginContext, options: any) => { return { init() { - console.log(options.key); + console.log(options.key); // 往引擎增加面板 ctx.skeleton.add({ // area 配置见下方说明 @@ -36,9 +37,9 @@ const pluginA = (ctx: IPublicModelPluginContext, options: any) => { }, destroy() { console.log('我被销毁了~'); - } - } -} + }, + }; +}; pluginA.pluginName = 'pluginA'; @@ -56,6 +57,7 @@ plugins.register(pluginA, { key: 'test' }); ![image.png](https://img.alicdn.com/imgextra/i3/O1CN01y05ZHC1Gix0p4nXxH_!!6000000000657-2-tps-3068-1648.png) ### 展示区域 area + #### topArea 展示在设计器的顶部区域,常见的相关区域的插件主要是:、 @@ -76,6 +78,7 @@ plugins.register(pluginA, { key: 'test' }); 4. JS 等代码面板。 可以发现,这个区域的面板大多数操作时是不需要同时并存的,且交互比较复杂的,需要一个更整块的区域来进行操作。 + #### centerArea 画布区域,由于画布大多数是展示作用,所以一般扩展的种类比较少。常见的扩展有: @@ -106,12 +109,12 @@ PanelDock 是以面板的形式展示在设计器的左侧区域的。其中主 接入可以参考代码 ```javascript -import { skeleton } from "@alilc/lowcode-engine"; +import { skeleton } from '@alilc/lowcode-engine'; skeleton.add({ - area: "leftArea", // 插件区域 - type: "PanelDock", // 插件类型,弹出面板 - name: "sourceEditor", + area: 'leftArea', // 插件区域 + type: 'PanelDock', // 插件类型,弹出面板 + name: 'sourceEditor', content: SourceEditor, // 插件组件实例 props: { align: "left", @@ -139,12 +142,12 @@ Widget 形式是直接渲染在当前编辑器的对应位置上。如 demo 中 接入可以参考代码: ```javascript -import {skeleton} from "@alilc/lowcode-engine"; +import { skeleton } from '@alilc/lowcode-engine'; // 注册 logo 面板 skeleton.add({ - area: "topArea", - type: "Widget", - name: "logo", + area: 'topArea', + type: 'Widget', + name: 'logo', content: Logo, // Widget 组件实例 contentProps: { // Widget 插件 props logo: @@ -152,7 +155,7 @@ skeleton.add({ href: "/", }, props: { - align: "left", + align: 'left', width: 100, }, }); @@ -163,7 +166,7 @@ skeleton.add({ 一个图标的表现形式,可以用于语言切换、跳转到外部链接、打开一个 widget 等场景。 ```javascript -import { skeleton } from "@alilc/lowcode-engine"; +import { skeleton } from '@alilc/lowcode-engine'; skeleton.add({ area: 'leftArea', @@ -176,12 +179,12 @@ skeleton.add({ props: { align: 'bottom', }, - onClick: function() { + onClick: function () { // 打开外部链接 window.open('https://lowcode-engine.cn'); // 显示 widget skeleton.showWidget('xxx'); - } + }, }); ``` @@ -211,4 +214,4 @@ skeleton.add({ - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - ICON 优化](https://www.bilibili.com/video/BV1zr4y1H7Km/) - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - 自动截图](https://www.bilibili.com/video/BV1GZ4y117VH/) - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - 样式优化](https://www.bilibili.com/video/BV1Pi4y1S7ZT/) - - [阿里低代码引擎项目实战 (12)-区块管理 (完结)-给引擎插件提个 PR](https://www.bilibili.com/video/BV1hB4y1277o/) \ No newline at end of file + - [阿里低代码引擎项目实战 (12)-区块管理 (完结)-给引擎插件提个 PR](https://www.bilibili.com/video/BV1hB4y1277o/) diff --git a/docs/docs/guide/expand/editor/setter.md b/docs/docs/guide/expand/editor/setter.md index 6a720374f..01fd949bb 100644 --- a/docs/docs/guide/expand/editor/setter.md +++ b/docs/docs/guide/expand/editor/setter.md @@ -1,6 +1,6 @@ --- title: 设置器扩展 -sidebar_position: 4 +sidebar_position: 5 --- ## 设置器简述 From 1cfb388e30ea40b94fdca62e4e0a5f9cdce6cc83 Mon Sep 17 00:00:00 2001 From: JackLian Date: Wed, 11 Jan 2023 16:21:38 +0800 Subject: [PATCH 09/89] chore: publish docs 1.0.15 --- docs/docs/faq/faq015.md | 2 +- docs/docs/guide/expand/editor/metaSpec.md | 2 +- docs/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/faq/faq015.md b/docs/docs/faq/faq015.md index 48e97bc22..683e7df3a 100644 --- a/docs/docs/faq/faq015.md +++ b/docs/docs/faq/faq015.md @@ -4,4 +4,4 @@ sidebar_position: 15 tags: [FAQ] --- 你可以通过在线工具「Parts 造物」生产物料描述协议,然后使用到你的项目中去。 -文档地址:[利用 Parts 造物快速使用 react 组件](/site/docs/guide/expand/editor/partsIntro) +文档地址:[利用 Parts 造物快速使用 react 组件](/site/docs/guide/expand/editor/parts/partsIntro) diff --git a/docs/docs/guide/expand/editor/metaSpec.md b/docs/docs/guide/expand/editor/metaSpec.md index 2e70550ac..2f874925f 100644 --- a/docs/docs/guide/expand/editor/metaSpec.md +++ b/docs/docs/guide/expand/editor/metaSpec.md @@ -10,7 +10,7 @@ sidebar_position: 2 ## 可视化生成物料描述 -使用 Parts 造物平台:[使用文档](/site/docs/guide/expand/editor/partsIntro) +使用 Parts 造物平台:[使用文档](/site/docs/guide/expand/editor/parts/partsIntro) ## 自动生成物料描述 diff --git a/docs/package.json b/docs/package.json index 4102563dc..5488b601d 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.14", + "version": "1.0.15", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 0dc59e86a4f8314f3f9b41d7661a8b95b1e4ae86 Mon Sep 17 00:00:00 2001 From: eternalsky Date: Wed, 11 Jan 2023 17:01:41 +0800 Subject: [PATCH 10/89] fix: docs order & some docs lint problems --- .../guide/expand/editor/parts/partsassets.md | 14 +++++++------- .../guide/expand/editor/parts/partslcc.md | 16 ++++++++-------- .../guide/expand/editor/parts/prototype.md | 6 +++--- docs/scripts/getDocsFromDir.js | 19 ++++++++++++------- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/docs/docs/guide/expand/editor/parts/partsassets.md b/docs/docs/guide/expand/editor/parts/partsassets.md index a8525f64c..00670ecad 100644 --- a/docs/docs/guide/expand/editor/parts/partsassets.md +++ b/docs/docs/guide/expand/editor/parts/partsassets.md @@ -5,7 +5,7 @@ sidebar_position: 4 ## 介绍 -通过前述介绍,相信大家已经了解如何使用 「[Parts·造物](https://parts.lowcode-engine.cn/)」 来将已有的 React 组件快速接入低代码引擎,以及生产低代码组件。 +通过前述介绍,相信大家已经了解如何使用「[Parts·造物](https://parts.lowcode-engine.cn/)」来将已有的 React 组件快速接入低代码引擎,以及生产低代码组件。 大家在使用的过程中,可能会希望构建出来的资产包可以后续随时访问下载,或者希望构建资产包时各个组件的版本等信息可以持久化起来并且能够多人维护。 @@ -20,7 +20,7 @@ sidebar_position: 4 - 填写资产包名称 - 配置资产包管理员,管理员拥有该资产包的所有权限,初始默认为资产包的创建者,还可以添加其他人作为管理员, -- 配置资产包描述(可选) +- 配置资产包描述 (可选) - 点击 `确定`, 即可完成资产包的创建 接下来需要为资产包添加一个或者多个组件。 @@ -43,12 +43,12 @@ sidebar_position: 4 - `开启缓存` : 可充分利用之前的构建结果缓存来加速资产包的生成,我们会将每个组件的构建结果以 包名和版本号为 key 进行缓存。 - `任务描述` : 当前构建任务的一些描述信息。 -点击 `确认` 按钮 会自动跳转到当前资产包的构建历史界面: +点击 `确认` 按钮 会自动跳转到当前资产包的构建历史界面: ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01krDaFc1TuTztMPssI_!!6000000002442-2-tps-1726-696.png) -构建历史界面会显示当前资产包所有的构建历史记录,表格状态栏展示了构建的状态:`成功`,`失败`,`正在运行` 三种状态, 操作列可以在构建成功时复制或者下载资产包结果 +构建历史界面会显示当前资产包所有的构建历史记录,表格状态栏展示了构建的状态:`成功`,`失败`,`正在运行` 三种状态,操作列可以在构建成功时复制或者下载资产包结果 ## 使用资产包 -你可以在 [lowcode-demo](https://github.com/alibaba/lowcode-demo) 中直接引用,可直接替换demo中原来的资产包文件: +你可以在 [lowcode-demo](https://github.com/alibaba/lowcode-demo) 中直接引用,可直接替换 demo 中原来的资产包文件: 例如,在 [demo-lowcode-component](https://github.com/alibaba/lowcode-demo/tree/main/demo-lowcode-component) 中,直接用你的资产包文件替换文件[assets.json](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/services/assets.json),即可快速使用自己的物料了。 ### 在编辑器中使用资产包 @@ -56,7 +56,7 @@ sidebar_position: 4 然后直接替换 [lowcode-demo](https://github.com/alibaba/lowcode-demo) demo 中的 `assets.json` 文件即可。 ### 在预览中使用资产包 -在预览中使用资产包的整体思路是从 `资产包` 中提取并转换出 `ReactRenderer` 渲染所需要的 react 组件列表(`components` 参数),然后将 `schema` 以及 `components` 传入到 `ReactRenderer` 中进行渲染,需要注意的是,在 `资产包` 的转换过程中,我们也需要将 `低代码组件` 转换成 react 组件, 具体逻辑可以参考下 [demo-lowcode-component](https://github.com/alibaba/lowcode-demo/tree/main/demo-lowcode-component) 中 `src/parse-assets.ts` 文件的实现。 +在预览中使用资产包的整体思路是从 `资产包` 中提取并转换出 `ReactRenderer` 渲染所需要的 react 组件列表 (`components` 参数),然后将 `schema` 以及 `components` 传入到 `ReactRenderer` 中进行渲染,需要注意的是,在 `资产包` 的转换过程中,我们也需要将 `低代码组件` 转换成 react 组件,具体逻辑可以参考下 [demo-lowcode-component](https://github.com/alibaba/lowcode-demo/tree/main/demo-lowcode-component) 中 `src/parse-assets.ts` 文件的实现。 基于资产包进行预览的整体逻辑如下: [详见](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/preview.tsx): ```ts import ReactDOM from 'react-dom'; @@ -125,7 +125,7 @@ const SamplePreview = () => { ReactDOM.render(, document.getElementById('ice-container')); ``` -从资产包中解析 react 组件列表的逻辑如下, [详见](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/parse-assets.ts): +从资产包中解析 react 组件列表的逻辑如下,[详见](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/parse-assets.ts): ```ts import { ComponentDescription, ComponentSchema, RemoteComponentDescription } from '@alilc/lowcode-types'; import { buildComponents, AssetsJson, AssetLoader } from '@alilc/lowcode-utils'; diff --git a/docs/docs/guide/expand/editor/parts/partslcc.md b/docs/docs/guide/expand/editor/parts/partslcc.md index 39f5dd46f..4d24b72f3 100644 --- a/docs/docs/guide/expand/editor/parts/partslcc.md +++ b/docs/docs/guide/expand/editor/parts/partslcc.md @@ -5,17 +5,17 @@ sidebar_position: 2 ## 什么是低代码组件 我们先了解一下什么是低代码组件,为什么要用低代码组件。 -低代码组件是通过可视化的方式生产的组件,这些组件既可以用于低代码搭建体系,也可以用于ProCode开发体系(后续迭代)。 +低代码组件是通过可视化的方式生产的组件,这些组件既可以用于低代码搭建体系,也可以用于 ProCode 开发体系(后续迭代)。 那么为什么我们要使用低代码的形式来开发组件: -* 首先轻快,低代码组件只需通过浏览器秒级完成初始化工作,不需要ProCode繁重的环境准备;环境一致(低代码环境),同时能够保证物料的开发环境和真实的运行环境是一致的,不会存在开发和运行环境不一致的问题。 +* 首先轻快,低代码组件只需通过浏览器秒级完成初始化工作,不需要 ProCode 繁重的环境准备;环境一致(低代码环境),同时能够保证物料的开发环境和真实的运行环境是一致的,不会存在开发和运行环境不一致的问题。 * 其次通用能力可视化方式抽象,提升研发效能,比如获取远程数据、视图开发、依赖管理、生命周期、事件绑定等功能。 -低代码组件不是用来替代 ProCode 的开发方式,而是让开发者可以从ProCode中重复的工作脱离出来,抽象更多业务垂直的能力,从而起到提效的作用。 +低代码组件不是用来替代 ProCode 的开发方式,而是让开发者可以从 ProCode 中重复的工作脱离出来,抽象更多业务垂直的能力,从而起到提效的作用。 ## 创建组件 -环境准备:我们可以通过Parts提供的通用[低代码组件开发环境](https://parts.lowcode-engine.cn/material#/)开发。 +环境准备:我们可以通过 Parts 提供的通用[低代码组件开发环境](https://parts.lowcode-engine.cn/material#/)开发。 点击开发新组件 --> 填写组件标题 --> 填写组件名称 --> 点击确定,完成组件创建工作。 @@ -29,13 +29,13 @@ sidebar_position: 2 ### 依赖管理 -依赖管理用于管理低代码组件本身的依赖(类似于dependencies)。步骤:点击添加组件 --> 选择安装的组件 --> 保存并构建 (需要等待几分钟构建)。 +依赖管理用于管理低代码组件本身的依赖(类似于 dependencies)。步骤:点击添加组件 --> 选择安装的组件 --> 保存并构建 (需要等待几分钟构建)。 ![](https://img.alicdn.com/imgextra/i4/O1CN01wC9JPK1J9dKLca9wK_!!6000000000986-2-tps-1438-819.png) ### 属性定义 -用于定义组件接收外部传入的propTypes,组件内部可以通过this.props.${属性名称}的方式获取属性值。 +用于定义组件接收外部传入的 propTypes,组件内部可以通过this.props.${属性名称}的方式获取属性值。 属性定义前建议先阅读 [物料描述详解](https://lowcode-engine.cn/site/docs/guide/expand/editor/metaSpec)、[预置设置器](https://lowcode-engine.cn/site/docs/guide/appendix/setters)。 @@ -45,7 +45,7 @@ sidebar_position: 2 ### 生命周期 -低代码组件的开发支持componentDidMount、componentDidUpdate、componentDidCatch、componentWillUnmount几个生命周期 +低代码组件的开发支持 componentDidMount、componentDidUpdate、componentDidCatch、componentWillUnmount 几个生命周期 ![](https://img.alicdn.com/imgextra/i4/O1CN010bnrxJ1oLlujlfFqj_!!6000000005209-2-tps-1438-819.png) @@ -55,7 +55,7 @@ sidebar_position: 2 ![](https://img.alicdn.com/imgextra/i2/O1CN01Tk96vp1xrDeNeIUJD_!!6000000006496-2-tps-1438-820.png) -在低代码应用中使用,组件面板 --> 低代码组件, 找到对应的低代码组件拖入画布即可。 +在低代码应用中使用,组件面板 --> 低代码组件,找到对应的低代码组件拖入画布即可。 ![](https://img.alicdn.com/imgextra/i2/O1CN01oGHLea1lzDAhZQQVO_!!6000000004889-2-tps-1438-819.png) diff --git a/docs/docs/guide/expand/editor/parts/prototype.md b/docs/docs/guide/expand/editor/parts/prototype.md index 71a4f3d01..b90728f65 100644 --- a/docs/docs/guide/expand/editor/parts/prototype.md +++ b/docs/docs/guide/expand/editor/parts/prototype.md @@ -51,7 +51,7 @@ sidebar_position: 3 #### 给组件增加物料描述 - 打开左侧 Setter 面板 -- 按照组件的属性拖入需要 Setter 类型 (如图中组件的width属性,拖入数字Setter) +- 按照组件的属性拖入需要 Setter 类型(如图中组件的 width 属性,拖入数字 Setter) - 各种 Setter 的介绍可以参看这篇文档:[预置设置器列表](/site/docs/guide/appendix/setters) - 配置属性的基本信息(如图所示) - 配置完成后点击右上角的保存 @@ -104,14 +104,14 @@ sidebar_position: 3 第三步:物料描述发布完成后,接下来我们就需要构建出可用的资产包用于低代码应用中。 #### 资产包构建 -有两种方式可以构建资产包: +有两种方式可以构建资产包: - 一种是通过 [`我的资产包`] 资产包管理模块进行整个资产包生命周期的管理,当然也包括资产包的构建,可参考 [资产包管理](./partsassets) - 一种是通过 [`我的物料`] 组件物料管理模块的 `资产包构建` 进行构建, 具体操作如下: - 选择需要构建的组件 - 点击构建资产包按钮 - 选择刚刚的物料描述配置 - - 开始构建,构建完成后你将得到一份json文件(里面包含了物料描述和umd包),就可以到项目中使用了 + - 开始构建,构建完成后你将得到一份 json 文件(里面包含了物料描述和 umd 包),就可以到项目中使用了 #### 资产包使用 详情请参考 [资产包管理](./partsassets#使用资产包) diff --git a/docs/scripts/getDocsFromDir.js b/docs/scripts/getDocsFromDir.js index 666d92c3c..18e67e718 100644 --- a/docs/scripts/getDocsFromDir.js +++ b/docs/scripts/getDocsFromDir.js @@ -8,9 +8,14 @@ module.exports = function getDocsFromDir(dir, cateList) { const baseDir = path.join(__dirname, '../docs/'); const docsDir = path.join(baseDir, dir); + function isNil(value) { + return value === undefined || value === null; + } + function getMarkdownOrder(filepath) { - const data = matter(fs.readFileSync(filepath, 'utf-8')).data; - return (data || {}).sidebar_position || 100; + const { data } = matter(fs.readFileSync(filepath, 'utf-8')); + const { sidebar_position } = data || {}; + return isNil(sidebar_position) ? 100 : sidebar_position; } const docs = glob.sync('*.md?(x)', { @@ -19,17 +24,17 @@ module.exports = function getDocsFromDir(dir, cateList) { }); const result = docs - .filter(doc => !/^index.md(x)?$/.test(doc)) - .map(doc => { + .filter((doc) => !/^index.md(x)?$/.test(doc)) + .map((doc) => { return path.join(docsDir, doc); }) .sort((a, b) => { const orderA = getMarkdownOrder(a); const orderB = getMarkdownOrder(b); - return orderB - orderA; + return orderA - orderB; }) - .map(filepath => { + .map((filepath) => { // /Users/xxx/site/docs/guide/basic/router.md => guide/basic/router const id = path .relative(baseDir, filepath) @@ -38,7 +43,7 @@ module.exports = function getDocsFromDir(dir, cateList) { return id; }); - (cateList || []).forEach(item => { + (cateList || []).forEach((item) => { const { dir, subCategory, ...otherConfig } = item; const indexList = glob.sync('index.md?(x)', { cwd: path.join(baseDir, dir), From c1299e3143b41a924ccc656443f449e04d623bd1 Mon Sep 17 00:00:00 2001 From: JackLian Date: Thu, 12 Jan 2023 08:58:50 +0800 Subject: [PATCH 11/89] chore: publish docs 1.0.17 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 5488b601d..613cb4831 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.15", + "version": "1.0.17", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 8537eff8934490e037cc33cc9889e2dfb119c720 Mon Sep 17 00:00:00 2001 From: JackLian Date: Thu, 12 Jan 2023 11:37:22 +0800 Subject: [PATCH 12/89] fix: fix lint issues in shell --- docs/docs/api/model/detecting.md | 2 +- .../designer/src/designer/active-tracker.ts | 2 +- packages/designer/src/designer/designer.ts | 46 +++++++--- packages/designer/src/designer/detecting.ts | 22 +++-- .../designer/src/document/document-model.ts | 35 +++++--- packages/designer/src/document/history.ts | 5 +- .../src/document/node/node-children.ts | 59 +++++++------ packages/designer/src/document/node/node.ts | 64 ++++++++++---- packages/designer/src/project/project.ts | 86 ++++++++++++++----- packages/editor-core/src/hotkey.ts | 23 ++--- packages/shell/src/api/canvas.ts | 28 +++--- packages/shell/src/api/common.tsx | 4 +- packages/shell/src/api/event.ts | 6 -- packages/shell/src/api/hotkey.ts | 12 ++- packages/shell/src/api/material.ts | 28 +++--- packages/shell/src/api/plugins.ts | 10 ++- packages/shell/src/api/project.ts | 32 ++++--- packages/shell/src/api/skeleton.ts | 6 +- packages/shell/src/api/workspace.ts | 11 ++- packages/shell/src/model/active-tracker.ts | 12 ++- packages/shell/src/model/component-meta.ts | 17 ++-- packages/shell/src/model/detecting.ts | 9 +- packages/shell/src/model/document-model.ts | 63 +++++++------- packages/shell/src/model/drag-object.ts | 2 +- packages/shell/src/model/dragon.ts | 6 +- packages/shell/src/model/drop-location.ts | 2 +- packages/shell/src/model/history.ts | 8 +- packages/shell/src/model/index.ts | 5 +- packages/shell/src/model/node-children.ts | 33 +++---- packages/shell/src/model/node.ts | 11 ++- packages/types/src/shell/api/hotkey.ts | 12 ++- packages/types/src/shell/api/project.ts | 3 +- .../types/src/shell/model/component-meta.ts | 2 +- packages/types/src/shell/model/detecting.ts | 2 +- packages/types/src/shell/model/editor.ts | 4 +- .../src/shell/type/hotkey-callback-config.ts | 10 +++ .../types/src/shell/type/hotkey-callbacks.ts | 5 ++ packages/types/src/shell/type/index.ts | 4 +- 38 files changed, 429 insertions(+), 262 deletions(-) create mode 100644 packages/types/src/shell/type/hotkey-callback-config.ts create mode 100644 packages/types/src/shell/type/hotkey-callbacks.ts diff --git a/docs/docs/api/model/detecting.md b/docs/docs/api/model/detecting.md index c7a20ddcb..ccd60e3a6 100644 --- a/docs/docs/api/model/detecting.md +++ b/docs/docs/api/model/detecting.md @@ -77,7 +77,7 @@ hover 节点变化事件 * set callback which will be called when hovering object changed. * @since v1.1.0 */ -onDetectingChange(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; +onDetectingChange(fn: (node: IPublicModelNode | null) => void): IPublicTypeDisposable; ``` 相关类型: diff --git a/packages/designer/src/designer/active-tracker.ts b/packages/designer/src/designer/active-tracker.ts index d62ad9fe5..6c7dc9104 100644 --- a/packages/designer/src/designer/active-tracker.ts +++ b/packages/designer/src/designer/active-tracker.ts @@ -6,7 +6,7 @@ import { } from '@alilc/lowcode-types'; import { isNode } from '@alilc/lowcode-utils'; -export interface IActiveTracker extends IPublicModelActiveTracker { +export interface IActiveTracker extends Omit< IPublicModelActiveTracker, 'track' > { track(originalTarget: IPublicTypeActiveTarget | INode): void; } diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 6e4b3c63e..6ade5fea0 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -17,17 +17,16 @@ import { IPublicTypeLocationData, IPublicEnumTransformStage, IPublicModelDragon, - IPublicModelActiveTracker, IPublicModelDropLocation, } from '@alilc/lowcode-types'; import { megreAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils'; import { Project } from '../project'; import { Node, DocumentModel, insertChildren, INode } from '../document'; -import { ComponentMeta } from '../component-meta'; +import { ComponentMeta, IComponentMeta } from '../component-meta'; import { INodeSelector, Component } from '../simulator'; import { Scroller } from './scroller'; -import { Dragon, ILocateEvent } from './dragon'; -import { ActiveTracker } from './active-tracker'; +import { Dragon, IDragon, ILocateEvent } from './dragon'; +import { ActiveTracker, IActiveTracker } from './active-tracker'; import { Detecting } from './detecting'; import { DropLocation } from './location'; import { OffsetObserver, createOffsetObserver } from './offset-observer'; @@ -56,24 +55,49 @@ export interface DesignerProps { onMount?: (designer: Designer) => void; onDragstart?: (e: ILocateEvent) => void; onDrag?: (e: ILocateEvent) => void; - onDragend?: (e: { dragObject: IPublicModelDragObject; copy: boolean }, loc?: DropLocation) => void; + onDragend?: ( + e: { dragObject: IPublicModelDragObject; copy: boolean }, + loc?: DropLocation, + ) => void; } export interface IDesigner { + get dragon(): IPublicModelDragon; - get activeTracker(): IPublicModelActiveTracker; + + get activeTracker(): IActiveTracker; + + get componentActions(): ComponentActions; + + get editor(): IPublicModelEditor; + createScroller(scrollable: IPublicModelScrollable): IPublicModelScroller; /** * 创建插入位置,考虑放到 dragon 中 */ createLocation(locationData: IPublicTypeLocationData): IPublicModelDropLocation; + + get componentsMap(): { [key: string]: IPublicTypeNpmInfo | Component }; + + loadIncrementalAssets(incrementalAssets: IPublicTypeAssetsJson): Promise; + + getComponentMeta( + componentName: string, + generateMetadata?: () => IPublicTypeComponentMetadata | null, + ): IComponentMeta; + + createComponentMeta(data: IPublicTypeComponentMetadata): IComponentMeta | null; + + getComponentMetasMap(): Map; + + addPropsReducer(reducer: IPublicTypePropsTransducer, stage: IPublicEnumTransformStage): void; } export class Designer implements IDesigner { - public dragon: Dragon; + dragon: IDragon; - public viewName: string | undefined; + viewName: string | undefined; readonly componentActions = new ComponentActions(); @@ -99,7 +123,7 @@ export class Designer implements IDesigner { private oobxList: OffsetObserver[] = []; - @obx.ref private _componentMetasMap = new Map(); + @obx.ref private _componentMetasMap = new Map(); @obx.ref private _simulatorComponent?: ComponentType; @@ -483,7 +507,7 @@ export class Designer implements IDesigner { metas.forEach((data) => this.createComponentMeta(data)); } - createComponentMeta(data: IPublicTypeComponentMetadata): ComponentMeta | null { + createComponentMeta(data: IPublicTypeComponentMetadata): IComponentMeta | null { const key = data.componentName; if (!key) { return null; @@ -515,7 +539,7 @@ export class Designer implements IDesigner { getComponentMeta( componentName: string, generateMetadata?: () => IPublicTypeComponentMetadata | null, - ) { + ): IComponentMeta { if (this._componentMetasMap.has(componentName)) { return this._componentMetasMap.get(componentName)!; } diff --git a/packages/designer/src/designer/detecting.ts b/packages/designer/src/designer/detecting.ts index b7ada8138..3a6082d5c 100644 --- a/packages/designer/src/designer/detecting.ts +++ b/packages/designer/src/designer/detecting.ts @@ -1,14 +1,18 @@ import { makeObservable, obx, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; -import { IPublicModelDetecting, IPublicModelNode, IPublicModelDocumentModel } from '@alilc/lowcode-types'; +import { IPublicModelDetecting } from '@alilc/lowcode-types'; +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' > { - capture(node: IPublicModelNode | null): void; + capture(node: INode | null): void; - release(node: IPublicModelNode | null): void; + release(node: INode | null): void; - leave(document: IPublicModelDocumentModel | undefined): void; + leave(document: IDocumentModel | undefined): void; + + get current(): INode | null; } export class Detecting implements IDetecting { @@ -31,7 +35,7 @@ export class Detecting implements IDetecting { @obx.ref xRayMode = false; - @obx.ref private _current: IPublicModelNode | null = null; + @obx.ref private _current: INode | null = null; private emitter: IEventBus = createModuleEventBus('Detecting'); @@ -43,27 +47,27 @@ export class Detecting implements IDetecting { return this._current; } - capture(node: IPublicModelNode | null) { + capture(node: INode | null) { if (this._current !== node) { this._current = node; this.emitter.emit(DETECTING_CHANGE_EVENT, this.current); } } - release(node: IPublicModelNode | null) { + release(node: INode | null) { if (this._current === node) { this._current = null; this.emitter.emit(DETECTING_CHANGE_EVENT, this.current); } } - leave(document: IPublicModelDocumentModel | undefined) { + leave(document: IDocumentModel | undefined) { if (this.current && this.current.document === document) { this._current = null; } } - onDetectingChange(fn: (node: IPublicModelNode) => void) { + onDetectingChange(fn: (node: INode) => void) { this.emitter.on(DETECTING_CHANGE_EVENT, fn); return () => { this.emitter.off(DETECTING_CHANGE_EVENT, fn); diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index cb345cc82..26648403b 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -9,21 +9,18 @@ import { IPublicTypeDragNodeDataObject, IPublicModelDocumentModel, IPublicModelHistory, - IPublicModelModalNodesManager, IPublicModelNode, - IPublicApiProject, - IPublicModelDropLocation, IPublicEnumTransformStage, IPublicTypeOnChangeOptions, } from '@alilc/lowcode-types'; -import { Project } from '../project'; +import { IProject, Project } from '../project'; import { ISimulatorHost } from '../simulator'; import { ComponentMeta } from '../component-meta'; -import { IDropLocation, Designer } from '../designer'; +import { IDropLocation, Designer, IHistory } from '../designer'; import { Node, insertChildren, insertChild, isNode, RootNode, INode } from './node/node'; import { Selection, ISelection } from './selection'; import { History } from './history'; -import { ModalNodesManager } from './node'; +import { IModalNodesManager, ModalNodesManager } from './node'; import { uniqueId, isPlainObject, compatStage, isJSExpression, isDOMText, isNodeSchema, isDragNodeObject, isDragNodeDataObject } from '@alilc/lowcode-utils'; import { EDITOR_EVENT } from '../types'; @@ -44,17 +41,31 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'select */ readonly selection: ISelection; + readonly project: IProject; + + /** + * 模态节点管理 + */ + readonly modalNodesManager: IModalNodesManager; + /** * 根据 id 获取节点 */ getNode(id: string): INode | null; + + getHistory(): IHistory; + + get focusNode(): INode | null; + + get rootNode(): INode | null; + } export class DocumentModel implements IDocumentModel { /** * 根节点 类型有:Page/Component/Block */ - rootNode: RootNode | null; + rootNode: INode | null; /** * 文档编号 @@ -74,11 +85,11 @@ export class DocumentModel implements IDocumentModel { /** * 模态节点管理 */ - readonly modalNodesManager: IPublicModelModalNodesManager; + readonly modalNodesManager: IModalNodesManager; private _nodesMap = new Map(); - readonly project: IPublicApiProject; + readonly project: IProject; readonly designer: Designer; @@ -114,7 +125,7 @@ export class DocumentModel implements IDocumentModel { this.rootNode?.getExtraProp('fileName', true)?.setValue(fileName); } - get focusNode() { + get focusNode(): INode { if (this._drillDownNode) { return this._drillDownNode; } @@ -147,7 +158,7 @@ export class DocumentModel implements IDocumentModel { @obx.ref private _dropLocation: IDropLocation | null = null; - set dropLocation(loc: IPublicModelDropLocation | null) { + set dropLocation(loc: IDropLocation | null) { this._dropLocation = loc; // pub event this.designer.editor.eventBus.emit( @@ -626,7 +637,7 @@ export class DocumentModel implements IDocumentModel { return data; } - getHistory(): History { + getHistory(): IHistory { return this.history; } diff --git a/packages/designer/src/document/history.ts b/packages/designer/src/document/history.ts index 5d52f0dd3..5de6ca78a 100644 --- a/packages/designer/src/document/history.ts +++ b/packages/designer/src/document/history.ts @@ -193,7 +193,7 @@ export class History implements IHistory { return this.onStateChange(func); } - onStateChange(func: () => any) { + onStateChange(func: () => any): () => void { this.emitter.on('statechange', func); return () => { this.emitter.removeListener('statechange', func); @@ -208,7 +208,8 @@ export class History implements IHistory { onChangeCursor(func: () => any): () => void { return this.onCursor(func); } - onCursor(func: () => any) { + + onCursor(func: () => any): () => void { this.emitter.on('cursor', func); return () => { this.emitter.removeListener('cursor', func); diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index 9993f4c04..bcdf897b3 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -11,7 +11,10 @@ export interface IOnChangeOptions { } export interface INodeChildren extends Omit { + get owner(): INode; + unlinkChild(node: INode): void; + /** * 删除一个节点 */ @@ -57,6 +60,11 @@ export interface INodeChildren extends Omit number, ): any; + /** + * 根据索引获得节点 + */ + get(index: number): INode | null; + /** overriding methods end */ } export class NodeChildren implements INodeChildren { @@ -64,6 +72,31 @@ export class NodeChildren implements INodeChildren { private emitter: IEventBus = createModuleEventBus('NodeChildren'); + /** + * 元素个数 + */ + @computed get size(): number { + return this.children.length; + } + + get isEmptyNode(): boolean { + return this.size < 1; + } + get notEmptyNode(): boolean { + return this.size > 0; + } + + @computed get length(): number { + return this.children.length; + } + + private purged = false; + + get [Symbol.toStringTag]() { + // 保证向前兼容性 + return 'Array'; + } + constructor( readonly owner: INode, data: IPublicTypeNodeData | IPublicTypeNodeData[], @@ -130,13 +163,6 @@ export class NodeChildren implements INodeChildren { return this.children.concat(nodes); } - /** - * 元素个数 - */ - @computed get size(): number { - return this.children.length; - } - /** * */ @@ -144,24 +170,10 @@ export class NodeChildren implements INodeChildren { return this.isEmptyNode; } - get isEmptyNode(): boolean { - return this.size < 1; - } - notEmpty() { return this.notEmptyNode; } - get notEmptyNode(): boolean { - return this.size > 0; - } - - @computed get length(): number { - return this.children.length; - } - - private purged = false; - /** * 回收销毁 */ @@ -483,11 +495,6 @@ export class NodeChildren implements INodeChildren { }; } - get [Symbol.toStringTag]() { - // 保证向前兼容性 - return 'Array'; - } - private reportModified(node: INode, owner: INode, options = {}) { if (!node) { return; diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 8a7e9732a..5525493a1 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -18,11 +18,11 @@ import { } from '@alilc/lowcode-types'; import { compatStage, isDOMText, isJSExpression } from '@alilc/lowcode-utils'; import { SettingTopEntry } from '@alilc/lowcode-designer'; -import { Props, getConvertedExtraKey } from './props/props'; +import { Props, getConvertedExtraKey, IProps } from './props/props'; import { DocumentModel, IDocumentModel } from '../document-model'; import { NodeChildren, INodeChildren } from './node-children'; -import { Prop } from './props/prop'; -import { ComponentMeta } from '../../component-meta'; +import { IProp, Prop } from './props/prop'; +import { ComponentMeta, IComponentMeta } from '../../component-meta'; import { ExclusiveGroup, isExclusiveGroup } from './exclusive-group'; import { includeSlot, removeSlot } from '../../utils/slot'; import { foreachReverse } from '../../utils/tree'; @@ -41,6 +41,34 @@ export interface INode extends IPublicModelNode { */ get children(): INodeChildren | null; + /** + * 获取上一个兄弟节点 + */ + get prevSibling(): INode | null; + + /** + * 获取下一个兄弟节点 + */ + get nextSibling(): INode | null; + + /** + * 父级节点 + */ + get parent(): INode | null; + + get slots(): INode[]; + + /** + * 关联属性 + */ + get slotFor(): IProp | null; + + get props(): IProps; + + get componentMeta(): IComponentMeta; + + get document(): IDocumentModel; + setVisible(flag: boolean): void; getVisible(): boolean; @@ -66,8 +94,6 @@ export interface INode extends IPublicModelNode { */ export(stage: IPublicEnumTransformStage, options?: any): IPublicTypeNodeSchema; - get document(): IDocumentModel; - emitPropChange(val: IPublicTypePropChangeOptions): void; import(data: IPublicTypeNodeSchema, checkId?: boolean): void; @@ -76,9 +102,13 @@ export interface INode extends IPublicModelNode { addSlot(slotNode: INode): void; - get componentMeta(): ComponentMeta; - onVisibleChange(func: (flag: boolean) => any): () => void; + + getProp(path: string, createIfNone?: boolean): IProp | null; + + getExtraProp(key: string, createIfNone?: boolean): IProp | null; + + replaceChild(node: INode, data: any): INode; } /** @@ -157,7 +187,7 @@ export class Node /** * 属性抽象 */ - props: Props; + props: IProps; protected _children?: INodeChildren; @@ -241,11 +271,11 @@ export class Node return !!this._isRGLContainer; } - private _slotFor?: Prop | null = null; + private _slotFor?: IProp | null = null; @obx.shallow _slots: INode[] = []; - get slots() { + get slots(): INode[] { return this._slots; } @@ -509,7 +539,7 @@ export class Node /** * 关联属性 */ - get slotFor() { + get slotFor(): IProp | null { return this._slotFor; } @@ -665,10 +695,10 @@ export class Node /** * 替换子节点 * - * @param {Node} node + * @param {INode} node * @param {object} data */ - replaceChild(node: Node, data: any): Node { + replaceChild(node: INode, data: any): INode { if (this.children?.has(node)) { const selected = this.document.selection.has(node.id); @@ -703,11 +733,11 @@ export class Node }; } - getProp(path: string, createIfNone = true): Prop | null { + getProp(path: string, createIfNone = true): IProp | null { return this.props.query(path, createIfNone) || null; } - getExtraProp(key: string, createIfNone = true): Prop | null { + getExtraProp(key: string, createIfNone = true): IProp | null { return this.props.get(getConvertedExtraKey(key), createIfNone) || null; } @@ -767,7 +797,7 @@ export class Node /** * 获取下一个兄弟节点 */ - get nextSibling(): Node | null { + get nextSibling(): INode | null { if (!this.parent) { return null; } @@ -781,7 +811,7 @@ export class Node /** * 获取上一个兄弟节点 */ - get prevSibling(): Node | null { + get prevSibling(): INode | null { if (!this.parent) { return null; } diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index f140b30d4..582d5fdeb 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -1,6 +1,6 @@ import { obx, computed, makeObservable, action, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; -import { Designer } from '../designer'; -import { DocumentModel, isDocumentModel } from '../document'; +import { IDesigner } from '../designer'; +import { DocumentModel, IDocumentModel, isDocumentModel } from '../document'; import { IPublicTypeProjectSchema, IPublicTypeRootSchema, @@ -12,14 +12,60 @@ import { import { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils'; import { ISimulatorHost } from '../simulator'; -export interface IProject extends IPublicApiProject { +export interface IProject extends Omit< IPublicApiProject, 'simulatorHost' | 'importSchema' | 'exportSchema' | 'openDocument' | 'getDocumentById' | 'getCurrentDocument' | 'addPropsTransducer' | 'onRemoveDocument' | 'onChangeDocument' | 'onSimulatorHostReady' | 'onSimulatorRendererReady' | 'setI18n' > { + get designer(): IDesigner; + + get simulator(): ISimulatorHost | null; + + get currentDocument(): IDocumentModel | null; + + get documents(): IDocumentModel[]; + + open(doc?: string | IDocumentModel | IPublicTypeRootSchema): IDocumentModel | null; + + getDocumentByFileName(fileName: string): IDocumentModel | null; + + createDocument(data?: IPublicTypeRootSchema): IDocumentModel; + + load(schema?: IPublicTypeProjectSchema, autoOpen?: boolean | string): void; + + getSchema( + stage: IPublicEnumTransformStage, + ): IPublicTypeProjectSchema; + + getDocument(id: string): IDocumentModel | null; + + onCurrentDocumentChange(fn: (doc: IDocumentModel) => void): () => void; + + onSimulatorReady(fn: (args: any) => void): () => void; + + onRendererReady(fn: () => void): () => void; + + /** + * 分字段设置储存数据,不记录操作记录 + */ + 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; } export class Project implements IProject { private emitter: IEventBus = createModuleEventBus('Project'); - @obx.shallow readonly documents: IPublicModelDocumentModel[] = []; + @obx.shallow readonly documents: IDocumentModel[] = []; private data: IPublicTypeProjectSchema = { version: '1.0.0', @@ -41,14 +87,7 @@ export class Project implements IProject { key = Math.random(); - // TODO: 考虑项目级别 History - - constructor(readonly designer: Designer, schema?: IPublicTypeProjectSchema, readonly viewName = 'global') { - makeObservable(this); - this.load(schema); - } - - @computed get currentDocument() { + @computed get currentDocument(): IDocumentModel | null { return this.documents.find((doc) => doc.active); } @@ -69,6 +108,13 @@ export class Project implements IProject { this._i18n = value || {}; } + private documentsMap = new Map(); + + constructor(readonly designer: IDesigner, schema?: IPublicTypeProjectSchema, readonly viewName = 'global') { + makeObservable(this); + this.load(schema); + } + private getComponentsMap(): IPublicTypeComponentsMap { return this.documents.reduce(( compomentsMap: IPublicTypeComponentsMap, @@ -104,7 +150,9 @@ export class Project implements IProject { /** * 获取项目整体 schema */ - getSchema(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save): IPublicTypeProjectSchema { + getSchema( + stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save, + ): IPublicTypeProjectSchema { return { ...this.data, componentsMap: this.getComponentsMap(), @@ -240,26 +288,24 @@ export class Project implements IProject { return Reflect.get(this.data, key); } - private documentsMap = new Map(); - - getDocument(id: string): DocumentModel | null { + getDocument(id: string): IDocumentModel | null { // 此处不能使用 this.documentsMap.get(id),因为在乐高 rollback 场景,document.id 会被改成其他值 return this.documents.find((doc) => doc.id === id) || null; } - getDocumentByFileName(fileName: string): DocumentModel | null { + getDocumentByFileName(fileName: string): IDocumentModel | null { return this.documents.find((doc) => doc.fileName === fileName) || null; } @action - createDocument(data?: IPublicTypeRootSchema): DocumentModel { + createDocument(data?: IPublicTypeRootSchema): IDocumentModel { const doc = new DocumentModel(this, data || this?.data?.componentsTree?.[0]); this.documents.push(doc); this.documentsMap.set(doc.id, doc); return doc; } - open(doc?: string | DocumentModel | IPublicTypeRootSchema): DocumentModel | null { + open(doc?: string | IDocumentModel | IPublicTypeRootSchema): IDocumentModel | null { if (!doc) { const got = this.documents.find((item) => item.isBlank()); if (got) { @@ -341,7 +387,7 @@ export class Project implements IProject { }; } - onCurrentDocumentChange(fn: (doc: DocumentModel) => void): () => void { + onCurrentDocumentChange(fn: (doc: IDocumentModel) => void): () => void { this.emitter.on('current-document.change', fn); return () => { this.emitter.removeListener('current-document.change', fn); diff --git a/packages/editor-core/src/hotkey.ts b/packages/editor-core/src/hotkey.ts index 656c6af6e..30390daca 100644 --- a/packages/editor-core/src/hotkey.ts +++ b/packages/editor-core/src/hotkey.ts @@ -1,6 +1,6 @@ import { isEqual } from 'lodash'; import { globalContext } from './di'; -import { IPublicTypeHotkeyCallback, IPublicApiHotkey } from '@alilc/lowcode-types'; +import { IPublicTypeHotkeyCallback, IPublicTypeHotkeyCallbackConfig, IPublicTypeHotkeyCallbacks, IPublicApiHotkey } from '@alilc/lowcode-types'; interface KeyMap { [key: number]: string; @@ -14,23 +14,10 @@ interface ActionEvent { type: string; } -interface IPublicTypeHotkeyCallbacks { - [key: string]: IPublicTypeHotkeyCallbackCfg[]; -} - interface HotkeyDirectMap { [key: string]: IPublicTypeHotkeyCallback; } -interface IPublicTypeHotkeyCallbackCfg { - callback: IPublicTypeHotkeyCallback; - modifiers: string[]; - action: string; - seq?: string; - level?: number; - combo?: string; -} - interface KeyInfo { key: string; modifiers: string[]; @@ -444,10 +431,10 @@ export class Hotkey implements IHotKey { sequenceName?: string, combination?: string, level?: number, - ): IPublicTypeHotkeyCallbackCfg[] { + ): IPublicTypeHotkeyCallbackConfig[] { let i: number; - let callback: IPublicTypeHotkeyCallbackCfg; - const matches: IPublicTypeHotkeyCallbackCfg[] = []; + let callback: IPublicTypeHotkeyCallbackConfig; + const matches: IPublicTypeHotkeyCallbackConfig[] = []; const action: string = e.type; // if there are no events related to this keycode @@ -498,7 +485,7 @@ export class Hotkey implements IHotKey { } private handleKey(character: string, modifiers: string[], e: KeyboardEvent): void { - const callbacks: IPublicTypeHotkeyCallbackCfg[] = this.getMatches(character, modifiers, e); + const callbacks: IPublicTypeHotkeyCallbackConfig[] = this.getMatches(character, modifiers, e); let i: number; const doNotReset: SequenceLevels = {}; let maxLevel = 0; diff --git a/packages/shell/src/api/canvas.ts b/packages/shell/src/api/canvas.ts index 4436514fb..3c3129957 100644 --- a/packages/shell/src/api/canvas.ts +++ b/packages/shell/src/api/canvas.ts @@ -14,9 +14,11 @@ import { IDesigner, } from '@alilc/lowcode-designer'; import { editorSymbol, designerSymbol, nodeSymbol } from '../symbols'; -import { Dragon } from '../model'; -import { DropLocation } from '../model/drop-location'; -import { ActiveTracker } from '../model/active-tracker'; +import { + Dragon as ShellDragon, + DropLocation as ShellDropLocation, + ActiveTracker as ShellActiveTracker, +} from '../model'; export class Canvas implements IPublicApiCanvas { private readonly [editorSymbol]: IPublicModelEditor; @@ -25,6 +27,15 @@ export class Canvas implements IPublicApiCanvas { return this[editorSymbol].get('designer') as IDesigner; } + get dragon(): IPublicModelDragon | null { + return ShellDragon.create(this[designerSymbol].dragon, this.workspaceMode); + } + + get activeTracker(): IPublicModelActiveTracker | null { + const activeTracker = new ShellActiveTracker(this[designerSymbol].activeTracker); + return activeTracker; + } + constructor(editor: IPublicModelEditor, readonly workspaceMode: boolean = false) { this[editorSymbol] = editor; } @@ -47,19 +58,10 @@ export class Canvas implements IPublicApiCanvas { }); } - get dragon(): IPublicModelDragon | null { - return Dragon.create(this[designerSymbol].dragon, this.workspaceMode); - } - - get activeTracker(): IPublicModelActiveTracker | null { - const activeTracker = new ActiveTracker(this[designerSymbol].activeTracker); - return activeTracker; - } - /** * @deprecated */ get dropLocation() { - return DropLocation.create((this[designerSymbol] as any).dropLocation || null); + return ShellDropLocation.create((this[designerSymbol] as any).dropLocation || null); } } \ No newline at end of file diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx index ee87bea15..9954fdfe6 100644 --- a/packages/shell/src/api/common.tsx +++ b/packages/shell/src/api/common.tsx @@ -58,7 +58,7 @@ import { computed as innerComputed, observer as innerObserver, } from '@alilc/lowcode-editor-core'; -import { Dragon } from '../model'; +import { Dragon as ShellDragon } from '../model'; import { ReactNode, Component } from 'react'; class DesignerCabin implements IPublicApiCommonDesignerCabin { @@ -149,7 +149,7 @@ class DesignerCabin implements IPublicApiCommonDesignerCabin { * @deprecated please use canvas.dragon */ get dragon(): IPublicModelDragon | null { - return Dragon.create(this[designerSymbol].dragon); + return ShellDragon.create(this[designerSymbol].dragon, false); } } diff --git a/packages/shell/src/api/event.ts b/packages/shell/src/api/event.ts index 1f82d5f87..746d9ae6a 100644 --- a/packages/shell/src/api/event.ts +++ b/packages/shell/src/api/event.ts @@ -14,12 +14,6 @@ export class Event implements IPublicApiEvent { private readonly [eventBusSymbol]: EventBus; private readonly options: EventOptions; - // TODO: - /** - * 内核触发的事件名 - */ - readonly names = []; - constructor(eventBus: EventBus, options: EventOptions, public workspaceMode = false) { this[eventBusSymbol] = eventBus; this.options = options; diff --git a/packages/shell/src/api/hotkey.ts b/packages/shell/src/api/hotkey.ts index 2e9e2043d..4e65844ce 100644 --- a/packages/shell/src/api/hotkey.ts +++ b/packages/shell/src/api/hotkey.ts @@ -1,6 +1,6 @@ import { globalContext, Hotkey as InnerHotkey } from '@alilc/lowcode-editor-core'; import { hotkeySymbol } from '../symbols'; -import { IPublicTypeDisposable, IPublicTypeHotkeyCallback, IPublicApiHotkey } from '@alilc/lowcode-types'; +import { IPublicTypeDisposable, IPublicTypeHotkeyCallback, IPublicTypeHotkeyCallbacks, IPublicApiHotkey } from '@alilc/lowcode-types'; const innerHotkeySymbol = Symbol('innerHotkey'); @@ -22,15 +22,17 @@ export class Hotkey implements IPublicApiHotkey { this[innerHotkeySymbol] = hotkey; } - get callbacks(): any { + get callbacks(): IPublicTypeHotkeyCallbacks { return this[hotkeySymbol].callBacks; } + /** * @deprecated */ get callBacks() { return this.callbacks; } + /** * 绑定快捷键 * @param combos 快捷键,格式如:['command + s'] 、['ctrl + shift + s'] 等 @@ -38,7 +40,11 @@ export class Hotkey implements IPublicApiHotkey { * @param action * @returns */ - bind(combos: string[] | string, callback: IPublicTypeHotkeyCallback, action?: string): IPublicTypeDisposable { + bind( + combos: string[] | string, + callback: IPublicTypeHotkeyCallback, + action?: string, + ): IPublicTypeDisposable { this[hotkeySymbol].bind(combos, callback, action); return () => { this[hotkeySymbol].unbind(combos, callback, action); diff --git a/packages/shell/src/api/material.ts b/packages/shell/src/api/material.ts index 08deefdcc..eca386c5a 100644 --- a/packages/shell/src/api/material.ts +++ b/packages/shell/src/api/material.ts @@ -1,6 +1,6 @@ -import { Editor, globalContext } from '@alilc/lowcode-editor-core'; +import { globalContext } from '@alilc/lowcode-editor-core'; import { - Designer, + IDesigner, isComponentMeta, } from '@alilc/lowcode-designer'; import { IPublicTypeAssetsJson } from '@alilc/lowcode-utils'; @@ -11,21 +11,22 @@ import { IPublicTypeMetadataTransducer, IPublicModelComponentMeta, IPublicTypeNpmInfo, + IPublicModelEditor, } from '@alilc/lowcode-types'; -import { Workspace } from '@alilc/lowcode-workspace'; +import { Workspace as InnerWorkspace } from '@alilc/lowcode-workspace'; import { editorSymbol, designerSymbol } from '../symbols'; -import { ComponentMeta } from '../model/component-meta'; +import { ComponentMeta as ShellComponentMeta } from '../model'; import { ComponentType } from 'react'; const innerEditorSymbol = Symbol('editor'); export class Material implements IPublicApiMaterial { - private readonly [innerEditorSymbol]: Editor; + private readonly [innerEditorSymbol]: IPublicModelEditor; - get [editorSymbol](): Editor { + get [editorSymbol](): IPublicModelEditor { if (this.workspaceMode) { return this[innerEditorSymbol]; } - const workspace: Workspace = globalContext.get('workspace'); + const workspace: InnerWorkspace = globalContext.get('workspace'); if (workspace.isActive) { return workspace.window.editor; } @@ -33,11 +34,11 @@ export class Material implements IPublicApiMaterial { return this[innerEditorSymbol]; } - get [designerSymbol](): Designer { + get [designerSymbol](): IDesigner { return this[editorSymbol].get('designer')!; } - constructor(editor: Editor, readonly workspaceMode: boolean = false) { + constructor(editor: IPublicModelEditor, readonly workspaceMode: boolean = false) { this[innerEditorSymbol] = editor; } @@ -103,7 +104,7 @@ export class Material implements IPublicApiMaterial { */ getComponentMeta(componentName: string): IPublicModelComponentMeta | null { const innerMeta = this[designerSymbol].getComponentMeta(componentName); - return ComponentMeta.create(innerMeta); + return ShellComponentMeta.create(innerMeta); } /** @@ -112,7 +113,7 @@ export class Material implements IPublicApiMaterial { * @returns */ createComponentMeta(metadata: IPublicTypeComponentMetadata) { - return ComponentMeta.create(this[designerSymbol].createComponentMeta(metadata)); + return ShellComponentMeta.create(this[designerSymbol].createComponentMeta(metadata)); } /** @@ -158,7 +159,10 @@ export class Material implements IPublicApiMaterial { * @param actionName * @param handle */ - modifyBuiltinComponentAction(actionName: string, handle: (action: IPublicTypeComponentAction) => void) { + modifyBuiltinComponentAction( + actionName: string, + handle: (action: IPublicTypeComponentAction) => void, + ) { this[designerSymbol].componentActions.modifyBuiltinComponentAction(actionName, handle); } diff --git a/packages/shell/src/api/plugins.ts b/packages/shell/src/api/plugins.ts index 681628515..6e2b9c6b7 100644 --- a/packages/shell/src/api/plugins.ts +++ b/packages/shell/src/api/plugins.ts @@ -9,7 +9,7 @@ import { IPublicTypePluginRegisterOptions, IPublicTypePreferenceValueType, } from '@alilc/lowcode-types'; -import { PluginInstance } from '../model/plugin-instance'; +import { PluginInstance as ShellPluginInstance } from '../model'; import { pluginsSymbol } from '../symbols'; const innerPluginsSymbol = Symbol('plugin'); @@ -43,21 +43,23 @@ export class Plugins implements IPublicApiPlugins { await this[pluginsSymbol].init(registerOptions); } - getPluginPreference(pluginName: string): Record | null | undefined { + getPluginPreference( + pluginName: string, + ): Record | null | undefined { return this[pluginsSymbol].getPluginPreference(pluginName); } get(pluginName: string): IPublicModelPluginInstance | null { const instance = this[pluginsSymbol].get(pluginName); if (instance) { - return new PluginInstance(instance); + return new ShellPluginInstance(instance); } return null; } getAll() { - return this[pluginsSymbol].getAll()?.map(d => new PluginInstance(d)); + return this[pluginsSymbol].getAll()?.map((d) => new ShellPluginInstance(d)); } has(pluginName: string) { diff --git a/packages/shell/src/api/project.ts b/packages/shell/src/api/project.ts index 3ad977584..04feb81f3 100644 --- a/packages/shell/src/api/project.ts +++ b/packages/shell/src/api/project.ts @@ -1,6 +1,6 @@ import { BuiltinSimulatorHost, - Project as InnerProject, + IProject as InnerProject, } from '@alilc/lowcode-designer'; import { globalContext } from '@alilc/lowcode-editor-core'; import { @@ -14,9 +14,7 @@ import { IPublicEnumTransformStage, IPublicTypeDisposable, } from '@alilc/lowcode-types'; - - -import { DocumentModel } from '../model/document-model'; +import { DocumentModel as ShellDocumentModel } from '../model'; import { SimulatorHost } from './simulator-host'; import { editorSymbol, projectSymbol, simulatorHostSymbol, documentSymbol } from '../symbols'; @@ -61,7 +59,7 @@ export class Project implements IPublicApiProject { * @returns */ get documents(): IPublicModelDocumentModel[] { - return this[projectSymbol].documents.map((doc) => DocumentModel.create(doc)!); + return this[projectSymbol].documents.map((doc) => ShellDocumentModel.create(doc)!); } /** @@ -85,8 +83,10 @@ export class Project implements IPublicApiProject { */ openDocument(doc?: string | IPublicTypeRootSchema | undefined) { const documentModel = this[projectSymbol].open(doc); - if (!documentModel) return null; - return DocumentModel.create(documentModel); + if (!documentModel) { + return null; + } + return ShellDocumentModel.create(documentModel); } /** @@ -96,7 +96,7 @@ export class Project implements IPublicApiProject { */ createDocument(data?: IPublicTypeRootSchema): IPublicModelDocumentModel | null { const doc = this[projectSymbol].createDocument(data); - return DocumentModel.create(doc); + return ShellDocumentModel.create(doc); } /** @@ -113,7 +113,8 @@ export class Project implements IPublicApiProject { * @returns */ getDocumentByFileName(fileName: string): IPublicModelDocumentModel | null { - return DocumentModel.create(this[projectSymbol].getDocumentByFileName(fileName)); + const innerDocumentModel = this[projectSymbol].getDocumentByFileName(fileName); + return ShellDocumentModel.create(innerDocumentModel); } /** @@ -122,7 +123,7 @@ export class Project implements IPublicApiProject { * @returns */ getDocumentById(id: string): IPublicModelDocumentModel | null { - return DocumentModel.create(this[projectSymbol].getDocument(id)); + return ShellDocumentModel.create(this[projectSymbol].getDocument(id)); } /** @@ -146,7 +147,7 @@ export class Project implements IPublicApiProject { * @returns */ getCurrentDocument(): IPublicModelDocumentModel | null { - return DocumentModel.create(this[projectSymbol].currentDocument); + return ShellDocumentModel.create(this[projectSymbol].currentDocument); } /** @@ -154,7 +155,10 @@ export class Project implements IPublicApiProject { * @param transducer * @param stage */ - addPropsTransducer(transducer: IPublicTypePropsTransducer, stage: IPublicEnumTransformStage): void { + addPropsTransducer( + transducer: IPublicTypePropsTransducer, + stage: IPublicEnumTransformStage, + ): void { this[projectSymbol].designer.addPropsReducer(transducer, stage); } @@ -175,10 +179,10 @@ export class Project implements IPublicApiProject { */ onChangeDocument(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable { const offFn = this[projectSymbol].onCurrentDocumentChange((originalDoc) => { - fn(DocumentModel.create(originalDoc)!); + fn(ShellDocumentModel.create(originalDoc)!); }); if (this[projectSymbol].currentDocument) { - fn(DocumentModel.create(this[projectSymbol].currentDocument)!); + fn(ShellDocumentModel.create(this[projectSymbol].currentDocument)!); } return offFn; } diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index 51a30d018..8d5e2dc75 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -23,7 +23,11 @@ export class Skeleton implements IPublicApiSkeleton { return this[innerSkeletonSymbol]; } - constructor(skeleton: InnerSkeleton, pluginName: string, readonly workspaceMode: boolean = false) { + constructor( + skeleton: InnerSkeleton, + pluginName: string, + readonly workspaceMode: boolean = false, + ) { this[innerSkeletonSymbol] = skeleton; this.pluginName = pluginName; } diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index f32b403b1..be6eb3ef7 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -1,9 +1,8 @@ import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types'; import { Workspace as InnerWorkSpace } from '@alilc/lowcode-workspace'; import { Plugins } from '@alilc/lowcode-shell'; -import { Window } from '../model/window'; import { workspaceSymbol } from '../symbols'; -import { Resource } from '../model'; +import { Resource as ShellResource, Window as ShellWindow } from '../model'; export class Workspace implements IPublicApiWorkspace { readonly [workspaceSymbol]: InnerWorkSpace; @@ -13,7 +12,7 @@ export class Workspace implements IPublicApiWorkspace { } get resourceList() { - return this[workspaceSymbol].getResourceList().map(d => new Resource(d)); + return this[workspaceSymbol].getResourceList().map((d) => new ShellResource(d)); } setResourceList(resourceList: IPublicResourceList) { @@ -29,14 +28,14 @@ export class Workspace implements IPublicApiWorkspace { } get window() { - return new Window(this[workspaceSymbol].window); + return new ShellWindow(this[workspaceSymbol].window); } registerResourceType(resourceTypeModel: IPublicTypeResourceType): void { this[workspaceSymbol].registerResourceType(resourceTypeModel); } - openEditorWindow(resourceName: string, title: string, extra: Object, viewName?: string) { + openEditorWindow(resourceName: string, title: string, extra: object, viewName?: string) { this[workspaceSymbol].openEditorWindow(resourceName, title, extra, viewName); } @@ -57,7 +56,7 @@ export class Workspace implements IPublicApiWorkspace { } get windows() { - return this[workspaceSymbol].windows.map(d => new Window(d)); + return this[workspaceSymbol].windows.map((d) => new ShellWindow(d)); } onChangeWindows(fn: () => void) { diff --git a/packages/shell/src/model/active-tracker.ts b/packages/shell/src/model/active-tracker.ts index 0c9c42efe..77ddeffab 100644 --- a/packages/shell/src/model/active-tracker.ts +++ b/packages/shell/src/model/active-tracker.ts @@ -1,16 +1,14 @@ import { IPublicModelActiveTracker, IPublicModelNode, IPublicTypeActiveTarget } from '@alilc/lowcode-types'; -import { IActiveTracker } from '@alilc/lowcode-designer'; -import { Node } from './node'; +import { IActiveTracker as InnerActiveTracker, INode as InnerNode } from '@alilc/lowcode-designer'; +import { Node as ShellNode } from './node'; import { nodeSymbol } from '../symbols'; const activeTrackerSymbol = Symbol('activeTracker'); - export class ActiveTracker implements IPublicModelActiveTracker { - private readonly [activeTrackerSymbol]: IActiveTracker; + private readonly [activeTrackerSymbol]: InnerActiveTracker; - - constructor(innerTracker: IActiveTracker) { + constructor(innerTracker: InnerActiveTracker) { this[activeTrackerSymbol] = innerTracker; } @@ -20,7 +18,7 @@ export class ActiveTracker implements IPublicModelActiveTracker { } return this[activeTrackerSymbol].onChange((t: IPublicTypeActiveTarget) => { const { node: innerNode, detail, instance } = t; - const publicNode = Node.create(innerNode); + const publicNode = ShellNode.create(innerNode as InnerNode); const publicActiveTarget = { node: publicNode!, detail, diff --git a/packages/shell/src/model/component-meta.ts b/packages/shell/src/model/component-meta.ts index 8fcab78ef..67cb2895d 100644 --- a/packages/shell/src/model/component-meta.ts +++ b/packages/shell/src/model/component-meta.ts @@ -1,5 +1,5 @@ import { - ComponentMeta as InnerComponentMeta, + IComponentMeta as InnerComponentMeta, INode, } from '@alilc/lowcode-designer'; import { IPublicTypeNodeData, IPublicTypeNodeSchema, IPublicModelComponentMeta, IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeNpmInfo, IPublicTypeTransformedComponentMetadata, IPublicModelNode } from '@alilc/lowcode-types'; @@ -9,6 +9,8 @@ import { ReactElement } from 'react'; export class ComponentMeta implements IPublicModelComponentMeta { private readonly [componentMetaSymbol]: InnerComponentMeta; + isComponentMeta = true; + constructor(componentMeta: InnerComponentMeta) { this[componentMetaSymbol] = componentMeta; } @@ -83,7 +85,7 @@ export class ComponentMeta implements IPublicModelComponentMeta { * @deprecated */ get prototype() { - return this[componentMetaSymbol].prototype; + return (this[componentMetaSymbol] as any).prototype; } get availableActions(): any { @@ -106,7 +108,6 @@ export class ComponentMeta implements IPublicModelComponentMeta { return this[componentMetaSymbol].getMetadata(); } - isComponentMeta = true; /** * check if the current node could be placed in parent node * @param my @@ -124,9 +125,15 @@ export class ComponentMeta implements IPublicModelComponentMeta { * @param parent * @returns */ - checkNestingDown(my: IPublicModelNode | IPublicTypeNodeData, target: IPublicTypeNodeSchema | IPublicModelNode | IPublicTypeNodeSchema[]) { + checkNestingDown( + my: IPublicModelNode | IPublicTypeNodeData, + target: IPublicTypeNodeSchema | IPublicModelNode | IPublicTypeNodeSchema[], + ) { const curNode = (my as any)?.isNode ? (my as any)[nodeSymbol] : my; - return this[componentMetaSymbol].checkNestingDown(curNode as any, (target as any)[nodeSymbol] || target); + return this[componentMetaSymbol].checkNestingDown( + curNode as any, + (target as any)[nodeSymbol] || target, + ); } refreshMetadata(): void { diff --git a/packages/shell/src/model/detecting.ts b/packages/shell/src/model/detecting.ts index f99423eae..7ce0fe1e5 100644 --- a/packages/shell/src/model/detecting.ts +++ b/packages/shell/src/model/detecting.ts @@ -2,6 +2,7 @@ import { Node as ShellNode } from './node'; import { Detecting as InnerDetecting, IDocumentModel as InnerDocumentModel, + INode as InnerNode, } from '@alilc/lowcode-designer'; import { documentSymbol, detectingSymbol } from '../symbols'; import { IPublicModelDetecting, IPublicModelNode, IPublicTypeDisposable } from '@alilc/lowcode-types'; @@ -52,7 +53,11 @@ export class Detecting implements IPublicModelDetecting { this[detectingSymbol].leave(this[documentSymbol]); } - onDetectingChange(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable { - return this[detectingSymbol].onDetectingChange(fn); + onDetectingChange(fn: (node: IPublicModelNode | null) => void): IPublicTypeDisposable { + const innerFn = (innerNode: InnerNode) => { + const shellNode = ShellNode.create(innerNode); + fn(shellNode); + }; + return this[detectingSymbol].onDetectingChange(innerFn); } } \ No newline at end of file diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts index 256cbd960..13fc49bae 100644 --- a/packages/shell/src/model/document-model.ts +++ b/packages/shell/src/model/document-model.ts @@ -1,8 +1,6 @@ -import { Editor } from '@alilc/lowcode-editor-core'; import { - DocumentModel as InnerDocumentModel, - Node as InnerNode, - isDragNodeObject, + IDocumentModel as InnerDocumentModel, + INode as InnerNode, } from '@alilc/lowcode-designer'; import { IPublicEnumTransformStage, @@ -23,23 +21,24 @@ import { IPublicModelDropLocation, IPublicApiCanvas, IPublicTypeDisposable, + IPublicModelEditor, } from '@alilc/lowcode-types'; -import { Node } from './node'; -import { Selection } from './selection'; -import { Detecting } from './detecting'; -import { History } from './history'; -import { DropLocation } from './drop-location'; -import { Project } from '../api/project'; -import { Prop } from './prop'; +import { isDragNodeObject } from '@alilc/lowcode-utils'; +import { Node as ShellNode } from './node'; +import { Selection as ShellSelection } from './selection'; +import { Detecting as ShellDetecting } from './detecting'; +import { History as ShellHistory } from './history'; +import { DropLocation as ShellDropLocation } from './drop-location'; +import { Project as ShellProject, Canvas as ShellCanvas } from '../api'; +import { Prop as ShellProp } from './prop'; import { ModalNodesManager } from './modal-nodes-manager'; import { documentSymbol, editorSymbol, nodeSymbol } from '../symbols'; -import { Canvas } from '../api'; const shellDocSymbol = Symbol('shellDocSymbol'); export class DocumentModel implements IPublicModelDocumentModel { private readonly [documentSymbol]: InnerDocumentModel; - private readonly [editorSymbol]: Editor; + private readonly [editorSymbol]: IPublicModelEditor; private _focusNode: IPublicModelNode | null; selection: IPublicModelSelection; detecting: IPublicModelDetecting; @@ -52,13 +51,13 @@ export class DocumentModel implements IPublicModelDocumentModel { constructor(document: InnerDocumentModel) { this[documentSymbol] = document; - this[editorSymbol] = document.designer?.editor as Editor; - this.selection = new Selection(document); - this.detecting = new Detecting(document); - this.history = new History(document); - this.canvas = new Canvas(this[editorSymbol]); + this[editorSymbol] = document.designer?.editor as IPublicModelEditor; + this.selection = new ShellSelection(document); + this.detecting = new ShellDetecting(document); + this.history = new ShellHistory(document); + this.canvas = new ShellCanvas(this[editorSymbol]); - this._focusNode = Node.create(this[documentSymbol].focusNode); + this._focusNode = ShellNode.create(this[documentSymbol].focusNode); } static create(document: InnerDocumentModel | undefined | null): IPublicModelDocumentModel | null { @@ -91,7 +90,7 @@ export class DocumentModel implements IPublicModelDocumentModel { * @returns */ get project(): IPublicApiProject { - return Project.create(this[documentSymbol].project); + return ShellProject.create(this[documentSymbol].project); } /** @@ -100,7 +99,7 @@ export class DocumentModel implements IPublicModelDocumentModel { * @returns */ get root(): IPublicModelNode | null { - return Node.create(this[documentSymbol].getRoot()); + return ShellNode.create(this[documentSymbol].rootNode); } get focusNode(): IPublicModelNode | null { @@ -135,7 +134,7 @@ export class DocumentModel implements IPublicModelDocumentModel { } get dropLocation(): IPublicModelDropLocation | null { - return DropLocation.create(this[documentSymbol].dropLocation); + return ShellDropLocation.create(this[documentSymbol].dropLocation); } set dropLocation(loc: IPublicModelDropLocation | null) { @@ -148,7 +147,7 @@ export class DocumentModel implements IPublicModelDocumentModel { * @param {string} nodeId */ getNodeById(nodeId: string): IPublicModelNode | null { - return Node.create(this[documentSymbol].getNode(nodeId)); + return ShellNode.create(this[documentSymbol].getNode(nodeId)); } /** @@ -189,7 +188,7 @@ export class DocumentModel implements IPublicModelDocumentModel { at, copy, ); - return Node.create(node); + return ShellNode.create(node); } /** @@ -198,7 +197,7 @@ export class DocumentModel implements IPublicModelDocumentModel { * @returns */ createNode(data: any): IPublicModelNode | null { - return Node.create(this[documentSymbol].createNode(data)); + return ShellNode.create(this[documentSymbol].createNode(data)); } /** @@ -243,7 +242,7 @@ export class DocumentModel implements IPublicModelDocumentModel { */ onAddNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable { return this[documentSymbol].onNodeCreate((node: InnerNode) => { - fn(Node.create(node)!); + fn(ShellNode.create(node)!); }); } @@ -262,7 +261,7 @@ export class DocumentModel implements IPublicModelDocumentModel { */ onRemoveNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable { return this[documentSymbol].onNodeDestroy((node: InnerNode) => { - fn(Node.create(node)!); + fn(ShellNode.create(node)!); }); } @@ -271,7 +270,7 @@ export class DocumentModel implements IPublicModelDocumentModel { */ onChangeDetecting(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable { return this[documentSymbol].designer.detecting.onDetectingChange((node: InnerNode) => { - fn(Node.create(node)!); + fn(ShellNode.create(node)!); }); } @@ -290,7 +289,7 @@ export class DocumentModel implements IPublicModelDocumentModel { */ onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): void { this[documentSymbol].onChangeNodeVisible((node: IPublicModelNode, visible: boolean) => { - fn(Node.create(node)!, visible); + fn(ShellNode.create(node)!, visible); }); } @@ -305,7 +304,7 @@ export class DocumentModel implements IPublicModelDocumentModel { } fn({ type: info.type, - node: Node.create(info.node)!, + node: ShellNode.create(info.node)!, }); }); } @@ -322,8 +321,8 @@ export class DocumentModel implements IPublicModelDocumentModel { key: info.key, oldValue: info.oldValue, newValue: info.newValue, - prop: Prop.create(info.prop)!, - node: Node.create(info.node as any)!, + prop: ShellProp.create(info.prop)!, + node: ShellNode.create(info.node as any)!, }); }, ); diff --git a/packages/shell/src/model/drag-object.ts b/packages/shell/src/model/drag-object.ts index 02389e511..dc4157bd2 100644 --- a/packages/shell/src/model/drag-object.ts +++ b/packages/shell/src/model/drag-object.ts @@ -9,7 +9,7 @@ export class DragObject implements IPublicModelDragObject { this[dragObjectSymbol] = dragObject; } - static create(dragObject: InnerDragObject): IPublicModelDragObject | null { + static create(dragObject: InnerDragObject | null): IPublicModelDragObject | null { if (!dragObject) { return null; } diff --git a/packages/shell/src/model/dragon.ts b/packages/shell/src/model/dragon.ts index cc3f7a0f1..392e3d158 100644 --- a/packages/shell/src/model/dragon.ts +++ b/packages/shell/src/model/dragon.ts @@ -15,7 +15,6 @@ import { export const innerDragonSymbol = Symbol('innerDragonSymbol'); - export class Dragon implements IPublicModelDragon { private readonly [innerDragonSymbol]: IPublicModelDragon; @@ -38,7 +37,10 @@ export class Dragon implements IPublicModelDragon { return designer.dragon; } - static create(dragon: IPublicModelDragon | null, workspaceMode: boolean): IPublicModelDragon | null { + static create( + dragon: IPublicModelDragon | null, + workspaceMode: boolean, + ): IPublicModelDragon | null { if (!dragon) { return null; } diff --git a/packages/shell/src/model/drop-location.ts b/packages/shell/src/model/drop-location.ts index e4b13a668..d927c969f 100644 --- a/packages/shell/src/model/drop-location.ts +++ b/packages/shell/src/model/drop-location.ts @@ -1,5 +1,5 @@ import { - DropLocation as InnerDropLocation, + IDropLocation as InnerDropLocation, } from '@alilc/lowcode-designer'; import { dropLocationSymbol } from '../symbols'; import { Node } from './node'; diff --git a/packages/shell/src/model/history.ts b/packages/shell/src/model/history.ts index e872847de..d16f1e3f8 100644 --- a/packages/shell/src/model/history.ts +++ b/packages/shell/src/model/history.ts @@ -1,11 +1,11 @@ -import { DocumentModel as InnerDocumentModel } from '@alilc/lowcode-designer'; +import { IDocumentModel as InnerDocumentModel, IHistory as InnerHistory } from '@alilc/lowcode-designer'; import { historySymbol, documentSymbol } from '../symbols'; import { IPublicModelHistory, IPublicTypeDisposable } from '@alilc/lowcode-types'; export class History implements IPublicModelHistory { private readonly [documentSymbol]: InnerDocumentModel; - private get [historySymbol]() { + private get [historySymbol](): InnerHistory { return this[documentSymbol].getHistory(); } @@ -64,7 +64,7 @@ export class History implements IPublicModelHistory { * @returns */ onChangeState(func: () => any): IPublicTypeDisposable { - return this[historySymbol].onStateChange(func); + return this[historySymbol].onChangeState(func); } /** @@ -73,6 +73,6 @@ export class History implements IPublicModelHistory { * @returns */ onChangeCursor(func: () => any): IPublicTypeDisposable { - return this[historySymbol].onCursor(func); + return this[historySymbol].onChangeCursor(func); } } diff --git a/packages/shell/src/model/index.ts b/packages/shell/src/model/index.ts index d0e45cc94..d20120c3e 100644 --- a/packages/shell/src/model/index.ts +++ b/packages/shell/src/model/index.ts @@ -14,4 +14,7 @@ export * from './props'; export * from './selection'; export * from './setting-prop-entry'; export * from './setting-top-entry'; -export * from './resource'; \ No newline at end of file +export * from './resource'; +export * from './active-tracker'; +export * from './plugin-instance'; +export * from './window'; \ No newline at end of file diff --git a/packages/shell/src/model/node-children.ts b/packages/shell/src/model/node-children.ts index 9f8792ee3..0192268bc 100644 --- a/packages/shell/src/model/node-children.ts +++ b/packages/shell/src/model/node-children.ts @@ -1,6 +1,6 @@ import { INode as InnerNode, INodeChildren } from '@alilc/lowcode-designer'; import { IPublicTypeNodeData, IPublicEnumTransformStage, IPublicModelNodeChildren, IPublicModelNode } from '@alilc/lowcode-types'; -import { Node } from './node'; +import { Node as ShellNode } from './node'; import { nodeSymbol, nodeChildrenSymbol } from '../symbols'; export class NodeChildren implements IPublicModelNodeChildren { @@ -21,7 +21,7 @@ export class NodeChildren implements IPublicModelNodeChildren { * 返回当前 children 实例所属的节点实例 */ get owner(): IPublicModelNode | null { - return Node.create(this[nodeChildrenSymbol].owner); + return ShellNode.create(this[nodeChildrenSymbol].owner); } /** @@ -107,7 +107,7 @@ export class NodeChildren implements IPublicModelNodeChildren { * @returns */ get(index: number): IPublicModelNode | null { - return Node.create(this[nodeChildrenSymbol].get(index)); + return ShellNode.create(this[nodeChildrenSymbol].get(index)); } /** @@ -125,7 +125,7 @@ export class NodeChildren implements IPublicModelNodeChildren { */ forEach(fn: (node: IPublicModelNode, index: number) => void): void { this[nodeChildrenSymbol].forEach((item: InnerNode, index: number) => { - fn(Node.create(item)!, index); + fn(ShellNode.create(item)!, index); }); } @@ -135,7 +135,7 @@ export class NodeChildren implements IPublicModelNodeChildren { */ map(fn: (node: IPublicModelNode, index: number) => T[]): any[] | null { return this[nodeChildrenSymbol].map((item: InnerNode, index: number) => { - return fn(Node.create(item)!, index); + return fn(ShellNode.create(item)!, index); }); } @@ -145,7 +145,7 @@ export class NodeChildren implements IPublicModelNodeChildren { */ every(fn: (node: IPublicModelNode, index: number) => boolean): boolean { return this[nodeChildrenSymbol].every((item: InnerNode, index: number) => { - return fn(Node.create(item)!, index); + return fn(ShellNode.create(item)!, index); }); } @@ -155,7 +155,7 @@ export class NodeChildren implements IPublicModelNodeChildren { */ some(fn: (node: IPublicModelNode, index: number) => boolean): boolean { return this[nodeChildrenSymbol].some((item: InnerNode, index: number) => { - return fn(Node.create(item)!, index); + return fn(ShellNode.create(item)!, index); }); } @@ -166,9 +166,9 @@ export class NodeChildren implements IPublicModelNodeChildren { filter(fn: (node: IPublicModelNode, index: number) => boolean): any { return this[nodeChildrenSymbol] .filter((item: InnerNode, index: number) => { - return fn(Node.create(item)!, index); + return fn(ShellNode.create(item)!, index); }) - .map((item: InnerNode) => Node.create(item)!); + .map((item: InnerNode) => ShellNode.create(item)!); } /** @@ -176,9 +176,9 @@ export class NodeChildren implements IPublicModelNodeChildren { * @param fn */ find(fn: (node: IPublicModelNode, index: number) => boolean): IPublicModelNode | null { - return Node.create( + return ShellNode.create( this[nodeChildrenSymbol].find((item: InnerNode, index: number) => { - return fn(Node.create(item)!, index); + return fn(ShellNode.create(item)!, index); }), ); } @@ -189,7 +189,7 @@ export class NodeChildren implements IPublicModelNodeChildren { */ reduce(fn: (acc: any, cur: IPublicModelNode) => any, initialValue: any): void { return this[nodeChildrenSymbol].reduce((acc: any, cur: InnerNode) => { - return fn(acc, Node.create(cur)!); + return fn(acc, ShellNode.create(cur)!); }, initialValue); } @@ -226,10 +226,11 @@ export class NodeChildren implements IPublicModelNodeChildren { sorter = () => 0; } this[nodeChildrenSymbol].mergeChildren( - (node: InnerNode, idx: number) => remover(Node.create(node)!, idx), - (children: InnerNode[]) => adder(children.map((node) => Node.create(node)!)), - (firstNode: InnerNode, secondNode: InnerNode) => - sorter(Node.create(firstNode)!, Node.create(secondNode)!), + (node: InnerNode, idx: number) => remover(ShellNode.create(node)!, idx), + (children: InnerNode[]) => adder(children.map((node) => ShellNode.create(node)!)), + (firstNode: InnerNode, secondNode: InnerNode) => { + return sorter(ShellNode.create(firstNode)!, ShellNode.create(secondNode)!); + }, ); } } diff --git a/packages/shell/src/model/node.ts b/packages/shell/src/model/node.ts index d9f86c8a8..40bad153d 100644 --- a/packages/shell/src/model/node.ts +++ b/packages/shell/src/model/node.ts @@ -283,7 +283,7 @@ export class Node implements IPublicModelNode { * 节点上挂载的插槽节点们 */ get slots(): IPublicModelNode[] { - return this[nodeSymbol].slots.map((node: IPublicModelNode) => Node.create(node)!); + return this[nodeSymbol].slots.map((node: InnerNode) => Node.create(node)!); } /** @@ -318,7 +318,7 @@ export class Node implements IPublicModelNode { return ShellSettingTopEntry.create(this[nodeSymbol].settingEntry as any); } - constructor(node: IPublicModelNode) { + constructor(node: InnerNode) { this[nodeSymbol] = node; this[documentSymbol] = node.document; @@ -351,7 +351,7 @@ export class Node implements IPublicModelNode { * @deprecated */ getDOMNode() { - return this[nodeSymbol].getDOMNode(); + return (this[nodeSymbol] as any).getDOMNode(); } /** @@ -512,7 +512,10 @@ export class Node implements IPublicModelNode { * @param options * @returns */ - exportSchema(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render, options?: any): IPublicTypeNodeSchema { + exportSchema( + stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render, + options?: any, + ): IPublicTypeNodeSchema { return this[nodeSymbol].export(stage, options); } diff --git a/packages/types/src/shell/api/hotkey.ts b/packages/types/src/shell/api/hotkey.ts index c8da780af..894eb0e2f 100644 --- a/packages/types/src/shell/api/hotkey.ts +++ b/packages/types/src/shell/api/hotkey.ts @@ -1,7 +1,14 @@ -import { IPublicTypeDisposable, IPublicTypeHotkeyCallback } from '../type'; +import { IPublicTypeDisposable, IPublicTypeHotkeyCallback, IPublicTypeHotkeyCallbacks } from '../type'; export interface IPublicApiHotkey { - get callbacks(): any; + + /** + * 获取当前快捷键配置 + * + * @experimental + * @since v1.1.0 + */ + get callbacks(): IPublicTypeHotkeyCallbacks; /** * 绑定快捷键 @@ -9,7 +16,6 @@ export interface IPublicApiHotkey { * @param combos 快捷键,格式如:['command + s'] 、['ctrl + shift + s'] 等 * @param callback 回调函数 * @param action - * @returns */ bind( combos: string[] | string, diff --git a/packages/types/src/shell/api/project.ts b/packages/types/src/shell/api/project.ts index 823159e7b..edafabb48 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 { + /** * 获取当前的 document * get current document @@ -40,7 +40,6 @@ export interface IPublicApiProject { */ createDocument(data?: IPublicTypeRootSchema): IPublicModelDocumentModel | null; - /** * 删除一个 document * remove a document diff --git a/packages/types/src/shell/model/component-meta.ts b/packages/types/src/shell/model/component-meta.ts index 238d916cf..160c7107d 100644 --- a/packages/types/src/shell/model/component-meta.ts +++ b/packages/types/src/shell/model/component-meta.ts @@ -3,6 +3,7 @@ import { ReactElement } from 'react'; import { IPublicModelNode } from './node'; export interface IPublicModelComponentMeta { + /** * 组件名 */ @@ -79,6 +80,5 @@ export interface IPublicModelComponentMeta { target: IPublicTypeNodeSchema | IPublicModelNode | IPublicTypeNodeSchema[], ): boolean; - refreshMetadata(): void; } diff --git a/packages/types/src/shell/model/detecting.ts b/packages/types/src/shell/model/detecting.ts index d828ace32..9bc215f9a 100644 --- a/packages/types/src/shell/model/detecting.ts +++ b/packages/types/src/shell/model/detecting.ts @@ -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) => void): IPublicTypeDisposable; + onDetectingChange(fn: (node: IPublicModelNode | null) => void): IPublicTypeDisposable; } diff --git a/packages/types/src/shell/model/editor.ts b/packages/types/src/shell/model/editor.ts index 4f7211387..11d75aac7 100644 --- a/packages/types/src/shell/model/editor.ts +++ b/packages/types/src/shell/model/editor.ts @@ -3,7 +3,7 @@ import { EventEmitter } from 'events'; import StrictEventEmitter from 'strict-event-emitter-types'; import * as GlobalEvent from '../../event'; import { IPublicApiEvent } from '../api'; -import { IPublicTypeEditorValueKey, IPublicTypeEditorGetOptions, IPublicTypeEditorGetResult, IPublicTypeEditorRegisterOptions } from '../type'; +import { IPublicTypeEditorValueKey, IPublicTypeEditorGetOptions, IPublicTypeEditorGetResult, IPublicTypeEditorRegisterOptions, IPublicTypeAssetsJson } from '../type'; export interface IPublicModelEditor extends StrictEventEmitter { get: ( @@ -25,4 +25,6 @@ export interface IPublicModelEditor extends StrictEventEmitter void; get eventBus(): IPublicApiEvent; + + setAssets(assets: IPublicTypeAssetsJson): void; } diff --git a/packages/types/src/shell/type/hotkey-callback-config.ts b/packages/types/src/shell/type/hotkey-callback-config.ts new file mode 100644 index 000000000..1903d6a84 --- /dev/null +++ b/packages/types/src/shell/type/hotkey-callback-config.ts @@ -0,0 +1,10 @@ +import { IPublicTypeHotkeyCallback } from './'; + +export interface IPublicTypeHotkeyCallbackConfig { + callback: IPublicTypeHotkeyCallback; + modifiers: string[]; + action: string; + seq?: string; + level?: number; + combo?: string; +} \ No newline at end of file diff --git a/packages/types/src/shell/type/hotkey-callbacks.ts b/packages/types/src/shell/type/hotkey-callbacks.ts new file mode 100644 index 000000000..3fd80a480 --- /dev/null +++ b/packages/types/src/shell/type/hotkey-callbacks.ts @@ -0,0 +1,5 @@ +import { IPublicTypeHotkeyCallbackConfig } from './'; + +export interface IPublicTypeHotkeyCallbacks { + [key: string]: IPublicTypeHotkeyCallbackConfig[]; +} \ 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 f66094f3d..a066e1f57 100644 --- a/packages/types/src/shell/type/index.ts +++ b/packages/types/src/shell/type/index.ts @@ -86,4 +86,6 @@ export * from './editor-register-options'; export * from './editor-view'; export * from './resource-type'; export * from './resource-type-config'; -export * from './editor-view-config'; \ No newline at end of file +export * from './editor-view-config'; +export * from './hotkey-callback-config'; +export * from './hotkey-callbacks'; \ No newline at end of file From 0d388a30766c556c5fe3abc57a6db4322b0588c9 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 12 Jan 2023 18:31:35 +0800 Subject: [PATCH 13/89] feat(workspace): resource supports the init lifecycle and initializes plugins --- packages/types/src/shell/model/resource.ts | 1 - packages/workspace/src/resource.ts | 11 ++++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/types/src/shell/model/resource.ts b/packages/types/src/shell/model/resource.ts index cfa48f189..5f26c8d7b 100644 --- a/packages/types/src/shell/model/resource.ts +++ b/packages/types/src/shell/model/resource.ts @@ -1,5 +1,4 @@ import { ReactElement } from 'react'; -import { IPublicModelResourceType } from './resource-type'; export interface IPublicModelResource { get title(): string | undefined; diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index 9753339f0..2495909b4 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -7,12 +7,16 @@ import { Workspace as InnerWorkSpace } from './workspace'; const logger = new Logger({ level: 'warn', bizName: 'workspace:resource' }); export class Resource implements IPublicModelResource { + private context: BasicContext; + resourceTypeInstance: IPublicResourceTypeConfig; editorViewMap: Map = new Map(); constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, workspace: InnerWorkSpace) { - this.resourceTypeInstance = resourceType.resourceTypeModel(new BasicContext(workspace, ''), {}); + this.context = new BasicContext(workspace, ''); + this.resourceTypeInstance = resourceType.resourceTypeModel(this.context, {}); + this.init(); if (this.resourceTypeInstance.editorViews) { this.resourceTypeInstance.editorViews.forEach((d: any) => { this.editorViewMap.set(d.viewName, d); @@ -51,6 +55,11 @@ export class Resource implements IPublicModelResource { return this.resourceData?.category; } + async init() { + await this.resourceTypeInstance.init?.(); + await this.context.innerPlugins.init(); + } + async import(schema: any) { return await this.resourceTypeInstance.import?.(schema); } From 4fd3af10c5b0e444b3cfb9758ee022cfcff96f7a Mon Sep 17 00:00:00 2001 From: JackLian Date: Fri, 13 Jan 2023 09:33:21 +0800 Subject: [PATCH 14/89] fix(shell/model): fix lint issues in shell/model --- docs/docs/api/model/drop-location.md | 2 +- .../designer/src/designer/active-tracker.ts | 22 ++++++++++++------- packages/designer/src/designer/location.ts | 10 ++++++--- .../src/designer/setting/setting-entry.ts | 8 +++---- .../designer/setting/setting-prop-entry.ts | 8 +++---- .../designer/src/document/node/props/prop.ts | 8 ++++--- packages/shell/src/model/active-tracker.ts | 6 ++--- packages/shell/src/model/drop-location.ts | 4 ++-- packages/shell/src/model/node.ts | 1 + packages/shell/src/model/resource.ts | 1 - .../shell/src/model/setting-prop-entry.ts | 16 +++++++------- packages/shell/src/model/setting-top-entry.ts | 8 +++---- packages/shell/src/model/window.ts | 4 ++-- .../types/src/shell/model/drop-location.ts | 2 +- 14 files changed, 56 insertions(+), 44 deletions(-) diff --git a/docs/docs/api/model/drop-location.md b/docs/docs/api/model/drop-location.md index 853da842c..dc6a684e4 100644 --- a/docs/docs/api/model/drop-location.md +++ b/docs/docs/api/model/drop-location.md @@ -17,7 +17,7 @@ sidebar_position: 13 拖拽放置位置目标 -`@type {IPublicModelNode}` +`@type {IPublicModelNode | null}` 相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) diff --git a/packages/designer/src/designer/active-tracker.ts b/packages/designer/src/designer/active-tracker.ts index 6c7dc9104..27a7090f8 100644 --- a/packages/designer/src/designer/active-tracker.ts +++ b/packages/designer/src/designer/active-tracker.ts @@ -6,16 +6,22 @@ import { } from '@alilc/lowcode-types'; import { isNode } from '@alilc/lowcode-utils'; -export interface IActiveTracker extends Omit< IPublicModelActiveTracker, 'track' > { - track(originalTarget: IPublicTypeActiveTarget | INode): void; +export interface IActiveTracker extends Omit< IPublicModelActiveTracker, 'track' | 'onChange' > { + track(originalTarget: ActiveTarget | INode): void; + + onChange(fn: (target: ActiveTarget) => void): () => void; +} + +export interface ActiveTarget extends Omit< IPublicTypeActiveTarget, 'node' > { + node: INode; } export class ActiveTracker implements IActiveTracker { private emitter: IEventBus = createModuleEventBus('ActiveTracker'); - @obx.ref private _target?: IPublicTypeActiveTarget | INode; + @obx.ref private _target?: ActiveTarget | INode; - track(originalTarget: IPublicTypeActiveTarget | INode) { + track(originalTarget: ActiveTarget | INode) { let target = originalTarget; if (isNode(originalTarget)) { target = { node: originalTarget as INode }; @@ -25,11 +31,11 @@ export class ActiveTracker implements IActiveTracker { } get currentNode() { - return (this._target as IPublicTypeActiveTarget)?.node; + return (this._target as ActiveTarget)?.node; } get detail() { - return (this._target as IPublicTypeActiveTarget)?.detail; + return (this._target as ActiveTarget)?.detail; } /** @@ -41,10 +47,10 @@ export class ActiveTracker implements IActiveTracker { } get instance() { - return (this._target as IPublicTypeActiveTarget)?.instance; + return (this._target as ActiveTarget)?.instance; } - onChange(fn: (target: IPublicTypeActiveTarget) => void): () => void { + onChange(fn: (target: ActiveTarget) => void): () => void { this.emitter.addListener('change', fn); return () => { this.emitter.removeListener('change', fn); diff --git a/packages/designer/src/designer/location.ts b/packages/designer/src/designer/location.ts index 59d32f048..08c168091 100644 --- a/packages/designer/src/designer/location.ts +++ b/packages/designer/src/designer/location.ts @@ -7,9 +7,9 @@ import { IPublicTypeRect, IPublicTypeLocationDetail, IPublicTypeLocationData, + IPublicModelLocateEvent, } from '@alilc/lowcode-types'; - export interface Point { clientX: number; clientY: number; @@ -99,11 +99,15 @@ 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 IPublicModelDropLocation { +export interface IDropLocation extends Omit< IPublicModelDropLocation, 'target' | 'clone' > { readonly source: string; + get target(): INode; + get document(): IPublicModelDocumentModel; + + clone(event: IPublicModelLocateEvent): IDropLocation; } export class DropLocation implements IDropLocation { @@ -126,7 +130,7 @@ export class DropLocation implements IDropLocation { this.event = event; } - clone(event: ILocateEvent): DropLocation { + clone(event: ILocateEvent): IDropLocation { return new DropLocation({ target: this.target, detail: this.detail, diff --git a/packages/designer/src/designer/setting/setting-entry.ts b/packages/designer/src/designer/setting/setting-entry.ts index 9d07001e5..a625e9424 100644 --- a/packages/designer/src/designer/setting/setting-entry.ts +++ b/packages/designer/src/designer/setting/setting-entry.ts @@ -1,11 +1,11 @@ import { IPublicModelSettingTarget } from '@alilc/lowcode-types'; -import { ComponentMeta } from '../../component-meta'; +import { IComponentMeta } from '../../component-meta'; import { Designer } from '../designer'; -import { Node } from '../../document'; +import { INode } from '../../document'; export interface SettingEntry extends IPublicModelSettingTarget { - readonly nodes: Node[]; - readonly componentMeta: ComponentMeta | null; + readonly nodes: INode[]; + readonly componentMeta: IComponentMeta | null; readonly designer: Designer; // 顶端 diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts index c632c8c37..3c3cee9d3 100644 --- a/packages/designer/src/designer/setting/setting-prop-entry.ts +++ b/packages/designer/src/designer/setting/setting-prop-entry.ts @@ -2,8 +2,8 @@ import { obx, computed, makeObservable, runInAction, IEventBus, createModuleEven import { GlobalEvent, IPublicModelEditor, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; import { uniqueId, isJSExpression, isSettingField } from '@alilc/lowcode-utils'; import { SettingEntry } from './setting-entry'; -import { Node } from '../../document'; -import { ComponentMeta } from '../../component-meta'; +import { INode } from '../../document'; +import { IComponentMeta } from '../../component-meta'; import { Designer } from '../designer'; import { Setters } from '@alilc/lowcode-shell'; @@ -19,9 +19,9 @@ export class SettingPropEntry implements SettingEntry { readonly setters: Setters; - readonly nodes: Node[]; + readonly nodes: INode[]; - readonly componentMeta: ComponentMeta | null; + readonly componentMeta: IComponentMeta | null; readonly designer: Designer; diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 642783588..84cceb919 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -11,12 +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 { readonly props: Props; readonly owner: INode; + get slotNode(): INode | null; + delete(prop: Prop): void; export(stage: IPublicEnumTransformStage): IPublicTypeCompositeValue; @@ -113,8 +115,8 @@ export class Prop implements IProp, IPropParent { private _slotNode?: INode; - get slotNode(): INode | undefined | null { - return this._slotNode; + get slotNode(): INode | null { + return this._slotNode || null; } @obx.shallow private _items: Prop[] | null = null; diff --git a/packages/shell/src/model/active-tracker.ts b/packages/shell/src/model/active-tracker.ts index 77ddeffab..41871aacb 100644 --- a/packages/shell/src/model/active-tracker.ts +++ b/packages/shell/src/model/active-tracker.ts @@ -1,5 +1,5 @@ import { IPublicModelActiveTracker, IPublicModelNode, IPublicTypeActiveTarget } from '@alilc/lowcode-types'; -import { IActiveTracker as InnerActiveTracker, INode as InnerNode } from '@alilc/lowcode-designer'; +import { IActiveTracker as InnerActiveTracker, ActiveTarget } from '@alilc/lowcode-designer'; import { Node as ShellNode } from './node'; import { nodeSymbol } from '../symbols'; @@ -16,9 +16,9 @@ export class ActiveTracker implements IPublicModelActiveTracker { if (!fn) { return () => {}; } - return this[activeTrackerSymbol].onChange((t: IPublicTypeActiveTarget) => { + return this[activeTrackerSymbol].onChange((t: ActiveTarget) => { const { node: innerNode, detail, instance } = t; - const publicNode = ShellNode.create(innerNode as InnerNode); + const publicNode = ShellNode.create(innerNode); const publicActiveTarget = { node: publicNode!, detail, diff --git a/packages/shell/src/model/drop-location.ts b/packages/shell/src/model/drop-location.ts index d927c969f..f38e74a07 100644 --- a/packages/shell/src/model/drop-location.ts +++ b/packages/shell/src/model/drop-location.ts @@ -2,7 +2,7 @@ import { IDropLocation as InnerDropLocation, } from '@alilc/lowcode-designer'; import { dropLocationSymbol } from '../symbols'; -import { Node } from './node'; +import { Node as ShellNode } from './node'; import { IPublicModelDropLocation, IPublicTypeLocationDetail, IPublicModelLocateEvent } from '@alilc/lowcode-types'; export class DropLocation implements IPublicModelDropLocation { @@ -20,7 +20,7 @@ export class DropLocation implements IPublicModelDropLocation { } get target() { - return Node.create(this[dropLocationSymbol].target); + return ShellNode.create(this[dropLocationSymbol].target); } get detail(): IPublicTypeLocationDetail { diff --git a/packages/shell/src/model/node.ts b/packages/shell/src/model/node.ts index 40bad153d..ba2412e89 100644 --- a/packages/shell/src/model/node.ts +++ b/packages/shell/src/model/node.ts @@ -335,6 +335,7 @@ export class Node implements IPublicModelNode { } const shellNode = new Node(node); // @ts-ignore 挂载 shell node 实例 + // eslint-disable-next-line no-param-reassign node[shellNodeSymbol] = shellNode; return shellNode; } diff --git a/packages/shell/src/model/resource.ts b/packages/shell/src/model/resource.ts index 0ca3f2445..3fa625ed6 100644 --- a/packages/shell/src/model/resource.ts +++ b/packages/shell/src/model/resource.ts @@ -1,7 +1,6 @@ import { IPublicModelResource } from '@alilc/lowcode-types'; import { Resource as InnerResource } from '@alilc/lowcode-workspace'; import { resourceSymbol } from '../symbols'; -import { ResourceType } from './resource-type'; export class Resource implements IPublicModelResource { readonly [resourceSymbol]: InnerResource; diff --git a/packages/shell/src/model/setting-prop-entry.ts b/packages/shell/src/model/setting-prop-entry.ts index b28c4adf0..88861cac4 100644 --- a/packages/shell/src/model/setting-prop-entry.ts +++ b/packages/shell/src/model/setting-prop-entry.ts @@ -12,9 +12,9 @@ import { IPublicTypeSetValueOptions, } from '@alilc/lowcode-types'; import { settingPropEntrySymbol } from '../symbols'; -import { Node } from './node'; -import { SettingTopEntry } from './setting-top-entry'; -import { ComponentMeta } from './component-meta'; +import { Node as ShellNode } from './node'; +import { 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 { @@ -92,14 +92,14 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { } get props(): IPublicModelSettingTopEntry { - return SettingTopEntry.create(this[settingPropEntrySymbol].props); + return ShellSettingTopEntry.create(this[settingPropEntrySymbol].props); } /** * 获取设置属性对应的节点实例 */ get node(): IPublicModelNode | null { - return Node.create(this[settingPropEntrySymbol].getNode()); + return ShellNode.create(this[settingPropEntrySymbol].getNode()); } /** @@ -113,7 +113,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * 获取顶级设置属性 */ get top(): IPublicModelSettingTopEntry { - return SettingTopEntry.create(this[settingPropEntrySymbol].top); + return ShellSettingTopEntry.create(this[settingPropEntrySymbol].top); } /** @@ -127,7 +127,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * componentMeta */ get componentMeta(): IPublicModelComponentMeta | null { - return ComponentMeta.create(this[settingPropEntrySymbol].componentMeta); + return ShellComponentMeta.create(this[settingPropEntrySymbol].componentMeta); } /** @@ -233,7 +233,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry { * @returns */ getProps(): IPublicModelSettingTopEntry { - return SettingTopEntry.create(this[settingPropEntrySymbol].getProps() as SettingEntry) as any; + return ShellSettingTopEntry.create(this[settingPropEntrySymbol].getProps() as SettingEntry); } /** diff --git a/packages/shell/src/model/setting-top-entry.ts b/packages/shell/src/model/setting-top-entry.ts index 0c5fd2565..ddcd16471 100644 --- a/packages/shell/src/model/setting-top-entry.ts +++ b/packages/shell/src/model/setting-top-entry.ts @@ -1,7 +1,7 @@ import { SettingEntry } from '@alilc/lowcode-designer'; import { settingTopEntrySymbol } from '../symbols'; -import { Node } from './node'; -import { SettingPropEntry } from './setting-prop-entry'; +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 { @@ -19,7 +19,7 @@ export class SettingTopEntry implements IPublicModelSettingTopEntry { * 返回所属的节点实例 */ get node(): IPublicModelNode | null { - return Node.create(this[settingTopEntrySymbol].getNode()); + return ShellNode.create(this[settingTopEntrySymbol].getNode()); } /** @@ -28,7 +28,7 @@ export class SettingTopEntry implements IPublicModelSettingTopEntry { * @returns */ get(propName: string | number): IPublicModelSettingPropEntry { - return SettingPropEntry.create(this[settingTopEntrySymbol].get(propName) as any); + return ShellSettingPropEntry.create(this[settingTopEntrySymbol].get(propName) as any); } /** diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index 8645e3e09..06e408a96 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -1,7 +1,7 @@ import { windowSymbol } from '../symbols'; import { IPublicModelResource, IPublicModelWindow } from '@alilc/lowcode-types'; import { EditorWindow } from '@alilc/lowcode-workspace'; -import { Resource } from './resource'; +import { Resource as ShellResource } from './resource'; export class Window implements IPublicModelWindow { private readonly [windowSymbol]: EditorWindow; @@ -19,7 +19,7 @@ export class Window implements IPublicModelWindow { } get resource(): IPublicModelResource { - return new Resource(this[windowSymbol].resource); + return new ShellResource(this[windowSymbol].resource); } constructor(editorWindow: EditorWindow) { diff --git a/packages/types/src/shell/model/drop-location.ts b/packages/types/src/shell/model/drop-location.ts index 11ae888ac..e25522bce 100644 --- a/packages/types/src/shell/model/drop-location.ts +++ b/packages/types/src/shell/model/drop-location.ts @@ -7,7 +7,7 @@ export interface IPublicModelDropLocation { * 拖拽位置目标 * get target of dropLocation */ - get target(): IPublicModelNode; + get target(): IPublicModelNode | null; /** * 拖拽放置位置详情 From f25babe7286e78733c71e8d2486e1b26125f217f Mon Sep 17 00:00:00 2001 From: JackLian Date: Fri, 13 Jan 2023 15:47:21 +0800 Subject: [PATCH 15/89] refactor: add isInLiveEditing api to canvas for refactoring of hotkey plugin as a standalone one --- docs/docs/api/canvas.md | 37 +++++++--------- .../tests/designer/builtin-hotkey.test.ts | 11 ++--- .../src/inner-plugins/builtin-hotkey.ts | 42 ++++++------------- packages/shell/src/api/canvas.ts | 4 ++ packages/types/src/shell/api/canvas.ts | 11 ++++- 5 files changed, 46 insertions(+), 59 deletions(-) diff --git a/docs/docs/api/canvas.md b/docs/docs/api/canvas.md index 344223bcb..b6af6680e 100644 --- a/docs/docs/api/canvas.md +++ b/docs/docs/api/canvas.md @@ -1,5 +1,5 @@ --- -title: cavas - 画布 API +title: canvas - 画布 API sidebar_position: 12 --- @@ -17,30 +17,25 @@ sidebar_position: 12 获取拖拽操作对象的实例 -```typescript -/** - * 获取拖拽操作对象的实例 - * get dragon instance, you can use this to obtain draging related abilities and lifecycle hooks - * @since v1.1.0 - */ -get dragon(): IPublicModelDragon | null; -``` -关联模型 [IPublicModelDragon](./model/dragon) +`@type {IPublicModelDragon | null}` + + +相关类型:[IPublicModelDragon](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/dragon.ts) ### activeTracker 获取活动追踪器实例 -```typescript -/** - * 获取活动追踪器实例 - * 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. - * @since v1.1.0 - */ -get activeTracker(): IPublicModelActiveTracker | null; -``` +`@type {IPublicModelActiveTracker | null}` + +相关类型:[IPublicModelActiveTracker](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/active-tracker.ts) + +### isInLiveEditing + +是否处于 LiveEditing 状态 + +`@type {boolean}` + ## 方法 @@ -83,4 +78,4 @@ createScroller(scrollable: IPublicModelScrollable): IPublicModelScroller; * @since v1.1.0 */ createScrollTarget(shell: HTMLDivElement): IPublicModelScrollTarget; -``` \ No newline at end of file +``` diff --git a/packages/designer/tests/designer/builtin-hotkey.test.ts b/packages/designer/tests/designer/builtin-hotkey.test.ts index 6df390ee4..9cb068ac1 100644 --- a/packages/designer/tests/designer/builtin-hotkey.test.ts +++ b/packages/designer/tests/designer/builtin-hotkey.test.ts @@ -7,11 +7,11 @@ import { import { Designer } from '../../src/designer/designer'; import formSchema from '../fixtures/schema/form'; import { fireEvent } from '@testing-library/react'; -import { isInLiveEditing, builtinHotkey } from '../../../engine/src/inner-plugins/builtin-hotkey'; +import { builtinHotkey } from '../../../engine/src/inner-plugins/builtin-hotkey'; import { shellModelFactory } from '../../../engine/src/modules/shell-model-factory'; import { ILowCodePluginContextPrivate, LowCodePluginManager } from '@alilc/lowcode-designer'; import { IPublicApiPlugins } from '@alilc/lowcode-types'; -import { Logger, Project } from '@alilc/lowcode-shell'; +import { Logger, Project, Canvas } from '@alilc/lowcode-shell'; import { Workspace } from '@alilc/lowcode-workspace'; const editor = new Editor(); @@ -19,12 +19,6 @@ const workspace = new Workspace(); let designer: Designer; -describe('error scenarios', () => { - it('edtior not registered', () => { - expect(isInLiveEditing()).toBeUndefined(); - }); -}); - // keyCode 对应表:https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode // hotkey 模块底层用的 keyCode,所以还不能用 key / code 测试 describe('快捷键测试', () => { @@ -40,6 +34,7 @@ describe('快捷键测试', () => { context.hotkey = hotkey; context.logger = logger; context.project = project; + context.canvas = new Canvas(editor); } }; pluginManager = new LowCodePluginManager(contextApiAssembler).toProxy(); diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index 6b926721b..3ee79831b 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -1,5 +1,4 @@ /* eslint-disable max-len */ -import { Editor, globalContext } from '@alilc/lowcode-editor-core'; import { isFormEvent } from '@alilc/lowcode-utils'; import { focusing, @@ -12,23 +11,9 @@ import { IPublicModelNode, } from '@alilc/lowcode-types'; import symbols from '../modules/symbols'; + const { nodeSymbol, documentSymbol } = symbols; -export function isInLiveEditing() { - const workspace = globalContext.has('workspace') && globalContext.get('workspace'); - if (workspace?.isActive) { - return Boolean( - workspace.window.editor.get('designer')?.project?.simulator?.liveEditing?.editing, - ); - } - - if (globalContext.has(Editor)) { - return Boolean( - globalContext.get(Editor).get('designer')?.project?.simulator?.liveEditing?.editing, - ); - } -} - /* istanbul ignore next */ function getNextForSelect(next: IPublicModelNode | null, head?: any, parent?: IPublicModelNode | null): any { if (next) { @@ -95,12 +80,12 @@ function getPrevForSelect(prev: IPublicModelNode | null, head?: any, parent?: IP export const builtinHotkey = (ctx: IPublicModelPluginContext) => { return { init() { - const { hotkey, project, logger } = ctx; + const { hotkey, project, logger, canvas } = ctx; // hotkey binding hotkey.bind(['backspace', 'del'], (e: KeyboardEvent, action) => { logger.info(`action ${action} is triggered`); - if (isInLiveEditing()) { + if (canvas.isInLiveEditing) { return; } // TODO: use focus-tracker @@ -124,7 +109,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { hotkey.bind('escape', (e: KeyboardEvent, action) => { logger.info(`action ${action} is triggered`); // const currentFocus = focusing.current; - if (isInLiveEditing()) { + if (canvas.isInLiveEditing) { return; } const sel = focusing.focusDesigner?.currentDocument?.selection; @@ -140,7 +125,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { // command + c copy command + x cut hotkey.bind(['command+c', 'ctrl+c', 'command+x', 'ctrl+x'], (e, action) => { logger.info(`action ${action} is triggered`); - if (isInLiveEditing()) { + if (canvas.isInLiveEditing) { return; } const doc = project.currentDocument; @@ -179,10 +164,9 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { // command + v paste hotkey.bind(['command+v', 'ctrl+v'], (e, action) => { logger.info(`action ${action} is triggered`); - if (isInLiveEditing()) { + if (canvas.isInLiveEditing) { return; } - if (isInLiveEditing()) return; // TODO const designer = focusing.focusDesigner; const doc = project?.currentDocument; @@ -212,7 +196,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { // command + z undo hotkey.bind(['command+z', 'ctrl+z'], (e, action) => { logger.info(`action ${action} is triggered`); - if (isInLiveEditing()) { + if (canvas.isInLiveEditing) { return; } const history = project.currentDocument?.history; @@ -230,7 +214,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { // command + shift + z redo hotkey.bind(['command+y', 'ctrl+y', 'command+shift+z'], (e, action) => { logger.info(`action ${action} is triggered`); - if (isInLiveEditing()) { + if (canvas.isInLiveEditing) { return; } const history = project.currentDocument?.history; @@ -247,7 +231,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { // sibling selection hotkey.bind(['left', 'right'], (e, action) => { logger.info(`action ${action} is triggered`); - if (isInLiveEditing()) { + if (canvas.isInLiveEditing) { return; } const doc = project.currentDocument; @@ -266,7 +250,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { hotkey.bind(['up', 'down'], (e, action) => { logger.info(`action ${action} is triggered`); - if (isInLiveEditing()) { + if (canvas.isInLiveEditing) { return; } const doc = project.currentDocument; @@ -291,7 +275,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { hotkey.bind(['option+left', 'option+right'], (e, action) => { logger.info(`action ${action} is triggered`); - if (isInLiveEditing()) { + if (canvas.isInLiveEditing) { return; } const doc = project.currentDocument; @@ -325,7 +309,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { hotkey.bind(['option+up'], (e, action) => { logger.info(`action ${action} is triggered`); - if (isInLiveEditing()) { + if (canvas.isInLiveEditing) { return; } const doc = project.currentDocument; @@ -367,7 +351,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { hotkey.bind(['option+down'], (e, action) => { logger.info(`action ${action} is triggered`); - if (isInLiveEditing()) { + if (canvas.isInLiveEditing) { return; } const doc = project.getCurrentDocument(); diff --git a/packages/shell/src/api/canvas.ts b/packages/shell/src/api/canvas.ts index 3c3129957..5489a8b75 100644 --- a/packages/shell/src/api/canvas.ts +++ b/packages/shell/src/api/canvas.ts @@ -36,6 +36,10 @@ export class Canvas implements IPublicApiCanvas { return activeTracker; } + get isInLiveEditing(): boolean { + return Boolean(this[editorSymbol].get('designer')?.project?.simulator?.liveEditing?.editing); + } + constructor(editor: IPublicModelEditor, readonly workspaceMode: boolean = false) { this[editorSymbol] = editor; } diff --git a/packages/types/src/shell/api/canvas.ts b/packages/types/src/shell/api/canvas.ts index 147d554ec..f7983e094 100644 --- a/packages/types/src/shell/api/canvas.ts +++ b/packages/types/src/shell/api/canvas.ts @@ -1,9 +1,11 @@ import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, IPublicModelScrollable, IPublicModelScroller, IPublicModelActiveTracker } from '../model'; import { IPublicTypeLocationData } from '../type'; +/** + * @since v1.1.0 + */ export interface IPublicApiCanvas { - /** * 创一个滚动控制器 Scroller,赋予一个视图滚动的基本能力, * a Scroller is a controller that gives a view (IPublicModelScrollable) the ability scrolling @@ -45,4 +47,11 @@ export interface IPublicApiCanvas { * @since v1.1.0 */ get activeTracker(): IPublicModelActiveTracker | null; + + /** + * 是否处于 LiveEditing 状态 + * check if canvas is in liveEditing state + * @since v1.1.0 + */ + get isInLiveEditing(): boolean; } From 8c7f57a12055cdde917ab145d5483cd7d7bf98c5 Mon Sep 17 00:00:00 2001 From: liujuping Date: Fri, 13 Jan 2023 18:01:29 +0800 Subject: [PATCH 16/89] fix: fix isJSFunction lacks the judgment of the old version of the protocol --- packages/utils/src/check-types/is-isfunction.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/utils/src/check-types/is-isfunction.ts b/packages/utils/src/check-types/is-isfunction.ts index 6ddf572ef..a6d5da900 100644 --- a/packages/utils/src/check-types/is-isfunction.ts +++ b/packages/utils/src/check-types/is-isfunction.ts @@ -1,4 +1,10 @@ - -export function isJSFunction(x: any): boolean { - return typeof x === 'object' && x && x.type === 'JSFunction'; +/** + * 内部版本 的 { type: 'JSExpression', source: '', value: '', extType: 'function' } 能力上等同于 JSFunction + */ +export function isInnerJsFunction(data: any) { + return data && data.type === 'JSExpression' && data.extType === 'function'; +} + +export function isJSFunction(data: any): boolean { + return typeof data === 'object' && data && data.type === 'JSFunction' || isInnerJsFunction(data); } From 0b0015c3685ad05f11e138596f9bc7c2faf89833 Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 16 Jan 2023 10:37:56 +0800 Subject: [PATCH 17/89] refactor: remove dependecy of designer.focusing for refactoring of hotkey plugin as a standalone one --- packages/designer/src/designer/designer.ts | 5 +- packages/designer/src/designer/focusing.ts | 8 --- packages/designer/src/designer/index.ts | 1 - packages/designer/src/document/node/node.ts | 14 ++--- .../src/inner-plugins/builtin-hotkey.ts | 63 ++++++++++++++++--- 5 files changed, 63 insertions(+), 28 deletions(-) delete mode 100644 packages/designer/src/designer/focusing.ts diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 6ade5fea0..0e3559e0a 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -30,7 +30,6 @@ import { ActiveTracker, IActiveTracker } from './active-tracker'; import { Detecting } from './detecting'; import { DropLocation } from './location'; import { OffsetObserver, createOffsetObserver } from './offset-observer'; -import { focusing } from './focusing'; import { SettingTopEntry } from './setting'; import { BemToolsManager } from '../builtin-simulator/bem-tools/manager'; import { ComponentActions } from '../component-actions'; @@ -241,9 +240,6 @@ export class Designer implements IDesigner { this.postEvent('init', this); this.setupSelection(); setupHistory(); - - // TODO: 先简单实现,后期通过焦点赋值 - focusing.focusDesigner = this; } setupSelection = () => { @@ -341,6 +337,7 @@ export class Designer implements IDesigner { /** * 获得合适的插入位置 + * @deprecated */ getSuitableInsertion( insertNode?: INode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[], diff --git a/packages/designer/src/designer/focusing.ts b/packages/designer/src/designer/focusing.ts deleted file mode 100644 index 66816bc03..000000000 --- a/packages/designer/src/designer/focusing.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Designer } from './designer'; - -// TODO: use focus-tracker replace -class Focusing { - focusDesigner?: Designer; -} - -export const focusing = new Focusing(); diff --git a/packages/designer/src/designer/index.ts b/packages/designer/src/designer/index.ts index 105291885..34d7a8c09 100644 --- a/packages/designer/src/designer/index.ts +++ b/packages/designer/src/designer/index.ts @@ -7,6 +7,5 @@ export * from './offset-observer'; export * from './scroller'; export * from './setting'; export * from './active-tracker'; -export * from './focusing'; export * from '../document'; export * from './clipboard'; diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 5525493a1..2b5433b00 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -1396,11 +1396,11 @@ export function comparePosition(node1: Node, node2: Node): PositionNO { export function insertChild( container: INode, - thing: Node | IPublicTypeNodeData, + thing: INode | IPublicTypeNodeData, at?: number | null, copy?: boolean, -): Node { - let node: Node; +): INode { + let node: INode; if (isNode(thing) && (copy || thing.isSlot())) { thing = thing.export(IPublicEnumTransformStage.Clone); } @@ -1410,20 +1410,20 @@ export function insertChild( node = container.document.createNode(thing); } - container.children.internalInsert(node, at); + container.children.insert(node, at); return node; } export function insertChildren( container: INode, - nodes: Node[] | IPublicTypeNodeData[], + nodes: INode[] | IPublicTypeNodeData[], at?: number | null, copy?: boolean, -): Node[] { +): INode[] { let index = at; let node: any; - const results: Node[] = []; + const results: INode[] = []; // eslint-disable-next-line no-cond-assign while ((node = nodes.pop())) { node = insertChild(container, node, index, copy); diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index 3ee79831b..d0165d89f 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -1,7 +1,6 @@ /* eslint-disable max-len */ -import { isFormEvent } from '@alilc/lowcode-utils'; +import { isFormEvent, isNodeSchema } from '@alilc/lowcode-utils'; import { - focusing, insertChildren, clipboard, } from '@alilc/lowcode-designer'; @@ -9,11 +8,60 @@ import { IPublicModelPluginContext, IPublicEnumTransformStage, IPublicModelNode, + IPublicTypeNodeSchema, } from '@alilc/lowcode-types'; import symbols from '../modules/symbols'; const { nodeSymbol, documentSymbol } = symbols; +/** + * 获得合适的插入位置 + */ +function getSuitableInsertion( + pluginContext: IPublicModelPluginContext, + insertNode?: IPublicModelNode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[], +): { target: IPublicModelNode; index?: number } | null { + const { project, material } = pluginContext; + const activeDoc = project.currentDocument; + if (!activeDoc) { + return null; + } + if ( + Array.isArray(insertNode) && + isNodeSchema(insertNode[0]) && + material.getComponentMeta(insertNode[0].componentName)?.isModal + ) { + if (!activeDoc.root) { + return null; + } + + return { + target: activeDoc.root, + }; + } + + const focusNode = activeDoc.focusNode!; + const nodes = activeDoc.selection.getNodes(); + const refNode = nodes.find((item) => focusNode.contains(item)); + let target; + let index: number | undefined; + if (!refNode || refNode === focusNode) { + target = focusNode; + } else if (refNode.componentMeta?.isContainer) { + target = refNode; + } else { + // FIXME!!, parent maybe null + target = refNode.parent!; + index = refNode.index + 1; + } + + if (target && insertNode && !target.componentMeta?.checkNestingDown(target, insertNode)) { + return null; + } + + return { target, index }; +} + /* istanbul ignore next */ function getNextForSelect(next: IPublicModelNode | null, head?: any, parent?: IPublicModelNode | null): any { if (next) { @@ -108,11 +156,11 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { hotkey.bind('escape', (e: KeyboardEvent, action) => { logger.info(`action ${action} is triggered`); - // const currentFocus = focusing.current; + if (canvas.isInLiveEditing) { return; } - const sel = focusing.focusDesigner?.currentDocument?.selection; + const sel = project.currentDocument?.selection; if (isFormEvent(e) || !sel) { return; } @@ -168,15 +216,14 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { return; } // TODO - const designer = focusing.focusDesigner; const doc = project?.currentDocument; - if (isFormEvent(e) || !designer || !doc) { + if (isFormEvent(e) || !doc) { return; } /* istanbul ignore next */ clipboard.waitPasteData(e, ({ componentsTree }) => { if (componentsTree) { - const { target, index } = designer.getSuitableInsertion(componentsTree) || {}; + const { target, index } = getSuitableInsertion(ctx, componentsTree) || {}; if (!target) { return; } @@ -187,7 +234,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { const nodes = insertChildren(target, canAddComponentsTree, index); if (nodes) { doc.selection.selectAll(nodes.map((o) => o.id)); - setTimeout(() => designer.activeTracker.track(nodes[0]), 10); + setTimeout(() => canvas.activeTracker?.track(nodes[0]), 10); } } }); From 852977c0914a119ffcc42afddb7a4cb658a1f5bc Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 16 Jan 2023 16:09:26 +0800 Subject: [PATCH 18/89] refactor: add clipboard to canvas for refactoring of hotkey plugin as a standalone one --- docs/docs/api/canvas.md | 6 +++ docs/docs/api/model/clipboard.md | 43 +++++++++++++++++++ docs/docs/api/model/resource.md | 2 +- packages/designer/src/designer/clipboard.ts | 22 +++++++--- .../src/inner-plugins/builtin-hotkey.ts | 2 +- packages/shell/src/api/canvas.ts | 10 +++++ packages/shell/src/index.ts | 2 + packages/shell/src/model/clipboard.ts | 22 ++++++++++ packages/shell/src/model/index.ts | 3 +- packages/shell/src/symbols.ts | 3 +- packages/types/src/shell/api/canvas.ts | 10 ++++- packages/types/src/shell/model/clipboard.ts | 25 +++++++++++ packages/types/src/shell/model/index.ts | 3 +- 13 files changed, 140 insertions(+), 13 deletions(-) create mode 100644 docs/docs/api/model/clipboard.md create mode 100644 packages/shell/src/model/clipboard.ts create mode 100644 packages/types/src/shell/model/clipboard.ts diff --git a/docs/docs/api/canvas.md b/docs/docs/api/canvas.md index b6af6680e..c16ba62c5 100644 --- a/docs/docs/api/canvas.md +++ b/docs/docs/api/canvas.md @@ -36,6 +36,12 @@ sidebar_position: 12 `@type {boolean}` +### clipboard +全局剪贴板实例 + +`@type {IPublicModelClipboard}` + +相关类型:[IPublicModelClipboard](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/clipboard.ts) ## 方法 diff --git a/docs/docs/api/model/clipboard.md b/docs/docs/api/model/clipboard.md new file mode 100644 index 000000000..15d9e280c --- /dev/null +++ b/docs/docs/api/model/clipboard.md @@ -0,0 +1,43 @@ +--- +title: Clipboard +sidebar_position: 14 +--- + +> **@types** [IPublicModelClipboard](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/clipboard.ts)
+> **@since** v1.1.0 + +## 方法 + +### setData + +给剪贴板赋值 + +```typescript +/** + * 给剪贴板赋值 + * set data to clipboard + * + * @param {*} data + * @since v1.1.0 + */ +setData(data: any): void; +``` + +### waitPasteData + +设置剪贴板数据设置的回调 + +```typescript +/** + * 设置剪贴板数据设置的回调 + * set callback for clipboard provide paste data + * + * @param {KeyboardEvent} keyboardEvent + * @param {(data: any, clipboardEvent: ClipboardEvent) => void} cb + * @since v1.1.0 + */ +waitPasteData( + keyboardEvent: KeyboardEvent, + cb: (data: any, clipboardEvent: ClipboardEvent) => void, + ): void; +``` \ No newline at end of file diff --git a/docs/docs/api/model/resource.md b/docs/docs/api/model/resource.md index 30b1e9f41..74f8d8f71 100644 --- a/docs/docs/api/model/resource.md +++ b/docs/docs/api/model/resource.md @@ -1,6 +1,6 @@ --- title: Resource -sidebar_position: 12 +sidebar_position: 13 --- > **[@experimental](./#experimental)**
diff --git a/packages/designer/src/designer/clipboard.ts b/packages/designer/src/designer/clipboard.ts index a43b51b0e..941f91442 100644 --- a/packages/designer/src/designer/clipboard.ts +++ b/packages/designer/src/designer/clipboard.ts @@ -1,3 +1,5 @@ +import { IPublicModelClipboard } from '@alilc/lowcode-types'; + function getDataFromPasteEvent(event: ClipboardEvent) { const { clipboardData } = event; if (!clipboardData) { @@ -23,7 +25,13 @@ function getDataFromPasteEvent(event: ClipboardEvent) { } } -class Clipboard { +export interface IClipboard extends IPublicModelClipboard { + + initCopyPaster(el: HTMLTextAreaElement): void; + + injectCopyPaster(document: Document): void; +} +class Clipboard implements IClipboard { private copyPasters: HTMLTextAreaElement[] = []; private waitFn?: (data: any, e: ClipboardEvent) => void; @@ -56,7 +64,7 @@ class Clipboard { } injectCopyPaster(document: Document) { - if (this.copyPasters.find(x => x.ownerDocument === document)) { + if (this.copyPasters.find((x) => x.ownerDocument === document)) { return; } const copyPaster = document.createElement<'textarea'>('textarea'); @@ -69,8 +77,8 @@ class Clipboard { }; } - setData(data: any) { - const copyPaster = this.copyPasters.find(x => x.ownerDocument); + setData(data: any): void { + const copyPaster = this.copyPasters.find((x) => x.ownerDocument); if (!copyPaster) { return; } @@ -81,12 +89,12 @@ class Clipboard { copyPaster.blur(); } - waitPasteData(e: KeyboardEvent, cb: (data: any, e: ClipboardEvent) => void) { - const win = e.view; + waitPasteData(keyboardEvent: KeyboardEvent, cb: (data: any, e: ClipboardEvent) => void) { + const win = keyboardEvent.view; if (!win) { return; } - const copyPaster = this.copyPasters.find(cp => cp.ownerDocument === win.document); + const copyPaster = this.copyPasters.find((cp) => cp.ownerDocument === win.document); if (copyPaster) { copyPaster.select(); this.waitFn = cb; diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index d0165d89f..03d559a9a 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -2,7 +2,6 @@ import { isFormEvent, isNodeSchema } from '@alilc/lowcode-utils'; import { insertChildren, - clipboard, } from '@alilc/lowcode-designer'; import { IPublicModelPluginContext, @@ -129,6 +128,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { return { init() { const { hotkey, project, logger, canvas } = ctx; + const { clipboard } = canvas; // hotkey binding hotkey.bind(['backspace', 'del'], (e: KeyboardEvent, action) => { logger.info(`action ${action} is triggered`); diff --git a/packages/shell/src/api/canvas.ts b/packages/shell/src/api/canvas.ts index 5489a8b75..444894452 100644 --- a/packages/shell/src/api/canvas.ts +++ b/packages/shell/src/api/canvas.ts @@ -8,6 +8,7 @@ import { IPublicModelEditor, IPublicModelDragon, IPublicModelActiveTracker, + IPublicModelClipboard, } from '@alilc/lowcode-types'; import { ScrollTarget as InnerScrollTarget, @@ -18,10 +19,14 @@ import { Dragon as ShellDragon, DropLocation as ShellDropLocation, ActiveTracker as ShellActiveTracker, + Clipboard as ShellClipboard, } from '../model'; +const clipboardInstanceSymbol = Symbol('clipboardInstace'); + export class Canvas implements IPublicApiCanvas { private readonly [editorSymbol]: IPublicModelEditor; + private readonly [clipboardInstanceSymbol]: IPublicModelClipboard; private get [designerSymbol](): IDesigner { return this[editorSymbol].get('designer') as IDesigner; @@ -40,8 +45,13 @@ export class Canvas implements IPublicApiCanvas { return Boolean(this[editorSymbol].get('designer')?.project?.simulator?.liveEditing?.editing); } + get clipboard(): IPublicModelClipboard { + return this[clipboardInstanceSymbol]; + } + constructor(editor: IPublicModelEditor, readonly workspaceMode: boolean = false) { this[editorSymbol] = editor; + this[clipboardInstanceSymbol] = new ShellClipboard(); } createScrollTarget(shell: HTMLDivElement): IPublicModelScrollTarget { diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index 92d616945..0307349ab 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -9,6 +9,7 @@ import { Dragon, SettingPropEntry, SettingTopEntry, + Clipboard, } from './model'; import { Project, @@ -57,4 +58,5 @@ export { Logger, Canvas, Workspace, + Clipboard, }; \ No newline at end of file diff --git a/packages/shell/src/model/clipboard.ts b/packages/shell/src/model/clipboard.ts new file mode 100644 index 000000000..9c4b30945 --- /dev/null +++ b/packages/shell/src/model/clipboard.ts @@ -0,0 +1,22 @@ +import { IPublicModelClipboard } from '@alilc/lowcode-types'; +import { clipboardSymbol } from '../symbols'; +import { IClipboard, clipboard } from '@alilc/lowcode-designer'; + +export class Clipboard implements IPublicModelClipboard { + private readonly [clipboardSymbol]: IClipboard; + + constructor() { + this[clipboardSymbol] = clipboard; + } + + setData(data: any): void { + this[clipboardSymbol].setData(data); + } + + waitPasteData( + keyboardEvent: KeyboardEvent, + cb: (data: any, clipboardEvent: ClipboardEvent) => void, + ): void { + this[clipboardSymbol].waitPasteData(keyboardEvent, cb); + } +} \ No newline at end of file diff --git a/packages/shell/src/model/index.ts b/packages/shell/src/model/index.ts index d20120c3e..f2805342e 100644 --- a/packages/shell/src/model/index.ts +++ b/packages/shell/src/model/index.ts @@ -17,4 +17,5 @@ export * from './setting-top-entry'; export * from './resource'; export * from './active-tracker'; export * from './plugin-instance'; -export * from './window'; \ No newline at end of file +export * from './window'; +export * from './clipboard'; \ No newline at end of file diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index cd164f62a..dac981e96 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -30,4 +30,5 @@ export const workspaceSymbol = Symbol('workspace'); export const windowSymbol = Symbol('window'); export const pluginInstanceSymbol = Symbol('plugin-instance'); export const resourceTypeSymbol = Symbol('resourceType'); -export const resourceSymbol = Symbol('resource'); \ No newline at end of file +export const resourceSymbol = Symbol('resource'); +export const clipboardSymbol = Symbol('clipboard'); \ No newline at end of file diff --git a/packages/types/src/shell/api/canvas.ts b/packages/types/src/shell/api/canvas.ts index f7983e094..33fbc7781 100644 --- a/packages/types/src/shell/api/canvas.ts +++ b/packages/types/src/shell/api/canvas.ts @@ -1,4 +1,4 @@ -import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, IPublicModelScrollable, IPublicModelScroller, IPublicModelActiveTracker } from '../model'; +import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, IPublicModelScrollable, IPublicModelScroller, IPublicModelActiveTracker, IPublicModelClipboard } from '../model'; import { IPublicTypeLocationData } from '../type'; /** @@ -54,4 +54,12 @@ export interface IPublicApiCanvas { * @since v1.1.0 */ get isInLiveEditing(): boolean; + + /** + * 获取全局剪贴板实例 + * get clipboard instance + * + * @since v1.1.0 + */ + get clipboard(): IPublicModelClipboard; } diff --git a/packages/types/src/shell/model/clipboard.ts b/packages/types/src/shell/model/clipboard.ts new file mode 100644 index 000000000..7fdcc4b1c --- /dev/null +++ b/packages/types/src/shell/model/clipboard.ts @@ -0,0 +1,25 @@ + +export interface IPublicModelClipboard { + + /** + * 给剪贴板赋值 + * set data to clipboard + * + * @param {*} data + * @since v1.1.0 + */ + setData(data: any): void; + + /** + * 设置剪贴板数据设置的回调 + * set callback for clipboard provide paste data + * + * @param {KeyboardEvent} keyboardEvent + * @param {(data: any, clipboardEvent: ClipboardEvent) => void} cb + * @since v1.1.0 + */ + waitPasteData( + keyboardEvent: KeyboardEvent, + cb: (data: any, clipboardEvent: ClipboardEvent) => void, + ): void; +} diff --git a/packages/types/src/shell/model/index.ts b/packages/types/src/shell/model/index.ts index e59216faa..8f48f68f1 100644 --- a/packages/types/src/shell/model/index.ts +++ b/packages/types/src/shell/model/index.ts @@ -28,4 +28,5 @@ export * from './editor'; export * from './preference'; export * from './plugin-instance'; export * from './sensor'; -export * from './resource'; \ No newline at end of file +export * from './resource'; +export * from './clipboard'; \ No newline at end of file From e6e5ea8a104534eb6300641b6b6d0be035db37f0 Mon Sep 17 00:00:00 2001 From: haoziqaq <357229046@qq.com> Date: Tue, 17 Jan 2023 15:55:54 +0800 Subject: [PATCH 19/89] fix(plugin-outline-pane): fix text display errors and improve internationalization --- packages/plugin-outline-pane/src/locale/en-US.json | 7 +++++++ packages/plugin-outline-pane/src/locale/zh-CN.json | 7 +++++++ packages/plugin-outline-pane/src/views/filter-tree.ts | 8 ++++---- packages/plugin-outline-pane/src/views/filter.tsx | 9 +++++---- packages/plugin-outline-pane/src/views/pane.tsx | 3 +-- packages/plugin-outline-pane/src/views/tree-node.tsx | 2 +- 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/plugin-outline-pane/src/locale/en-US.json b/packages/plugin-outline-pane/src/locale/en-US.json index 8bb4221f7..b0f3d3e4a 100644 --- a/packages/plugin-outline-pane/src/locale/en-US.json +++ b/packages/plugin-outline-pane/src/locale/en-US.json @@ -11,5 +11,12 @@ "Slots": "Slots", "Slot for {prop}": "Slot for {prop}", "Outline Tree": "Outline Tree", + "Filter Node": "Filter Node", + "Check All": "Check All", + "Conditional rendering": "Conditional rendering", + "Loop rendering": "Loop rendering", + "Locked": "Locked", + "Hidden": "Hidden", + "Modal View": "Modal View", "Rename": "Rename" } diff --git a/packages/plugin-outline-pane/src/locale/zh-CN.json b/packages/plugin-outline-pane/src/locale/zh-CN.json index 822bf9e94..8036688f2 100644 --- a/packages/plugin-outline-pane/src/locale/zh-CN.json +++ b/packages/plugin-outline-pane/src/locale/zh-CN.json @@ -11,5 +11,12 @@ "Slots": "插槽", "Slot for {prop}": "属性 {prop} 的插槽", "Outline Tree": "大纲树", + "Filter Node": "过滤节点", + "Check All": "全选", + "Conditional rendering": "条件渲染", + "Loop rendering": "循环渲染", + "Locked": "已锁定", + "Hidden": "已隐藏", + "Modal View": "模态视图层", "Rename": "重命名" } diff --git a/packages/plugin-outline-pane/src/views/filter-tree.ts b/packages/plugin-outline-pane/src/views/filter-tree.ts index 61ecb9c02..2a07e15c6 100644 --- a/packages/plugin-outline-pane/src/views/filter-tree.ts +++ b/packages/plugin-outline-pane/src/views/filter-tree.ts @@ -9,16 +9,16 @@ export const FilterType = { export const FILTER_OPTIONS = [{ value: FilterType.CONDITION, - label: '条件渲染', + label: 'Conditional rendering', }, { value: FilterType.LOOP, - label: '循环渲染', + label: 'Loop rendering', }, { value: FilterType.LOCKED, - label: '已锁定', + label: 'Locked', }, { value: FilterType.HIDDEN, - label: '已隐藏', + label: 'Hidden', }]; export const matchTreeNode = ( diff --git a/packages/plugin-outline-pane/src/views/filter.tsx b/packages/plugin-outline-pane/src/views/filter.tsx index 223a4eab0..d4fa792ae 100644 --- a/packages/plugin-outline-pane/src/views/filter.tsx +++ b/packages/plugin-outline-pane/src/views/filter.tsx @@ -5,10 +5,11 @@ 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 Component<{ tree: Tree; + pluginContext: IPublicModelPluginContext; }, { keywords: string; filterOps: string[]; @@ -55,7 +56,7 @@ export default class Filter extends Component<{ - 全选 + {this.props.pluginContext.intlNode('Check All')} - {op.label} + {this.props.pluginContext.intlNode(op.label)} ))} diff --git a/packages/plugin-outline-pane/src/views/pane.tsx b/packages/plugin-outline-pane/src/views/pane.tsx index 1ed4c74ba..4cee54a51 100644 --- a/packages/plugin-outline-pane/src/views/pane.tsx +++ b/packages/plugin-outline-pane/src/views/pane.tsx @@ -6,7 +6,6 @@ import { IPublicModelPluginContext } from '@alilc/lowcode-types'; import Filter from './filter'; import { TreeMaster } from '../controllers/tree-master'; - export class Pane extends Component<{ config: any; pluginContext: IPublicModelPluginContext; @@ -40,7 +39,7 @@ export class Pane extends Component<{ return (
- +
this.controller.mount(shell)} className="lc-outline-tree-container">
diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx index a6dc03f08..789068c18 100644 --- a/packages/plugin-outline-pane/src/views/tree-node.tsx +++ b/packages/plugin-outline-pane/src/views/tree-node.tsx @@ -38,7 +38,7 @@ class ModalTreeNodeView extends Component<{ return (
- 模态视图层 + {this.pluginContext.intlNode('Modal View')}
Date: Mon, 16 Jan 2023 16:57:20 +0800 Subject: [PATCH 20/89] refactor: use insertChildren from hotkey plugin instead of from designer --- .../src/inner-plugins/builtin-hotkey.ts | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index 03d559a9a..75d36bc6f 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -1,18 +1,56 @@ /* eslint-disable max-len */ -import { isFormEvent, isNodeSchema } from '@alilc/lowcode-utils'; -import { - insertChildren, -} from '@alilc/lowcode-designer'; +import { isFormEvent, isNodeSchema, isNode } from '@alilc/lowcode-utils'; import { IPublicModelPluginContext, IPublicEnumTransformStage, IPublicModelNode, IPublicTypeNodeSchema, + IPublicTypeNodeData, } from '@alilc/lowcode-types'; import symbols from '../modules/symbols'; const { nodeSymbol, documentSymbol } = symbols; +function insertChild( + container: IPublicModelNode, + originalChild: IPublicModelNode | IPublicTypeNodeData, + at?: number | null, +): IPublicModelNode | null { + let child = originalChild; + if (isNode(child) && (child as IPublicModelNode).isSlotNode) { + child = (child as IPublicModelNode).exportSchema(IPublicEnumTransformStage.Clone); + } + let node = null; + if (isNode(child)) { + node = (child as IPublicModelNode); + container.children?.insert(node, at); + } else { + node = container.document?.createNode(child) || null; + if (node) { + container.children?.insert(node, at); + } + } + + return (node as IPublicModelNode) || null; +} + +function insertChildren( + container: IPublicModelNode, + nodes: IPublicModelNode[] | IPublicTypeNodeData[], + at?: number | null, +): IPublicModelNode[] { + let index = at; + let node: any; + const results: IPublicModelNode[] = []; + // eslint-disable-next-line no-cond-assign + while ((node = nodes.pop())) { + node = insertChild(container, node, index); + results.push(node); + index = node.index; + } + return results; +} + /** * 获得合适的插入位置 */ From 5c6572e3026ce7dafde6648b04f6ea0bc1be4b5e Mon Sep 17 00:00:00 2001 From: haoziqaq <357229046@qq.com> Date: Tue, 17 Jan 2023 18:58:34 +0800 Subject: [PATCH 21/89] fix(react-simulator-renderer): fix missing i18n of customCreateElement --- .../src/locale/en-US.json | 4 ++++ .../src/locale/index.ts | 21 +++++++++++++++++++ .../src/locale/zh-CN.json | 4 ++++ .../src/renderer-view.tsx | 10 +++++---- 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 packages/react-simulator-renderer/src/locale/en-US.json create mode 100644 packages/react-simulator-renderer/src/locale/index.ts create mode 100644 packages/react-simulator-renderer/src/locale/zh-CN.json diff --git a/packages/react-simulator-renderer/src/locale/en-US.json b/packages/react-simulator-renderer/src/locale/en-US.json new file mode 100644 index 000000000..ac864c0a2 --- /dev/null +++ b/packages/react-simulator-renderer/src/locale/en-US.json @@ -0,0 +1,4 @@ +{ + "Drag and drop components or templates here": "Drag and drop components or templates here", + "Locked elements and child elements cannot be edited": "Locked elements and child elements cannot be edited" +} \ No newline at end of file diff --git a/packages/react-simulator-renderer/src/locale/index.ts b/packages/react-simulator-renderer/src/locale/index.ts new file mode 100644 index 000000000..e4b39a347 --- /dev/null +++ b/packages/react-simulator-renderer/src/locale/index.ts @@ -0,0 +1,21 @@ +import { createElement } from 'react'; +import enUS from './en-US.json'; +import zhCN from './zh-CN.json'; + +const instance: Record> = { + 'zh-CN': zhCN as Record, + 'en-US': enUS as Record, +}; + +export function createIntl(locale: string = 'zh-CN') { + const intl = (id: string) => { + return instance[locale][id]; + }; + + const intlNode = (id: string) => createElement('span', instance[locale][id]); + + return { + intl, + intlNode, + }; +} diff --git a/packages/react-simulator-renderer/src/locale/zh-CN.json b/packages/react-simulator-renderer/src/locale/zh-CN.json new file mode 100644 index 000000000..74bb821dd --- /dev/null +++ b/packages/react-simulator-renderer/src/locale/zh-CN.json @@ -0,0 +1,4 @@ +{ + "Drag and drop components or templates here": "拖拽组件或模板到这里", + "Locked elements and child elements cannot be edited": "锁定元素及子元素无法编辑" +} \ No newline at end of file diff --git a/packages/react-simulator-renderer/src/renderer-view.tsx b/packages/react-simulator-renderer/src/renderer-view.tsx index d1c7abe30..68e66fc02 100644 --- a/packages/react-simulator-renderer/src/renderer-view.tsx +++ b/packages/react-simulator-renderer/src/renderer-view.tsx @@ -10,6 +10,7 @@ import { SimulatorRendererContainer, DocumentInstance } from './renderer'; import { host } from './host'; import { isRendererDetached } from './utils/misc'; import './renderer.less'; +import { createIntl } from './locale'; // patch cloneElement avoid lost keyProps const originCloneElement = window.React.cloneElement; @@ -130,6 +131,7 @@ class Renderer extends Component<{ documentInstance: DocumentInstance; }> { startTime: number | null = null; + schemaChangedSymbol = false; componentDidUpdate() { this.recordTime(); @@ -152,8 +154,6 @@ class Renderer extends Component<{ this.recordTime(); } - schemaChangedSymbol = false; - getSchemaChangedSymbol = () => { return this.schemaChangedSymbol; }; @@ -172,6 +172,8 @@ class Renderer extends Component<{ if (!container.autoRender || isRendererDetached()) return null; + const { intl } = createIntl(locale); + return ( { return node?.getExtraProp('isLocked')?.getValue() === true; }); if (lockedNode) { - defaultPlaceholder = '锁定元素及子元素无法编辑'; + defaultPlaceholder = intl('Locked elements and child elements cannot be edited'); } children = (
From be309cba0178010a14ef8dca5169f3ad900832e7 Mon Sep 17 00:00:00 2001 From: haoziqaq <357229046@qq.com> Date: Thu, 19 Jan 2023 10:41:15 +0800 Subject: [PATCH 22/89] fix(editor-skeleton): fix missing i18n --- .../src/transducers/addon-combine.ts | 108 ++++++++++-------- 1 file changed, 63 insertions(+), 45 deletions(-) diff --git a/packages/editor-skeleton/src/transducers/addon-combine.ts b/packages/editor-skeleton/src/transducers/addon-combine.ts index 1b5c27015..855dbe569 100644 --- a/packages/editor-skeleton/src/transducers/addon-combine.ts +++ b/packages/editor-skeleton/src/transducers/addon-combine.ts @@ -1,8 +1,14 @@ -import { IPublicTypeTransformedComponentMetadata, IPublicTypeFieldConfig, IPublicModelSettingTarget } from '@alilc/lowcode-types'; +import { + IPublicTypeTransformedComponentMetadata, + IPublicTypeFieldConfig, + IPublicModelSettingTarget, +} from '@alilc/lowcode-types'; import { IconSlot } from '../icons/slot'; import { getConvertedExtraKey } from '@alilc/lowcode-designer'; -export default function (metadata: IPublicTypeTransformedComponentMetadata): IPublicTypeTransformedComponentMetadata { +export default function ( + metadata: IPublicTypeTransformedComponentMetadata, +): IPublicTypeTransformedComponentMetadata { const { componentName, configure = {} } = metadata; // 如果已经处理过,不再重新执行一遍 @@ -111,35 +117,33 @@ export default function (metadata: IPublicTypeTransformedComponentMetadata): IPu }, ]; } - /* - propsGroup.push({ - name: '#generals', - title: { type: 'i18n', 'zh-CN': '通用', 'en-US': 'General' }, - items: [ - { - name: 'id', - title: 'ID', - setter: 'StringSetter', - }, - { - name: 'key', - title: 'Key', - // todo: use Mixin - setter: 'StringSetter', - }, - { - name: 'ref', - title: 'Ref', - setter: 'StringSetter', - }, - { - name: '!more', - title: '更多', - setter: 'PropertiesSetter', - }, - ], - }); - */ + // propsGroup.push({ + // name: '#generals', + // title: { type: 'i18n', 'zh-CN': '通用', 'en-US': 'General' }, + // items: [ + // { + // name: 'id', + // title: 'ID', + // setter: 'StringSetter', + // }, + // { + // name: 'key', + // title: 'Key', + // // todo: use Mixin + // setter: 'StringSetter', + // }, + // { + // name: 'ref', + // title: 'Ref', + // setter: 'StringSetter', + // }, + // { + // name: '!more', + // title: '更多', + // setter: 'PropertiesSetter', + // }, + // ], + // }); const stylesGroup: IPublicTypeFieldConfig[] = []; const advancedGroup: IPublicTypeFieldConfig[] = []; if (propsGroup) { @@ -216,18 +220,24 @@ export default function (metadata: IPublicTypeTransformedComponentMetadata): IPu setValue(field: IPublicModelSettingTarget, eventData) { const { eventDataList, eventList } = eventData; - Array.isArray(eventList) && eventList.map((item) => { - field.parent.clearPropValue(item.name); - return item; - }); - Array.isArray(eventDataList) && eventDataList.map((item) => { - field.parent.setPropValue(item.name, { - type: 'JSFunction', - // 需要传下入参 - value: `function(){return this.${item.relatedEventName}.apply(this,Array.prototype.slice.call(arguments).concat([${item.paramStr ? item.paramStr : ''}])) }`, + Array.isArray(eventList) && + eventList.map((item) => { + field.parent.clearPropValue(item.name); + return item; + }); + Array.isArray(eventDataList) && + eventDataList.map((item) => { + field.parent.setPropValue(item.name, { + type: 'JSFunction', + // 需要传下入参 + value: `function(){return this.${ + item.relatedEventName + }.apply(this,Array.prototype.slice.call(arguments).concat([${ + item.paramStr ? item.paramStr : '' + }])) }`, + }); + return item; }); - return item; - }); }, }, ], @@ -296,7 +306,7 @@ export default function (metadata: IPublicTypeTransformedComponentMetadata): IPu }, { name: 'key', - title: '循环 Key', + title: { type: 'i18n', 'zh-CN': '循环 Key', 'en-US': 'Loop Key' }, setter: [ { componentName: 'StringSetter', @@ -317,8 +327,16 @@ export default function (metadata: IPublicTypeTransformedComponentMetadata): IPu advancedGroup.push({ name: 'key', title: { - label: '渲染唯一标识(key)', - tip: '搭配「条件渲染」或「循环渲染」时使用,和 react 组件中的 key 原理相同,点击查看帮助', + label: { + type: 'i18n', + 'zh-CN': '渲染唯一标识 (key)', + 'en-US': 'Render unique identifier (key)', + }, + tip: { + type: 'i18n', + 'zh-CN': '搭配「条件渲染」或「循环渲染」时使用,和 react 组件中的 key 原理相同,点击查看帮助', + 'en-US': 'Used with 「Conditional Rendering」or「Cycle Rendering」, the same principle as the key in the react component, click to view the help', + }, docUrl: 'https://www.yuque.com/lce/doc/qm75w3', }, setter: [ From 20f289fd28e7aed6aabbaa4a22c2d9157f2128d8 Mon Sep 17 00:00:00 2001 From: zhutengfei1990 <1041885117@qq.com> Date: Tue, 24 Jan 2023 16:47:55 +0800 Subject: [PATCH 23/89] fix: fix typo in specs --- 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 3e2b1342c..0d97f5cc0 100644 --- a/docs/docs/guide/design/specs.md +++ b/docs/docs/guide/design/specs.md @@ -23,7 +23,7 @@ sidebar_position: 1 对于低代码物料来说,A 平台创建的物料无法使用到 B 平台上,如果想在 B 平台实现同样的物料,需要按照 B 平台的标准搭建一份物料。 -对于 ProCode 物料来说,需要在低代码平台进行消费,是需要进行转换的,包括搭建配置项的生成、物料搭建试图等,可能还需要特殊的描述文件进行描述。由于这一层没有统一,同一份 ProCode 物料每接入一个低代码,可能需要的描述文件格式不同,转换的代码不同,使用的工具也不同。 +对于 ProCode 物料来说,需要在低代码平台进行消费,是需要进行转换的,包括搭建配置项的生成、物料搭建视图等,可能还需要特殊的描述文件进行描述。由于这一层没有统一,同一份 ProCode 物料每接入一个低代码,可能需要的描述文件格式不同,转换的代码不同,使用的工具也不同。 ### 生态隔离 From 093eeb9b700af38e07aff6097f5a95e2ec876877 Mon Sep 17 00:00:00 2001 From: JackLian Date: Sat, 28 Jan 2023 16:50:04 +0800 Subject: [PATCH 24/89] fix(docs): fix toc display issue for specs --- docs/docs/specs/material-spec.md | 62 ++++++++++++++++---------------- docs/docusaurus.config.js | 4 +-- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/docs/docs/specs/material-spec.md b/docs/docs/specs/material-spec.md index 234ec62f6..3bee847c0 100644 --- a/docs/docs/specs/material-spec.md +++ b/docs/docs/specs/material-spec.md @@ -84,7 +84,7 @@ component // 组件名称, 比如 biz-button ``` -#### README.md +##### README.md - README.md 应该包含业务组件的源信息、使用说明以及 API,示例如下: @@ -126,7 +126,7 @@ npm install @alifd/ice-layout -S | type | type | String | `primray`、`normal` | normal | ``` -#### package.json +##### package.json `package.json` 中包含了一些依赖信息和配置信息,示例如下: ```json @@ -159,7 +159,7 @@ npm install @alifd/ice-layout -S } ``` -#### src/index.js +##### src/index.js 包含组件的出口文件,示例如下: @@ -178,7 +178,7 @@ export default Button; import Button, { Group } form '@scope/button'; ``` -#### src/index.scss +##### src/index.scss ```css /* 不引入依赖组件的样式,比如组件 import { Button } from '@alifd/next'; */ @@ -193,7 +193,7 @@ import Button, { Group } form '@scope/button'; } ``` -#### demo +##### demo demo 目录存放的是组件的文档,无文档的业务组件无法带来任何价值,因此 demo 是必选项。demo 目录下的文件采取 markdown 的写法,可以是多个文件,示例(demo/basic.md)如下: demo/basic.md @@ -236,12 +236,12 @@ ReactDOM.render(
API 是组件的属性解释,给开发者作为组件属性配置的参考。为了保持 API 的一致性,我们制定这个 API 命名规范。对于业界通用的,约定俗成的命名,我们遵循社区的约定。对于业界有多种规则难以确定的,我们确定其中一种,大家共同遵守。 -#### 通用规则 +##### 通用规则 - 所有的 API 采用小驼峰的书写规则,如 `onChange`、`direction`、`defaultVisible`。 - 标签名采用大驼峰书写规则,如 `Menu`、`Slider`、`DatePicker`。 -#### 通用命名 +##### 通用命名 | API 名称 | 类型 | 描述 | 常见变量 | | :------------- | :------------- | :----------------------------------------------------------- | :---------------------------------------------------- | @@ -261,7 +261,7 @@ API 是组件的属性解释,给开发者作为组件属性配置的参考。 | has+'属性' | boolean | 拥有某个属性 | 例如 `hasArrow`, `hasHeader`, `hasClose` 等等 | -#### 多选枚举 +##### 多选枚举 当某个 API 的接口,允许用户指定多个枚举值的时候,我们把这个接口定义为多选枚举。一个很典型的例子是某个弹层组件的 `closable` 属性,我们会允许:键盘 esc 按键、点击 mask、点击 close 按钮、点击组件以外的任何区域进行关闭。 @@ -280,11 +280,11 @@ true 表示触发规则都会关闭,false 表示触发规则不会关闭。 - ``,任何情况下都不关闭,只能通过受控设置 visible - ``,用户按 esc 或者点击关闭按钮会关闭 -#### 事件 +##### 事件 - 标准事件或者自定义的符合 w3c 标准的事件,命名必须 on 开头, 即 `on` + 事件名,如 onExpand。 -#### 表单规范 +##### 表单规范 - 支持[受控模式](https://reactjs.org/docs/forms.html#controlled-components)(value + onChange) (A) - value 控制组件数据展现 @@ -292,7 +292,7 @@ true 表示触发规则都会关闭,false 表示触发规则不会关闭。 - `value={undefined}`的时候清空数据,field 的 reset 函数会给所有组件下发 undefined 数据 (AA)) - 一次完整操作抛一次 onChange 事件 `建议` 比如有 Process 表示进展中的状态,建议增加 API `onProcess`;如果有 Start 表示启动状态,建议增加 API `onStart`  (AA) -#### 属性的传递 +##### 属性的传递 **1. 原子组件(Atomic Component)** > 最小粒子,不能再拆分的组件 @@ -354,7 +354,7 @@ $ iceworks sync 文件命名采取 [bcp47](https://tools.ietf.org/html/bcp47) 规范 -#### 目录规范 +##### 目录规范 在 `src` 目录新增 `locale` 目录用于管理不同语言的文案。 @@ -367,7 +367,7 @@ $ iceworks sync |------ ja-JP.js ``` -#### 定义不同的语言 +##### 定义不同的语言 ```javascript // zh-CN.js @@ -390,7 +390,7 @@ export default { }; ``` -#### 组件支持多语言建议方案 +##### 组件支持多语言建议方案 ```jsx // index.jsx @@ -417,7 +417,7 @@ export default class BizHello extends Component { } ``` -#### 组件支持全局替换国际化文案 +##### 组件支持全局替换国际化文案 配合 ConfigProvider 支持全局替换国际化文案。 @@ -451,7 +451,7 @@ export default ConfigProvider.config(BizHello, { 业务组件中如果有自定义的需要跟随主题色的 UI,一定要引入变量的形式,增加组件的流通性。 -#### src/index.scss +##### src/index.scss ```css /* 如果需要引入主题变量引入此段 */ @@ -503,7 +503,7 @@ api 属性标准参考 [https://fusion.design/help.html#/dev-biz](https://fusio 无障碍需要符合 [WCAG 2.1 A 级标准](https://www.w3.org/TR/WCAG21/),可参考 [W3C 无障碍最佳实践](https://www.w3.org/TR/wai-aria-practices-1.1/)、[Fusion 无障碍指引 2.3.1](https://alibaba-fusion.github.io/next/part1/basics.html) 章节等。 -#### 增加 a11y.md 无障碍 demo +##### 增加 a11y.md 无障碍 demo 必须借助 API 才能完成无障碍工作的组件必须为开发者提供无障碍的使用文档,请[参考](https://fusion.design/pc/component/select?themeid=2#accessibility-container)组件 API 中 `ARIA and Keyboard` ,建议在 `demo` 目录新增 `a11y.md` 文件用于演示组件的无障碍使用。 @@ -517,7 +517,7 @@ component 详细指引查看无障碍开发指南 [https://alibaba-fusion.github.io/next/part1/basics.html](https://alibaba-fusion.github.io/next/part1/basics.html)。 -#### 通过键盘快速访问 +##### 通过键盘快速访问 一般键盘事件有 Up Arrow/Down Arrow/Enter/Esc/Tab @@ -531,7 +531,7 @@ component | Esc | 关闭列表 | -#### 对读屏软件友好 +##### 对读屏软件友好 - 对于组件,我们为开发者内置 `role` 和特定 `aria-_属性`,开发者也可以对非组件 API 属性都可以透传至 DOM 元素,进行修改 `role` 和 `aria-_参数`,但是要注意对应关系,请[参考](https://alibaba-fusion.github.io/next/part1/WAI-ARIA.html)。 - 对一些特殊的组件传递参数才能支持无障碍,设置 `id`,`autoFocus` 和传参数,如下: @@ -925,18 +925,18 @@ props 数组下对象字段描述: |initialChildren | 组件拖入“设计器”时根据此配置自动生成 children 节点 schema |NodeData[]/Function NodeData[] | ((target: SettingTarget) => 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 -|callbacks.onNodeRemove| 在容器中删除组件时触发的事件回调| Function| (e: MouseEvent, currentNode: any) => any +|callbacks.onNodeAdd| 在容器中拖入组件时触发的事件回调 | Function| (e: MouseEvent, currentNode: any) => any +|callbacks.onNodeRemove| 在容器中删除组件时触发的事件回调 | Function| (e: MouseEvent, currentNode: any) => any |callbacks.onResize| 调整容器尺寸时触发的事件回调,常常与 getResizingHandlers 搭配使用 | Function| 详见 Types 定义 |callbacks.onResizeStart| 调整容器尺寸开始时触发的事件回调,常常与 getResizingHandlers 搭配使用 | Function| 详见 Types 定义 |callbacks.onResizeEnd| 调整容器尺寸结束时触发的事件回调,常常与 getResizingHandlers 搭配使用 | Function| 详见 Types 定义 -|callbacks.onSubtreeModified| 容器节点结构树发生变化时触发的回调| Function| (currentNode: any, options: any) => void; -|callbacks.onMouseDownHook| 鼠标按下操作回调| Function| (e: MouseEvent, currentNode: any) => any; -|callbacks.onClickHook| 鼠标单击操作回调| Function| (e: MouseEvent, currentNode: any) => any; -|callbacks.onDblClickHook| 鼠标双击操作回调| Function| (e: MouseEvent, currentNode: any) => any; +|callbacks.onSubtreeModified| 容器节点结构树发生变化时触发的回调 | Function| (currentNode: any, options: any) => void; +|callbacks.onMouseDownHook| 鼠标按下操作回调 | Function| (e: MouseEvent, currentNode: any) => any; +|callbacks.onClickHook| 鼠标单击操作回调 | Function| (e: MouseEvent, currentNode: any) => any; +|callbacks.onDblClickHook| 鼠标双击操作回调 | Function| (e: MouseEvent, currentNode: any) => any; |callbacks.onMoveHook| 节点被拖动回调 | Function| (currentNode: any) => boolean; |callbacks.onHoverHook| 节点被 hover 回调 | Function| (currentNode: any) => boolean; -|callbacks.onChildMoveHook| 容器节点的子节点被拖动回调| Function| (childNode: any, currentNode: any) => boolean; +|callbacks.onChildMoveHook| 容器节点的子节点被拖动回调 | Function| (childNode: any, currentNode: any) => boolean; 描述举例: @@ -1543,7 +1543,7 @@ block/ ``` -#### 入口文件 +##### 入口文件 (/src/index.jsx) @@ -1559,7 +1559,7 @@ const App = hot(router); ReactDOM.render(, document.getElementById(pkg.config && pkg.config.targetRootID || 'root')); ``` -#### 应用参数配置文件 +##### 应用参数配置文件 (/src/config/app.js) @@ -1596,7 +1596,7 @@ export default { } ``` -#### 应用扩展配置规范: +##### 应用扩展配置规范: (/src/utils/index.js) @@ -1618,7 +1618,7 @@ export default { } ``` -#### 应用常量配置 +##### 应用常量配置 (/src/config/constants.js) @@ -1628,7 +1628,7 @@ export default { } ``` -#### 应用样式配置 +##### 应用样式配置 (/src/global.scss) diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 97a0237b4..0aaa4c50f 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -39,7 +39,6 @@ const config = { presets: [ [ 'classic', - /** @type {import('@docusaurus/preset-classic').Options} */ ({ docs: { sidebarPath: require.resolve('./config/sidebars.js'), @@ -55,7 +54,6 @@ const config = { ], themeConfig: - /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ docs: { sidebar: { @@ -76,7 +74,7 @@ const config = { metadata: [{ name: 'referrer', content: 'no-referrer' }], tableOfContents: { minHeadingLevel: 2, - maxHeadingLevel: 5, + maxHeadingLevel: 6, }, }), From 1b74e71353a4fde3b9030752cde93e27745b1ab6 Mon Sep 17 00:00:00 2001 From: JackLian Date: Sun, 29 Jan 2023 10:14:26 +0800 Subject: [PATCH 25/89] refactor: remove dependency of documentSymbol --- packages/designer/src/component-meta.ts | 10 +++--- .../designer/src/document/document-model.ts | 16 ++++++--- packages/designer/src/document/node/node.ts | 33 ++++++++----------- .../designer/tests/document/node/node.test.ts | 2 +- .../src/inner-plugins/builtin-hotkey.ts | 16 ++++++--- packages/shell/src/model/document-model.ts | 7 ++-- 6 files changed, 48 insertions(+), 36 deletions(-) diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 70d8630b5..9a74d0ddb 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -13,9 +13,9 @@ import { IPublicTypeMetadataTransducer, IPublicModelComponentMeta, } from '@alilc/lowcode-types'; -import { deprecate, isRegExp, isTitleConfig } from '@alilc/lowcode-utils'; +import { deprecate, isRegExp, isTitleConfig, isNode } from '@alilc/lowcode-utils'; import { computed, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core'; -import { isNode, Node, INode } from './document'; +import { Node, INode } from './document'; import { Designer } from './designer'; import { IconContainer, @@ -161,6 +161,9 @@ export class ComponentMeta implements IComponentMeta { return this._acceptable!; } + // compatiable vision + prototype?: any; + constructor(readonly designer: Designer, metadata: IPublicTypeComponentMetadata) { this.parseMetadata(metadata); } @@ -347,8 +350,6 @@ export class ComponentMeta implements IComponentMeta { }; } - // compatiable vision - prototype?: any; } export function isComponentMeta(obj: any): obj is ComponentMeta { @@ -373,4 +374,3 @@ function preprocessMetadata(metadata: IPublicTypeComponentMetadata): IPublicType configure: {}, }; } - diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 26648403b..5eb60c396 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -17,11 +17,11 @@ import { IProject, Project } from '../project'; import { ISimulatorHost } from '../simulator'; import { ComponentMeta } from '../component-meta'; import { IDropLocation, Designer, IHistory } from '../designer'; -import { Node, insertChildren, insertChild, isNode, RootNode, INode } from './node/node'; +import { Node, 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 } from '@alilc/lowcode-utils'; +import { uniqueId, isPlainObject, compatStage, isJSExpression, isDOMText, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isNode } from '@alilc/lowcode-utils'; import { EDITOR_EVENT } from '../types'; export type GetDataType = T extends undefined @@ -32,7 +32,7 @@ export type GetDataType = T extends undefined : any : T; -export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'selection' > { +export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'selection' | 'checkNesting' > { readonly designer: Designer; @@ -59,6 +59,11 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'select get rootNode(): INode | null; + checkNesting( + dropTarget: INode, + dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject, + ): boolean; + } export class DocumentModel implements IDocumentModel { @@ -569,7 +574,10 @@ export class DocumentModel implements IDocumentModel { this.rootNode = null; } - checkNesting(dropTarget: INode, dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | Node | IPublicTypeDragNodeDataObject): boolean { + checkNesting( + dropTarget: INode, + dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject, + ): boolean { let items: Array; if (isDragNodeDataObject(dragObject)) { items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data]; diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 2b5433b00..f52d7e7bf 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -16,7 +16,7 @@ import { IPublicModelExclusiveGroup, IPublicEnumTransformStage, } from '@alilc/lowcode-types'; -import { compatStage, isDOMText, isJSExpression } from '@alilc/lowcode-utils'; +import { compatStage, isDOMText, isJSExpression, isNode } from '@alilc/lowcode-utils'; import { SettingTopEntry } from '@alilc/lowcode-designer'; import { Props, getConvertedExtraKey, IProps } from './props/props'; import { DocumentModel, IDocumentModel } from '../document-model'; @@ -109,6 +109,8 @@ export interface INode extends IPublicModelNode { getExtraProp(key: string, createIfNone?: boolean): IProp | null; replaceChild(node: INode, data: any): INode; + + getSuitablePlace(node: INode, ref: any): any; } /** @@ -913,7 +915,7 @@ export class Node /** * 判断是否包含特定节点 */ - contains(node: Node): boolean { + contains(node: INode): boolean { return contains(this, node); } @@ -1149,14 +1151,14 @@ export class Node /** * TODO: replace non standard metas with standard ones. */ - getSuitablePlace(node: Node, ref: any): any { + getSuitablePlace(node: INode, ref: any): any { const focusNode = this.document?.focusNode; // 如果节点是模态框,插入到根节点下 if (node?.componentMeta?.isModal) { return { container: focusNode, ref }; } - if (!ref && this.contains(focusNode)) { + if (!ref && focusNode && this.contains(focusNode)) { const rootCanDropIn = focusNode.componentMeta?.prototype?.options?.canDropIn; if ( rootCanDropIn === undefined || @@ -1171,7 +1173,7 @@ export class Node if (this.isRoot() && this.children) { const dropElement = this.children.filter((c) => { - if (!c.isContainer()) { + if (!c.isContainerNode) { return false; } const canDropIn = c.componentMeta?.prototype?.options?.canDropIn; @@ -1304,22 +1306,15 @@ export type PageNode = Node; export type ComponentNode = Node; export type RootNode = PageNode | ComponentNode; -/** - * @deprecated use same function from '@alilc/lowcode-utils' instead - */ -export function isNode(node: any): node is Node { - return node && node.isNode; +export function isRootNode(node: INode): node is INode { + return node && node.isRootNode; } -export function isRootNode(node: Node): node is RootNode { - return node && node.isRoot(); -} - -export function isLowCodeComponent(node: Node): boolean { +export function isLowCodeComponent(node: INode): node is INode { return node.componentMeta?.getMetadata().devMode === 'lowCode'; } -export function getZLevelTop(child: Node, zLevel: number): Node | null { +export function getZLevelTop(child: INode, zLevel: number): INode | null { let l = child.zLevel; if (l < zLevel || zLevel < 0) { return null; @@ -1340,12 +1335,12 @@ export function getZLevelTop(child: Node, zLevel: number): Node | null { * @param node2 测试的被包含节点 * @returns 是否包含 */ -export function contains(node1: Node, node2: Node): boolean { +export function contains(node1: INode, node2: INode): boolean { if (node1 === node2) { return true; } - if (!node1.isParental() || !node2.parent) { + if (!node1.isParentalNode || !node2.parent) { return false; } @@ -1367,7 +1362,7 @@ export enum PositionNO { BeforeOrAfter = 2, TheSame = 0, } -export function comparePosition(node1: Node, node2: Node): PositionNO { +export function comparePosition(node1: INode, node2: INode): PositionNO { if (node1 === node2) { return PositionNO.TheSame; } diff --git a/packages/designer/tests/document/node/node.test.ts b/packages/designer/tests/document/node/node.test.ts index d8915c991..f7d35f6d6 100644 --- a/packages/designer/tests/document/node/node.test.ts +++ b/packages/designer/tests/document/node/node.test.ts @@ -7,7 +7,6 @@ import { DocumentModel } from '../../../src/document/document-model'; import { isRootNode, Node, - isNode, comparePosition, contains, PositionNO, @@ -23,6 +22,7 @@ import rootHeaderMetadata from '../../fixtures/component-metadata/root-header'; 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'; describe('Node 方法测试', () => { let editor: Editor; diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index 75d36bc6f..b6d3a0950 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -6,10 +6,12 @@ import { IPublicModelNode, IPublicTypeNodeSchema, IPublicTypeNodeData, + IPublicEnumDragObjectType, + IPublicTypeDragNodeObject, } from '@alilc/lowcode-types'; import symbols from '../modules/symbols'; -const { nodeSymbol, documentSymbol } = symbols; +const { nodeSymbol } = symbols; function insertChild( container: IPublicModelNode, @@ -265,10 +267,16 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { if (!target) { return; } - let canAddComponentsTree = componentsTree.filter((i) => { - return (doc as any)[documentSymbol].checkNestingUp(target, i); + let canAddComponentsTree = componentsTree.filter((node: IPublicModelNode) => { + const dragNodeObject: IPublicTypeDragNodeObject = { + type: IPublicEnumDragObjectType.Node, + nodes: [node], + }; + return doc.checkNesting(target, dragNodeObject); }); - if (canAddComponentsTree.length === 0) return; + if (canAddComponentsTree.length === 0) { + return; + } const nodes = insertChildren(target, canAddComponentsTree, index); if (nodes) { doc.selection.selectAll(nodes.map((o) => o.id)); diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts index 13fc49bae..ba371543a 100644 --- a/packages/shell/src/model/document-model.ts +++ b/packages/shell/src/model/document-model.ts @@ -8,7 +8,6 @@ import { GlobalEvent, IPublicModelDocumentModel, IPublicTypeOnChangeOptions, - IPublicModelDragObject, IPublicTypeDragNodeObject, IPublicTypeDragNodeDataObject, IPublicModelNode, @@ -227,9 +226,11 @@ export class DocumentModel implements IPublicModelDocumentModel { dropTarget: IPublicModelNode, dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject, ): boolean { - let innerDragObject: IPublicModelDragObject = dragObject; + let innerDragObject = dragObject; if (isDragNodeObject(dragObject)) { - innerDragObject.nodes = innerDragObject.nodes.map((node: Node) => (node[nodeSymbol] || node)); + innerDragObject.nodes = innerDragObject.nodes?.map( + (node: IPublicModelNode) => ((node as any)[nodeSymbol] || node), + ); } return this[documentSymbol].checkNesting( ((dropTarget as any)[nodeSymbol] || dropTarget) as any, From 67a5e724fd2934f6773456542cf9dbc40081d12a Mon Sep 17 00:00:00 2001 From: JackLian Date: Sun, 29 Jan 2023 17:35:24 +0800 Subject: [PATCH 26/89] refactor: remove dependency of nodeSymbol --- docs/docs/api/model/node.md | 4 +- packages/designer/src/document/node/node.ts | 2 +- .../src/inner-plugins/builtin-hotkey.ts | 70 +++++++++++++++++-- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/docs/docs/api/model/node.md b/docs/docs/api/model/node.md index fbc88034b..333e973f0 100644 --- a/docs/docs/api/model/node.md +++ b/docs/docs/api/model/node.md @@ -160,7 +160,7 @@ sidebar_position: 1 `@type {IPublicModelComponentMeta | null}` -相关类型:[IPublicTypeIconType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts) +相关类型:[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts) ### document @@ -644,4 +644,4 @@ isConditionalVisible(): boolean | undefined; setConditionalVisible(): void; ``` -**@since v1.1.0** \ No newline at end of file +**@since v1.1.0** diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index f52d7e7bf..1d294663b 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -1149,7 +1149,7 @@ export class Node } /** - * TODO: replace non standard metas with standard ones. + * @deprecated no one is using this, will be removed in a future release */ getSuitablePlace(node: INode, ref: any): any { const focusNode = this.document?.focusNode; diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index b6d3a0950..73aac64aa 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -9,9 +9,6 @@ import { IPublicEnumDragObjectType, IPublicTypeDragNodeObject, } from '@alilc/lowcode-types'; -import symbols from '../modules/symbols'; - -const { nodeSymbol } = symbols; function insertChild( container: IPublicModelNode, @@ -163,6 +160,67 @@ function getPrevForSelect(prev: IPublicModelNode | null, head?: any, parent?: IP return null; } +function getSuitablePlaceForNode(targetNode: IPublicModelNode, node: IPublicModelNode, ref: any): any { + const { document } = targetNode; + if (!document) { + return null; + } + + const dragNodeObject: IPublicTypeDragNodeObject = { + type: IPublicEnumDragObjectType.Node, + nodes: [node], + }; + + const focusNode = document?.focusNode; + // 如果节点是模态框,插入到根节点下 + if (node?.componentMeta?.isModal) { + return { container: focusNode, ref }; + } + const canDropInFn = document.checkNesting; + + if (!ref && focusNode && targetNode.contains(focusNode)) { + if (canDropInFn(focusNode, dragNodeObject)) { + return { container: focusNode }; + } + + return null; + } + + if (targetNode.isRootNode && targetNode.children) { + const dropElement = targetNode.children.filter((c) => { + if (!c.isContainerNode) { + return false; + } + if (canDropInFn(c, dragNodeObject)) { + return true; + } + return false; + })[0]; + + if (dropElement) { + return { container: dropElement, ref }; + } + + if (canDropInFn(targetNode, dragNodeObject)) { + return { container: targetNode, ref }; + } + + return null; + } + + if (targetNode.isContainerNode) { + if (canDropInFn(targetNode, dragNodeObject)) { + return { container: targetNode, ref }; + } + } + + if (targetNode.parent) { + return getSuitablePlaceForNode(targetNode.parent, node, { index: targetNode.index }); + } + + return null; +} + // 注册默认的 setters export const builtinHotkey = (ctx: IPublicModelPluginContext) => { return { @@ -426,14 +484,14 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { const silbing = firstNode.prevSibling; if (silbing) { if (silbing.isContainerNode) { - const place = (silbing as any)[nodeSymbol].getSuitablePlace(firstNode, null); + const place = getSuitablePlaceForNode(silbing, firstNode, null); silbing.insertAfter(firstNode, place.ref, true); } else { parent.insertBefore(firstNode, silbing, true); } firstNode?.select(); } else { - const place = (parent as any)[nodeSymbol].getSuitablePlace(firstNode, null); // upwards + const place = getSuitablePlaceForNode(parent, firstNode, null); // upwards if (place) { const container = place.container.internalToShellNode(); container.insertBefore(firstNode, place.ref); @@ -474,7 +532,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { } firstNode?.select(); } else { - const place = (parent as any)[nodeSymbol].getSuitablePlace(firstNode, null); // upwards + const place = getSuitablePlaceForNode(parent, firstNode, null); // upwards if (place) { const container = place.container.internalToShellNode(); container.insertAfter(firstNode, place.ref, true); From 6482609ac140b62ddd2b0469f187e0b9b775583b Mon Sep 17 00:00:00 2001 From: liujuping Date: Sun, 29 Jan 2023 19:00:02 +0800 Subject: [PATCH 27/89] feat: add resource layer layout in workspace mode --- .../types/src/shell/type/resource-list.ts | 2 +- .../src/{ => context}/base-context.ts | 6 +-- .../context.ts => context/view-context.ts} | 12 ++--- packages/workspace/src/index.ts | 2 +- packages/workspace/src/layouts/workbench.tsx | 6 +-- packages/workspace/src/resource.ts | 35 ++++++++------ .../view.tsx => view/editor-view.tsx} | 16 +++---- .../workspace/src/view/resource-view.less | 14 ++++++ packages/workspace/src/view/resource-view.tsx | 36 +++++++++++++++ .../view.tsx => view/window-view.tsx} | 25 ++++------ .../{editor-window/context.ts => window.ts} | 6 +-- packages/workspace/src/workspace.ts | 46 ++++++++++--------- 12 files changed, 127 insertions(+), 79 deletions(-) rename packages/workspace/src/{ => context}/base-context.ts (95%) rename packages/workspace/src/{editor-view/context.ts => context/view-context.ts} (93%) rename packages/workspace/src/{editor-view/view.tsx => view/editor-view.tsx} (69%) create mode 100644 packages/workspace/src/view/resource-view.less create mode 100644 packages/workspace/src/view/resource-view.tsx rename packages/workspace/src/{editor-window/view.tsx => view/window-view.tsx} (52%) rename packages/workspace/src/{editor-window/context.ts => window.ts} (95%) diff --git a/packages/types/src/shell/type/resource-list.ts b/packages/types/src/shell/type/resource-list.ts index e5fbcba7e..9b8cc3272 100644 --- a/packages/types/src/shell/type/resource-list.ts +++ b/packages/types/src/shell/type/resource-list.ts @@ -1,7 +1,7 @@ export interface IPublicResourceData { resourceName: string; title: string; - category: string; + category?: string; options: { [key: string]: any; }; diff --git a/packages/workspace/src/base-context.ts b/packages/workspace/src/context/base-context.ts similarity index 95% rename from packages/workspace/src/base-context.ts rename to packages/workspace/src/context/base-context.ts index 0ff63ee02..b90a131a3 100644 --- a/packages/workspace/src/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -1,5 +1,3 @@ -/* eslint-disable no-param-reassign */ -/* eslint-disable max-len */ import { Editor, engineConfig, Setters as InnerSetters, @@ -33,8 +31,8 @@ import { IPublicTypePluginMeta, } from '@alilc/lowcode-types'; import { getLogger } from '@alilc/lowcode-utils'; -import { Workspace as InnerWorkspace } from './workspace'; -import { EditorWindow } from './editor-window/context'; +import { Workspace as InnerWorkspace } from '../workspace'; +import { EditorWindow } from '../window'; export class BasicContext { skeleton: Skeleton; diff --git a/packages/workspace/src/editor-view/context.ts b/packages/workspace/src/context/view-context.ts similarity index 93% rename from packages/workspace/src/editor-view/context.ts rename to packages/workspace/src/context/view-context.ts index b991532fb..55bbf2d57 100644 --- a/packages/workspace/src/editor-view/context.ts +++ b/packages/workspace/src/context/view-context.ts @@ -2,8 +2,8 @@ import { 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 { BasicContext } from '../base-context'; -import { EditorWindow } from '../editor-window/context'; +import { BasicContext } from './base-context'; +import { EditorWindow } from '../window'; import { getWebviewPlugin } from '../inner-plugins/webview'; export class Context extends BasicContext { @@ -17,6 +17,10 @@ export class Context extends BasicContext { @obx isInit: boolean = false; + get active() { + return this._activate; + } + init = flow(function* (this: any) { if (this.viewType === 'webview') { const url = yield this.instance?.url?.(); @@ -44,10 +48,6 @@ export class Context extends BasicContext { this.innerHotkey.activate(this._activate); }; - get active() { - return this._activate; - } - async save() { return await this.instance?.save?.(); } diff --git a/packages/workspace/src/index.ts b/packages/workspace/src/index.ts index 2f6da97a8..9442266bb 100644 --- a/packages/workspace/src/index.ts +++ b/packages/workspace/src/index.ts @@ -1,4 +1,4 @@ export { Workspace } from './workspace'; -export * from './editor-window/context'; +export * from './window'; export * from './layouts/workbench'; export { Resource } from './resource'; diff --git a/packages/workspace/src/layouts/workbench.tsx b/packages/workspace/src/layouts/workbench.tsx index 7ffb0e531..fe5ef846f 100644 --- a/packages/workspace/src/layouts/workbench.tsx +++ b/packages/workspace/src/layouts/workbench.tsx @@ -1,6 +1,6 @@ import { Component } from 'react'; import { TipContainer, observer } from '@alilc/lowcode-editor-core'; -import { EditorWindowView } from '../editor-window/view'; +import { WindowView } from '../view/window-view'; import classNames from 'classnames'; import TopArea from './top-area'; import LeftArea from './left-area'; @@ -46,9 +46,9 @@ export class Workbench extends Component<{
{ workspace.windows.map(d => ( - )) diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index 2495909b4..effa6abee 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -1,6 +1,6 @@ import { IPublicTypeEditorView, IPublicModelResource, IPublicResourceData, IPublicResourceTypeConfig } from '@alilc/lowcode-types'; import { Logger } from '@alilc/lowcode-utils'; -import { BasicContext } from './base-context'; +import { BasicContext } from './context/base-context'; import { ResourceType } from './resource-type'; import { Workspace as InnerWorkSpace } from './workspace'; @@ -13,20 +13,6 @@ export class Resource implements IPublicModelResource { editorViewMap: Map = new Map(); - constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, workspace: InnerWorkSpace) { - this.context = new BasicContext(workspace, ''); - this.resourceTypeInstance = resourceType.resourceTypeModel(this.context, {}); - this.init(); - if (this.resourceTypeInstance.editorViews) { - this.resourceTypeInstance.editorViews.forEach((d: any) => { - this.editorViewMap.set(d.viewName, d); - }); - } - if (!resourceType) { - logger.error(`resourceType[${resourceType}] is unValid.`); - } - } - get name() { return this.resourceType.name; } @@ -55,6 +41,24 @@ export class Resource implements IPublicModelResource { return this.resourceData?.category; } + get skeleton() { + return this.context.innerSkeleton; + } + + constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, workspace: InnerWorkSpace) { + this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`); + this.resourceTypeInstance = resourceType.resourceTypeModel(this.context, {}); + this.init(); + if (this.resourceTypeInstance.editorViews) { + this.resourceTypeInstance.editorViews.forEach((d: any) => { + this.editorViewMap.set(d.viewName, d); + }); + } + if (!resourceType) { + logger.error(`resourceType[${resourceType}] is unValid.`); + } + } + async init() { await this.resourceTypeInstance.init?.(); await this.context.innerPlugins.init(); @@ -63,6 +67,7 @@ export class Resource implements IPublicModelResource { async import(schema: any) { return await this.resourceTypeInstance.import?.(schema); } + async save(value: any) { return await this.resourceTypeInstance.save?.(value); } diff --git a/packages/workspace/src/editor-view/view.tsx b/packages/workspace/src/view/editor-view.tsx similarity index 69% rename from packages/workspace/src/editor-view/view.tsx rename to packages/workspace/src/view/editor-view.tsx index 77f0dffeb..7ada5c911 100644 --- a/packages/workspace/src/editor-view/view.tsx +++ b/packages/workspace/src/view/editor-view.tsx @@ -4,9 +4,9 @@ import { Workbench, } from '@alilc/lowcode-editor-skeleton'; import { PureComponent } from 'react'; -import { Context } from './context'; +import { Context } from '../context/view-context'; -export * from '../base-context'; +export * from '../context/base-context'; @observer export class EditorView extends PureComponent<{ @@ -23,13 +23,11 @@ export class EditorView extends PureComponent<{ } return ( - <> - - + ); } } diff --git a/packages/workspace/src/view/resource-view.less b/packages/workspace/src/view/resource-view.less new file mode 100644 index 000000000..4c281f8d8 --- /dev/null +++ b/packages/workspace/src/view/resource-view.less @@ -0,0 +1,14 @@ +.workspace-resource-view { + display: flex; + position: absolute; + flex-direction: column; + top: 0; + bottom: 0; + left: 0; + right: 0; +} + +.workspace-editor-body { + position: relative; + height: 100%; +} \ No newline at end of file diff --git a/packages/workspace/src/view/resource-view.tsx b/packages/workspace/src/view/resource-view.tsx new file mode 100644 index 000000000..37e960b99 --- /dev/null +++ b/packages/workspace/src/view/resource-view.tsx @@ -0,0 +1,36 @@ +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 './resource-view.less'; + +@observer +export class ResourceView extends PureComponent<{ + window: EditorWindow; + resource: Resource; +}, any> { + render() { + const { skeleton } = this.props.resource; + const { editorViews } = this.props.window; + return ( +
+ +
+ { + Array.from(editorViews.values()).map((editorView: any) => { + return ( + + ); + }) + } +
+
+ ); + } +} \ No newline at end of file diff --git a/packages/workspace/src/editor-window/view.tsx b/packages/workspace/src/view/window-view.tsx similarity index 52% rename from packages/workspace/src/editor-window/view.tsx rename to packages/workspace/src/view/window-view.tsx index eb049aeed..396582a02 100644 --- a/packages/workspace/src/editor-window/view.tsx +++ b/packages/workspace/src/view/window-view.tsx @@ -1,17 +1,17 @@ import { PureComponent } from 'react'; -import { EditorView } from '../editor-view/view'; +import { ResourceView } from './resource-view'; import { engineConfig, observer } from '@alilc/lowcode-editor-core'; -import { EditorWindow } from './context'; +import { EditorWindow } from '../window'; import { BuiltinLoading } from '@alilc/lowcode-designer'; @observer -export class EditorWindowView extends PureComponent<{ - editorWindow: EditorWindow; +export class WindowView extends PureComponent<{ + window: EditorWindow; active: boolean; }, any> { render() { const { active } = this.props; - const { editorView, editorViews } = this.props.editorWindow; + const { editorView, resource } = this.props.window; if (!editorView) { const Loading = engineConfig.get('loadingComponent', BuiltinLoading); return ( @@ -23,17 +23,10 @@ export class EditorWindowView extends PureComponent<{ return (
- { - Array.from(editorViews.values()).map((editorView: any) => { - return ( - - ); - }) - } +
); } diff --git a/packages/workspace/src/editor-window/context.ts b/packages/workspace/src/window.ts similarity index 95% rename from packages/workspace/src/editor-window/context.ts rename to packages/workspace/src/window.ts index 680647587..73064c6b4 100644 --- a/packages/workspace/src/editor-window/context.ts +++ b/packages/workspace/src/window.ts @@ -1,8 +1,8 @@ import { uniqueId } from '@alilc/lowcode-utils'; import { makeObservable, obx } from '@alilc/lowcode-editor-core'; -import { Context } from '../editor-view/context'; -import { Workspace } from '../workspace'; -import { Resource } from '../resource'; +import { Context } from './context/view-context'; +import { Workspace } from './workspace'; +import { Resource } from './resource'; export class EditorWindow { id: string = uniqueId('window'); diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index c4462a71a..509ca9d9d 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -2,8 +2,8 @@ import { Designer } 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 { BasicContext } from './base-context'; -import { EditorWindow } from './editor-window/context'; +import { BasicContext } from './context/base-context'; +import { EditorWindow } from './window'; import { Resource } from './resource'; import { ResourceType } from './resource-type'; @@ -20,6 +20,12 @@ export class Workspace implements IPublicApiWorkspace { private emitter: IEventBus = createModuleEventBus('workspace'); + private _isActive = false; + + private resourceTypeMap: Map = new Map(); + + private resourceList: Resource[] = []; + get skeleton() { return this.context.innerSkeleton; } @@ -28,7 +34,17 @@ export class Workspace implements IPublicApiWorkspace { return this.context.innerPlugins; } - private _isActive = false; + get isActive() { + return this._isActive; + } + + get defaultResourceType(): ResourceType | null { + if (this.resourceTypeMap.size >= 1) { + return Array.from(this.resourceTypeMap.values())[0]; + } + + return null; + } windows: EditorWindow[] = []; @@ -36,10 +52,6 @@ export class Workspace implements IPublicApiWorkspace { @obx.ref window: EditorWindow; - private resourceTypeMap: Map = new Map(); - - private resourceList: Resource[] = []; - constructor( readonly registryInnerPlugin: (designer: Designer, editor: Editor, plugins: Plugins) => Promise, readonly shellModelFactory: any, @@ -66,10 +78,6 @@ export class Workspace implements IPublicApiWorkspace { this.emitChangeActiveWindow(); } - get isActive() { - return this._isActive; - } - setActive(value: boolean) { this._isActive = value; } @@ -105,14 +113,6 @@ export class Workspace implements IPublicApiWorkspace { return this.resourceTypeMap.get(resourceName)!; } - get defaultResourceType(): ResourceType | null { - if (this.resourceTypeMap.size >= 1) { - return Array.from(this.resourceTypeMap.values())[0]; - } - - return null; - } - removeResourceType(resourceName: string) { if (this.resourceTypeMap.has(resourceName)) { this.resourceTypeMap.delete(resourceName); @@ -153,13 +153,17 @@ export class Workspace implements IPublicApiWorkspace { console.error(`${name} is not available`); return; } - const filterWindows = this.windows.filter(d => (d.resource.name === name && d.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(); return; } - const resource = new Resource({}, resourceType, this); + const resource = new Resource({ + resourceName: name, + title, + options, + }, resourceType, this); this.window = new EditorWindow(resource, this, title, options); this.windows.push(this.window); this.editorWindowMap.set(this.window.id, this.window); From 5cf395957cd2079b103426967b4446813883f8ff Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 30 Jan 2023 11:13:40 +0800 Subject: [PATCH 28/89] feat: the advanced.autoruns parameter uses a shell wrapper --- packages/designer/src/document/node/node.ts | 3 ++- .../designer/src/document/node/props/props.ts | 2 ++ packages/types/src/shell/type/metadata.ts | 27 +++++++++++++++++-- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 1d294663b..7e0a7c530 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -27,6 +27,7 @@ import { ExclusiveGroup, isExclusiveGroup } 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; @@ -376,7 +377,7 @@ export class Node } this.autoruns = autoruns.map((item) => { return autorun(() => { - item.autorun(this.props.get(item.name, true) as any); + item.autorun(ShellProp.create(this.props.get(item.name, true))!); }); }); } diff --git a/packages/designer/src/document/node/props/props.ts b/packages/designer/src/document/node/props/props.ts index 56c1e7711..16c392bc4 100644 --- a/packages/designer/src/document/node/props/props.ts +++ b/packages/designer/src/document/node/props/props.ts @@ -44,6 +44,8 @@ export interface IProps extends Omit boolean; + /** * 嵌套控制 * 防止错误的节点嵌套,比如 a 嵌套 a, FormField 只能在 Form 容器下,Column 只能在 Table 下等 */ export interface IPublicTypeNestingRule { + /** * 子级白名单 */ childWhitelist?: string[] | string | RegExp | IPublicTypeNestingFilter; + /** * 父级白名单 */ parentWhitelist?: string[] | string | RegExp | IPublicTypeNestingFilter; + /** * 后裔白名单 */ descendantWhitelist?: string[] | string | RegExp | IPublicTypeNestingFilter; + /** * 后裔黑名单 */ descendantBlacklist?: string[] | string | RegExp | IPublicTypeNestingFilter; + /** * 祖先白名单 可用来做区域高亮 */ @@ -36,22 +42,27 @@ export interface IPublicTypeNestingRule { * 组件能力配置 */ export interface IPublicTypeComponentConfigure { + /** * 是否容器组件 */ isContainer?: boolean; + /** * 组件是否带浮层,浮层组件拖入设计器时会遮挡画布区域,此时应当辅助一些交互以防止阻挡 */ isModal?: boolean; + /** * 是否存在渲染的根节点 */ isNullNode?: boolean; + /** * 组件树描述信息 */ descriptor?: string; + /** * 嵌套控制:防止错误的节点嵌套 * 比如 a 嵌套 a, FormField 只能在 Form 容器下,Column 只能在 Table 下等 @@ -68,10 +79,12 @@ export interface IPublicTypeComponentConfigure { * 组件选中框的 cssSelector */ rootSelector?: string; + /** * 禁用的行为,可以为 `'copy'`, `'move'`, `'remove'` 或它们组成的数组 */ disableBehaviors?: string[] | string; + /** * 用于详细配置上述操作项的内容 */ @@ -88,7 +101,7 @@ export interface IPublicTypeFilterItem { } export interface IPublicTypeAutorunItem { name: string; - autorun: (target: IPublicModelSettingTarget) => any; + autorun: (prop: IPublicModelProp) => any; } // thinkof Array @@ -96,19 +109,23 @@ export interface IPublicTypeAutorunItem { * Live Text Editing(如果 children 内容是纯文本,支持双击直接编辑)的可配置项目 */ export interface IPublicTypeLiveTextEditingConfig { + /** * @todo 待补充文档 */ propTarget: string; + /** * @todo 待补充文档 */ selector?: string; + /** * 编辑模式 纯文本 | 段落编辑 | 文章编辑(默认纯文本,无跟随工具条) * @default 'plaintext' */ mode?: 'plaintext' | 'paragraph' | 'article'; + /** * 从 contentEditable 获取内容并设置到属性 */ @@ -125,27 +142,33 @@ export type ConfigureSupportEvent = string | { * 通用扩展面板支持性配置 */ export interface ConfigureSupport { + /** * 支持事件列表 */ events?: ConfigureSupportEvent[]; + /** * 支持 className 设置 */ className?: boolean; + /** * 支持样式设置 */ style?: boolean; + /** * 支持生命周期设置 */ lifecycles?: any[]; + // general?: boolean; /** * 支持循环设置 */ loop?: boolean; + /** * 支持条件式渲染设置 */ From 810ccbd03ef6ce5e4159c3e52aa7efad7073a67e Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 30 Jan 2023 14:40:17 +0800 Subject: [PATCH 29/89] feat: add get advanced api for ComponentMeta --- .../bem-tools/border-detecting.tsx | 2 +- .../bem-tools/border-resizing.tsx | 30 ++-- .../bem-tools/border-selecting.tsx | 2 +- .../builtin-simulator/bem-tools/insertion.tsx | 2 +- .../designer/src/builtin-simulator/host.ts | 168 +++++++++--------- packages/designer/src/component-meta.ts | 18 +- packages/designer/src/designer/designer.ts | 4 +- .../src/designer/drag-ghost/index.tsx | 2 +- .../src/document/node/node-children.ts | 2 +- packages/designer/src/document/node/node.ts | 8 +- .../tests/document/node/node.add.test.ts | 5 +- .../tests/document/node/node.modify.test.ts | 3 + .../tests/document/node/node.remove.test.ts | 3 + .../designer/tests/document/node/node.test.ts | 2 +- .../designer/tests/document/selection.test.ts | 3 + .../designer/tests/project/project.test.ts | 3 + .../src/controllers/pane-controller.ts | 140 +++++++-------- packages/shell/src/model/component-meta.ts | 6 +- .../types/src/shell/model/component-meta.ts | 8 +- .../types/src/shell/model/setting-target.ts | 2 +- packages/types/src/shell/type/advanced.ts | 100 ++++++----- packages/types/src/shell/type/configure.ts | 4 + packages/utils/src/node-helper.ts | 2 +- 23 files changed, 288 insertions(+), 231 deletions(-) diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx index f316e1c7a..49e68b77c 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx @@ -76,7 +76,7 @@ export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> { const { host } = this.props; const { current } = this; - const canHoverHook = current?.componentMeta.getMetadata()?.configure.advanced?.callbacks?.onHoverHook; + const canHoverHook = current?.componentMeta.advanced.callbacks?.onHoverHook; const canHover = (canHoverHook && typeof canHoverHook === 'function') ? canHoverHook(current.internalToShellNode()) : true; if (!canHover || !current || host.viewport.scrolling || host.liveEditing.editing) { 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 33dce7712..e174c4ad6 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx @@ -136,40 +136,40 @@ export class BoxResizingInstance extends Component<{ this.willBind(); const resize = (e: MouseEvent, direction: string, node: any, moveX: number, moveY: number) => { - const metadata = node.componentMeta.getMetadata(); + const { advanced } = node.componentMeta; if ( - metadata.configure?.advanced?.callbacks && - typeof metadata.configure.advanced.callbacks.onResize === 'function' + advanced.callbacks && + typeof advanced.callbacks.onResize === 'function' ) { (e as any).trigger = direction; (e as any).deltaX = moveX; (e as any).deltaY = moveY; const cbNode = node?.isNode ? node.internalToShellNode() : node; - metadata.configure.advanced.callbacks.onResize(e, cbNode); + advanced.callbacks.onResize(e, cbNode); } }; const resizeStart = (e: MouseEvent, direction: string, node: any) => { - const metadata = node.componentMeta.getMetadata(); + const { advanced } = node.componentMeta; if ( - metadata.configure?.advanced?.callbacks && - typeof metadata.configure.advanced.callbacks.onResizeStart === 'function' + advanced.callbacks && + typeof advanced.callbacks.onResizeStart === 'function' ) { (e as any).trigger = direction; const cbNode = node?.isNode ? node.internalToShellNode() : node; - metadata.configure.advanced.callbacks.onResizeStart(e, cbNode); + advanced.callbacks.onResizeStart(e, cbNode); } }; const resizeEnd = (e: MouseEvent, direction: string, node: any) => { - const metadata = node.componentMeta.getMetadata(); + const { advanced } = node.componentMeta; if ( - metadata.configure?.advanced?.callbacks && - typeof metadata.configure.advanced.callbacks.onResizeEnd === 'function' + advanced.callbacks && + typeof advanced.callbacks.onResizeEnd === 'function' ) { (e as any).trigger = direction; const cbNode = node?.isNode ? node.internalToShellNode() : node; - metadata.configure.advanced.callbacks.onResizeEnd(e, cbNode); + advanced.callbacks.onResizeEnd(e, cbNode); } const workspace = globalContext.get('workspace'); @@ -242,9 +242,9 @@ export class BoxResizingInstance extends Component<{ const { node, offsetWidth, offsetHeight, offsetTop, offsetLeft } = observed; let triggerVisible: any = []; - const metadata = node.componentMeta.getMetadata(); - if (metadata.configure?.advanced?.getResizingHandlers) { - triggerVisible = metadata.configure.advanced.getResizingHandlers(node.internalToShellNode()); + const { advanced } = node.componentMeta; + if (advanced.getResizingHandlers) { + triggerVisible = advanced.getResizingHandlers(node.internalToShellNode()); } triggerVisible = normalizeTriggers(triggerVisible); 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 0280d9055..da3c73ae5 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx @@ -46,7 +46,7 @@ export class BorderSelectingInstance extends Component<{ dragging, }); - const hideSelectTools = observed.node.componentMeta.getMetadata().configure.advanced?.hideSelectTools; + const { hideSelectTools } = observed.node.componentMeta.advanced; if (hideSelectTools) { return null; diff --git a/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx b/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx index e9955004b..98ac4266c 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/insertion.tsx @@ -121,7 +121,7 @@ export class InsertionView extends Component<{ host: BuiltinSimulatorHost }> { return null; } // 如果是个绝对定位容器,不需要渲染插入标记 - if (loc.target.componentMeta.getMetadata().configure.advanced?.isAbsoluteLayoutContainer) { + if (loc.target?.componentMeta?.advanced.isAbsoluteLayoutContainer) { return null; } diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 2171050c8..1eb228f29 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -99,6 +99,7 @@ export interface BuiltinSimulatorProps { simulatorUrl?: Asset; theme?: Asset; componentsAsset?: Asset; + // eslint-disable-next-line @typescript-eslint/member-ordering [key: string]: any; } @@ -184,40 +185,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost(() => this.componentsAsset); - this.injectionConsumer = new ResourceConsumer(() => { - return { - appHelper: engineConfig.get('appHelper'), - }; - }); - - this.i18nConsumer = new ResourceConsumer(() => this.project.i18n); - - transactionManager.onStartTransaction(() => { - this.stopAutoRepaintNode(); - }, IPublicEnumTransitionType.REPAINT); - // 防止批量调用 transaction 时,执行多次 rerender - const rerender = debounce(this.rerender.bind(this), 28); - transactionManager.onEndTransaction(() => { - rerender(); - this.enableAutoRepaintNode(); - }, IPublicEnumTransitionType.REPAINT); - } - get currentDocument() { return this.project.currentDocument; } @@ -285,6 +252,87 @@ export class BuiltinSimulatorHost implements ISimulatorHost void; + + private disableDetecting?: () => void; + + readonly liveEditing = new LiveEditing(); + + @obx private instancesMap: { + [docId: string]: Map; + } = {}; + + private tryScrollAgain: number | null = null; + + private _sensorAvailable = true; + + /** + * @see IPublicModelSensor + */ + get sensorAvailable(): boolean { + return this._sensorAvailable; + } + + private sensing = false; + + constructor(project: Project, designer: Designer) { + makeObservable(this); + this.project = project; + this.designer = designer; + this.scroller = this.designer.createScroller(this.viewport); + this.autoRender = !engineConfig.get('disableAutoRender', false); + this.componentsConsumer = new ResourceConsumer(() => this.componentsAsset); + this.injectionConsumer = new ResourceConsumer(() => { + return { + appHelper: engineConfig.get('appHelper'), + }; + }); + + this.i18nConsumer = new ResourceConsumer(() => this.project.i18n); + + transactionManager.onStartTransaction(() => { + this.stopAutoRepaintNode(); + }, IPublicEnumTransitionType.REPAINT); + // 防止批量调用 transaction 时,执行多次 rerender + const rerender = debounce(this.rerender.bind(this), 28); + transactionManager.onEndTransaction(() => { + rerender(); + this.enableAutoRepaintNode(); + }, IPublicEnumTransitionType.REPAINT); + } + + stopAutoRepaintNode() { + this.renderer?.stopAutoRepaintNode(); + } + + enableAutoRepaintNode() { + this.renderer?.enableAutoRepaintNode(); + } + /** * @see ISimulator */ @@ -337,30 +385,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost void; - - private disableDetecting?: () => void; - /** * 设置悬停处理 */ @@ -742,8 +762,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost; - } = {}; setInstance(docId: string, id: string, instances: IPublicTypeComponentInstance[] | null) { if (!hasOwnProperty(this.instancesMap, docId)) { this.instancesMap[docId] = new Map(); @@ -1045,8 +1060,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost { - const onMoveHook = node.componentMeta?.getMetadata()?.configure.advanced?.callbacks?.onMoveHook; + const onMoveHook = node.componentMeta?.advanced.callbacks?.onMoveHook; const canMove = onMoveHook && typeof onMoveHook === 'function' ? onMoveHook(node.internalToShellNode()) : true; let parentContainerNode: Node | null = null; @@ -1195,7 +1197,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost { @@ -234,7 +240,7 @@ export class ComponentMeta implements IComponentMeta { collectLiveTextEditing(this.configure); this._liveTextEditing = liveTextEditing.length > 0 ? liveTextEditing : undefined; - const isTopFixed = this._transformedMetadata.configure.advanced?.isTopFixed; + const isTopFixed = this.advanced.isTopFixed; if (isTopFixed) { this._isTopFixed = isTopFixed; diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 0e3559e0a..968b54ce5 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -567,7 +567,7 @@ export class Designer implements IDesigner { if (metaData.devMode === 'lowCode') { maps[key] = metaData.schema; } else { - const view = metaData.configure.advanced?.view; + const { view } = config.advanced; if (view) { maps[key] = view; } else { @@ -620,4 +620,4 @@ export class Designer implements IDesigner { purge() { // TODO: } -} \ No newline at end of file +} diff --git a/packages/designer/src/designer/drag-ghost/index.tsx b/packages/designer/src/designer/drag-ghost/index.tsx index 717472543..50fca2f28 100644 --- a/packages/designer/src/designer/drag-ghost/index.tsx +++ b/packages/designer/src/designer/drag-ghost/index.tsx @@ -39,7 +39,7 @@ export default class DragGhost extends Component<{ designer: Designer }> { this.y = e.globalY; if (isSimulatorHost(e.sensor)) { const container = e.sensor.getDropContainer(e); - if (container?.container.componentMeta.getMetadata().configure.advanced?.isAbsoluteLayoutContainer) { + if (container?.container.componentMeta.advanced.isAbsoluteLayoutContainer) { this.isAbsoluteLayoutContainer = true; return; } diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index bcdf897b3..d370a797b 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -502,7 +502,7 @@ export class NodeChildren implements INodeChildren { if (node.isRootNode) { return; } - const callbacks = owner.componentMeta?.getMetadata().configure.advanced?.callbacks; + const callbacks = owner.componentMeta?.advanced.callbacks; if (callbacks?.onSubtreeModified) { try { callbacks?.onSubtreeModified.call( diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 7e0a7c530..7baa5ad0a 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -371,7 +371,7 @@ export class Node } private setupAutoruns() { - const autoruns = this.componentMeta.getMetadata().configure.advanced?.autoruns; + const { autoruns } = this.componentMeta.advanced; if (!autoruns || autoruns.length < 1) { return; } @@ -385,7 +385,7 @@ export class Node private initialChildren(children: any): IPublicTypeNodeData[] { // FIXME! this is dirty code if (children == null) { - const initialChildren = this.componentMeta.getMetadata().configure.advanced?.initialChildren; + const { initialChildren } = this.componentMeta.advanced; if (initialChildren) { if (typeof initialChildren === 'function') { return initialChildren(this as any) || []; @@ -471,7 +471,7 @@ export class Node } private didDropIn(dragment: Node) { - const callbacks = this.componentMeta.getMetadata().configure.advanced?.callbacks; + const { callbacks } = this.componentMeta.advanced; if (callbacks?.onNodeAdd) { const cbThis = this.internalToShellNode(); callbacks?.onNodeAdd.call(cbThis, dragment.internalToShellNode(), cbThis); @@ -482,7 +482,7 @@ export class Node } private didDropOut(dragment: Node) { - const callbacks = this.componentMeta.getMetadata().configure.advanced?.callbacks; + const { callbacks } = this.componentMeta.advanced; if (callbacks?.onNodeRemove) { const cbThis = this.internalToShellNode(); callbacks?.onNodeRemove.call(cbThis, dragment.internalToShellNode(), cbThis); diff --git a/packages/designer/tests/document/node/node.add.test.ts b/packages/designer/tests/document/node/node.add.test.ts index 4f5655db9..bede02196 100644 --- a/packages/designer/tests/document/node/node.add.test.ts +++ b/packages/designer/tests/document/node/node.add.test.ts @@ -17,6 +17,9 @@ jest.mock('../../../src/designer/designer', () => { getMetadata() { return { configure: { advanced: null } }; }, + get advanced() { + return {}; + }, }; }, transformProps(props) { return props; }, @@ -506,7 +509,7 @@ describe('schema 生成节点模型测试', () => { }); }); - it('场景二:插入 Node 实例,指定 index', () => { + it.only('场景二:插入 Node 实例,指定 index', () => { expect(project).toBeTruthy(); const ids = getIdsFromSchema(formSchema); const { currentDocument } = project; diff --git a/packages/designer/tests/document/node/node.modify.test.ts b/packages/designer/tests/document/node/node.modify.test.ts index 7aa055ae1..f7bd7dd5e 100644 --- a/packages/designer/tests/document/node/node.modify.test.ts +++ b/packages/designer/tests/document/node/node.modify.test.ts @@ -14,6 +14,9 @@ jest.mock('../../../src/designer/designer', () => { getMetadata() { return { configure: { advanced: null } }; }, + get advanced() { + return {}; + }, }; }, transformProps(props) { return props; }, diff --git a/packages/designer/tests/document/node/node.remove.test.ts b/packages/designer/tests/document/node/node.remove.test.ts index 28bdf914f..82d180443 100644 --- a/packages/designer/tests/document/node/node.remove.test.ts +++ b/packages/designer/tests/document/node/node.remove.test.ts @@ -16,6 +16,9 @@ jest.mock('../../../src/designer/designer', () => { getMetadata() { return { configure: { advanced: null } }; }, + get advanced() { + return {}; + }, }; }, transformProps(props) { return props; }, diff --git a/packages/designer/tests/document/node/node.test.ts b/packages/designer/tests/document/node/node.test.ts index f7d35f6d6..e0be159ff 100644 --- a/packages/designer/tests/document/node/node.test.ts +++ b/packages/designer/tests/document/node/node.test.ts @@ -473,7 +473,7 @@ describe('Node 方法测试', () => { const form = doc.getNode('node_k1ow3cbo'); designer.createComponentMeta(divMetadata); designer.createComponentMeta(formMetadata); - const callbacks = form.componentMeta.getMetadata().configure.advanced?.callbacks; + const callbacks = form.componentMeta.advanced.callbacks; const fn1 = callbacks.onNodeAdd = jest.fn(); const fn2 = callbacks.onNodeRemove = jest.fn(); const textField = doc.getNode('node_k1ow3cc9'); diff --git a/packages/designer/tests/document/selection.test.ts b/packages/designer/tests/document/selection.test.ts index 30032ac7a..b8b5ad434 100644 --- a/packages/designer/tests/document/selection.test.ts +++ b/packages/designer/tests/document/selection.test.ts @@ -17,6 +17,9 @@ jest.mock('../../src/designer/designer', () => { getMetadata() { return { configure: { advanced: null } }; }, + get advanced() { + return {}; + }, }; }, transformProps(props) { return props; }, diff --git a/packages/designer/tests/project/project.test.ts b/packages/designer/tests/project/project.test.ts index 6e4aeb8c0..2066c0398 100644 --- a/packages/designer/tests/project/project.test.ts +++ b/packages/designer/tests/project/project.test.ts @@ -17,6 +17,9 @@ jest.mock('../../src/designer/designer', () => { getMetadata() { return { configure: { advanced: null } }; }, + get advanced() { + return {}; + }, }; }, transformProps(props) { return props; }, diff --git a/packages/plugin-outline-pane/src/controllers/pane-controller.ts b/packages/plugin-outline-pane/src/controllers/pane-controller.ts index be3b6b9ce..0d565c15f 100644 --- a/packages/plugin-outline-pane/src/controllers/pane-controller.ts +++ b/packages/plugin-outline-pane/src/controllers/pane-controller.ts @@ -31,6 +31,75 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicMo readonly id = uniqueId('outline'); + private indentTrack = new IndentTrack(); + + private _sensorAvailable = false; + + /** + * @see IPublicModelSensor + */ + get sensorAvailable() { + return this._sensorAvailable; + } + + private dwell = new DwellTimer((target, event) => { + const { canvas, project } = this.pluginContext; + const document = project.getCurrentDocument(); + let index: any; + let focus: any; + let valid = true; + if (target.hasSlots()) { + index = null; + focus = { type: 'slots' }; + } else { + index = 0; + valid = !!document?.checkNesting(target, event.dragObject as any); + } + canvas.createLocation({ + target, + source: this.id, + event, + detail: { + type: IPublicTypeLocationDetailType.Children, + index, + focus, + valid, + }, + }); + }); + + /** + * @see ITreeBoard + */ + readonly at: string | symbol; + + private tryScrollAgain: number | null = null; + + private sensing = false; + + /** + * @see IScrollable + */ + get bounds(): DOMRect | null { + if (!this._shell) { + return null; + } + return this._shell.getBoundingClientRect(); + } + + private _scrollTarget?: IPublicModelScrollTarget; + + /** + * @see IScrollable + */ + get scrollTarget() { + return this._scrollTarget; + } + + private scroller?: IPublicModelScroller; + + private _shell: HTMLDivElement | null = null; + constructor(at: string | symbol, pluginContext: IPublicModelPluginContext, treeMaster: TreeMaster) { this.pluginContext = pluginContext; this.treeMaster = treeMaster; @@ -52,8 +121,6 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicMo /** -------------------- IPublicModelSensor begin -------------------- */ - private indentTrack = new IndentTrack(); - /** * @see IPublicModelSensor */ @@ -91,7 +158,7 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicMo } const operationalNodes = nodes?.filter((node: any) => { - const onMoveHook = node.componentMeta?.getMetadata().configure?.advanced?.callbacks?.onMoveHook; + const onMoveHook = node.componentMeta?.advanced.callbacks?.onMoveHook; const canMove = onMoveHook && typeof onMoveHook === 'function' ? onMoveHook(node) : true; return canMove; @@ -233,24 +300,10 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicMo this.indentTrack.reset(); } - private _sensorAvailable = false; - - /** - * @see IPublicModelSensor - */ - get sensorAvailable() { - return this._sensorAvailable; - } - /** -------------------- IPublicModelSensor end -------------------- */ /** -------------------- ITreeBoard begin -------------------- */ - /** - * @see ITreeBoard - */ - readonly at: string | symbol; - /** * @see ITreeBoard */ @@ -295,32 +348,6 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicMo /** -------------------- ITreeBoard end -------------------- */ - private dwell = new DwellTimer((target, event) => { - const { canvas, project } = this.pluginContext; - const document = project.getCurrentDocument(); - let index: any; - let focus: any; - let valid = true; - if (target.hasSlots()) { - index = null; - focus = { type: 'slots' }; - } else { - index = 0; - valid = !!document?.checkNesting(target, event.dragObject as any); - } - canvas.createLocation({ - target, - source: this.id, - event, - detail: { - type: IPublicTypeLocationDetailType.Children, - index, - focus, - valid, - }, - }); - }); - private getNear(treeNode: TreeNode, e: IPublicModelLocateEvent, originalIndex?: number, originalRect?: DOMRect) { const { canvas, project } = this.pluginContext; const document = project.getCurrentDocument(); @@ -541,39 +568,12 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicMo return canvas.createLocation(locationData); } - private tryScrollAgain: number | null = null; - - private sensing = false; - - /** - * @see IScrollable - */ - get bounds(): DOMRect | null { - if (!this._shell) { - return null; - } - return this._shell.getBoundingClientRect(); - } - - private _scrollTarget?: IPublicModelScrollTarget; - - /** - * @see IScrollable - */ - get scrollTarget() { - return this._scrollTarget; - } - - private scroller?: IPublicModelScroller; - purge() { const { canvas } = this.pluginContext; canvas.dragon?.removeSensor(this); this.treeMaster?.removeBoard(this); } - private _shell: HTMLDivElement | null = null; - mount(shell: HTMLDivElement | null) { if (this._shell === shell) { return; diff --git a/packages/shell/src/model/component-meta.ts b/packages/shell/src/model/component-meta.ts index 67cb2895d..c913c2c0f 100644 --- a/packages/shell/src/model/component-meta.ts +++ b/packages/shell/src/model/component-meta.ts @@ -2,7 +2,7 @@ import { IComponentMeta as InnerComponentMeta, INode, } from '@alilc/lowcode-designer'; -import { IPublicTypeNodeData, IPublicTypeNodeSchema, IPublicModelComponentMeta, IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeNpmInfo, IPublicTypeTransformedComponentMetadata, IPublicModelNode } from '@alilc/lowcode-types'; +import { IPublicTypeNodeData, IPublicTypeNodeSchema, IPublicModelComponentMeta, IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeNpmInfo, IPublicTypeTransformedComponentMetadata, IPublicModelNode, IPublicTypeAdvanced } from '@alilc/lowcode-types'; import { componentMetaSymbol, nodeSymbol } from '../symbols'; import { ReactElement } from 'react'; @@ -92,6 +92,10 @@ export class ComponentMeta implements IPublicModelComponentMeta { return this[componentMetaSymbol].availableActions; } + get advanced(): IPublicTypeAdvanced { + return this[componentMetaSymbol].advanced; + } + /** * 设置 npm 信息 * @param npm diff --git a/packages/types/src/shell/model/component-meta.ts b/packages/types/src/shell/model/component-meta.ts index 160c7107d..7a5f3fa8c 100644 --- a/packages/types/src/shell/model/component-meta.ts +++ b/packages/types/src/shell/model/component-meta.ts @@ -1,4 +1,4 @@ -import { IPublicTypeNodeSchema, IPublicTypeNodeData, IPublicTypeIconType, IPublicTypeTransformedComponentMetadata, IPublicTypeI18nData, IPublicTypeNpmInfo } from '../type'; +import { IPublicTypeNodeSchema, IPublicTypeNodeData, IPublicTypeIconType, IPublicTypeTransformedComponentMetadata, IPublicTypeI18nData, IPublicTypeNpmInfo, IPublicTypeAdvanced } from '../type'; import { ReactElement } from 'react'; import { IPublicModelNode } from './node'; @@ -49,6 +49,12 @@ export interface IPublicModelComponentMeta { get availableActions(): any; + /** + * configure.advanced + * @since v1.1.0 + */ + get advanced(): IPublicTypeAdvanced; + /** * 设置 npm 信息 * @param npm diff --git a/packages/types/src/shell/model/setting-target.ts b/packages/types/src/shell/model/setting-target.ts index f8b1df0b9..e41cf6ea6 100644 --- a/packages/types/src/shell/model/setting-target.ts +++ b/packages/types/src/shell/model/setting-target.ts @@ -2,6 +2,7 @@ import { IPublicApiSetters } from '../api'; import { IPublicModelEditor } from './'; export interface IPublicModelSettingTarget { + /** * 同样类型的节点 */ @@ -39,7 +40,6 @@ export interface IPublicModelSettingTarget { */ readonly parent: IPublicModelSettingTarget; - /** * 获取当前值 */ diff --git a/packages/types/src/shell/type/advanced.ts b/packages/types/src/shell/type/advanced.ts index 7a3474034..f4c750535 100644 --- a/packages/types/src/shell/type/advanced.ts +++ b/packages/types/src/shell/type/advanced.ts @@ -5,58 +5,24 @@ import { IPublicModelSettingTarget } from '../model'; /** * 高级特性配置 */ - export interface IPublicTypeAdvanced { - /** - * @todo 待补充文档 - */ - context?: { [contextInfoName: string]: any }; - /** - * @deprecated 使用组件 metadata 上的 snippets 字段即可 - */ - snippets?: IPublicTypeSnippet[]; - /** - * @todo 待补充文档 - */ - view?: ComponentType; - /** - * @todo 待补充文档 - */ - transducers?: any; - /** - * @deprecated 用于动态初始化拖拽到设计器里的组件的 prop 的值 - */ - initials?: IPublicTypeInitialItem[]; - /** - * @todo 待补充文档 - */ - filters?: IPublicTypeFilterItem[]; - /** - * @todo 待补充文档 - */ - autoruns?: IPublicTypeAutorunItem[]; + /** * 配置 callbacks 可捕获引擎抛出的一些事件,例如 onNodeAdd、onResize 等 + * callbacks/hooks which can be used to do + * things on some special ocations like onNodeAdd or onResize */ callbacks?: IPublicTypeCallbacks; + /** * 拖入容器时,自动带入 children 列表 */ initialChildren?: IPublicTypeNodeData[] | ((target: IPublicModelSettingTarget) => IPublicTypeNodeData[]); - /** - * @todo 待补充文档 - */ - isAbsoluteLayoutContainer?: boolean; - /** - * @todo 待补充文档 - */ - hideSelectTools?: boolean; /** * 样式 及 位置,handle 上必须有明确的标识以便事件路由判断,或者主动设置事件独占模式 * NWSE 是交给引擎计算放置位置,ReactElement 必须自己控制初始位置 - */ - /** + * * 用于配置设计器中组件 resize 操作工具的样式和内容 * - hover 时控制柄高亮 * - mousedown 时请求独占 @@ -73,13 +39,67 @@ export interface IPublicTypeAdvanced { }> | ReactElement[]); + /** + * @deprecated 用于动态初始化拖拽到设计器里的组件的 prop 的值 + */ + initials?: IPublicTypeInitialItem[]; + + /** + * @deprecated 使用组件 metadata 上的 snippets 字段即可 + */ + snippets?: IPublicTypeSnippet[]; + + /** + * 是否绝对布局容器,还未进入协议 + * @experimental not in spec yet + */ + isAbsoluteLayoutContainer?: boolean; + + /** + * hide bem tools when selected + * @experimental not in spec yet + */ + hideSelectTools?: boolean; + /** * Live Text Editing:如果 children 内容是纯文本,支持双击直接编辑 + * @experimental not in spec yet */ liveTextEditing?: IPublicTypeLiveTextEditingConfig[]; /** - * @deprecated 暂未使用 + * TODO: 补充文档 + * @experimental not in spec yet + */ + view?: ComponentType; + + /** + * @legacy capability for vision + * @deprecated */ isTopFixed?: boolean; + + /** + * TODO: 补充文档 或 删除 + * @deprecated not used anywhere, dont know what is it for + */ + context?: { [contextInfoName: string]: any }; + + /** + * @legacy capability for vision + * @deprecated + */ + filters?: IPublicTypeFilterItem[]; + + /** + * @legacy capability for vision + * @deprecated + */ + autoruns?: IPublicTypeAutorunItem[]; + + /** + * @legacy capability for vision + * @deprecated + */ + transducers?: any; } diff --git a/packages/types/src/shell/type/configure.ts b/packages/types/src/shell/type/configure.ts index 34f5a7fb2..44fd1ffe6 100644 --- a/packages/types/src/shell/type/configure.ts +++ b/packages/types/src/shell/type/configure.ts @@ -4,18 +4,22 @@ import { IPublicTypeComponentConfigure, ConfigureSupport, IPublicTypeFieldConfig * 编辑体验配置 */ export interface IPublicTypeConfigure { + /** * 属性面板配置 */ props?: IPublicTypeFieldConfig[]; + /** * 组件能力配置 */ component?: IPublicTypeComponentConfigure; + /** * 通用扩展面板支持性配置 */ supports?: ConfigureSupport; + /** * 高级特性配置 */ diff --git a/packages/utils/src/node-helper.ts b/packages/utils/src/node-helper.ts index 9d6573cdc..1293cec2e 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?.getMetadata().configure?.advanced?.callbacks?.onClickHook; + const onClickHook = node.componentMeta?.advanced.callbacks?.onClickHook; const canClick = typeof onClickHook === 'function' ? onClickHook(e as MouseEvent, node) : true; return canClick; }; From a42f538b06da5cdbbf3ed1fbe8d8992829f1c404 Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 1 Feb 2023 14:31:37 +0800 Subject: [PATCH 30/89] fix: fix the problem caused by the default metadataTransducer registration timing being too late --- 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 b4302f86b..05033873a 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -66,7 +66,7 @@ async function registryInnerPlugin(designer: Designer, editor: Editor, plugins: await plugins.register(setterRegistry, {}, { autoInit: true }); await plugins.register(defaultPanelRegistry(editor)); await plugins.register(builtinHotkey); - await plugins.register(registerDefaults); + await plugins.register(registerDefaults, {}, { autoInit: true }); } const innerWorkspace = new InnerWorkspace(registryInnerPlugin, shellModelFactory); From 0e18feeb6e551010eff1d07bbd557971e3086970 Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 1 Feb 2023 21:41:57 +0800 Subject: [PATCH 31/89] feat: added export of propSymbol and prop classes --- packages/engine/src/modules/classes.ts | 2 ++ packages/engine/src/modules/symbols.ts | 2 ++ packages/shell/src/api/material.ts | 16 +++++++++++----- packages/types/src/shell/api/material.ts | 2 +- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/engine/src/modules/classes.ts b/packages/engine/src/modules/classes.ts index 11d1e7089..9547eba7a 100644 --- a/packages/engine/src/modules/classes.ts +++ b/packages/engine/src/modules/classes.ts @@ -8,6 +8,7 @@ import { SettingPropEntry, SettingTopEntry, Selection, + Prop, } from '@alilc/lowcode-shell'; import { Node as InnerNode } from '@alilc/lowcode-designer'; @@ -22,4 +23,5 @@ export default { SettingTopEntry, InnerNode, Selection, + Prop, }; diff --git a/packages/engine/src/modules/symbols.ts b/packages/engine/src/modules/symbols.ts index a022b848a..7f72f53e0 100644 --- a/packages/engine/src/modules/symbols.ts +++ b/packages/engine/src/modules/symbols.ts @@ -9,6 +9,7 @@ import { settingPropEntrySymbol, settingTopEntrySymbol, designerCabinSymbol, + propSymbol, } from '@alilc/lowcode-shell'; export default { @@ -22,4 +23,5 @@ export default { settingPropEntrySymbol, settingTopEntrySymbol, designerCabinSymbol, + propSymbol, }; diff --git a/packages/shell/src/api/material.ts b/packages/shell/src/api/material.ts index eca386c5a..cfc84620f 100644 --- a/packages/shell/src/api/material.ts +++ b/packages/shell/src/api/material.ts @@ -170,10 +170,16 @@ export class Material implements IPublicApiMaterial { * 监听 assets 变化的事件 * @param fn */ - onChangeAssets(fn: () => void) { - // 设置 assets,经过 setAssets 赋值 - this[editorSymbol].onGot('assets', fn); - // 增量设置 assets,经过 loadIncrementalAssets 赋值 - this[editorSymbol].eventBus.on('designer.incrementalAssetsReady', fn); + onChangeAssets(fn: () => void): Function { + const dispose = [ + // 设置 assets,经过 setAssets 赋值 + this[editorSymbol].onGot('assets', fn), + // 增量设置 assets,经过 loadIncrementalAssets 赋值 + this[editorSymbol].eventBus.on('designer.incrementalAssetsReady', fn), + ]; + + return () => { + dispose.forEach(d => d && d()); + }; } } diff --git a/packages/types/src/shell/api/material.ts b/packages/types/src/shell/api/material.ts index deec23d52..c8834816b 100644 --- a/packages/types/src/shell/api/material.ts +++ b/packages/types/src/shell/api/material.ts @@ -104,5 +104,5 @@ export interface IPublicApiMaterial { * add callback for assets changed event * @param fn */ - onChangeAssets(fn: () => void): void; + onChangeAssets(fn: () => void): Function; } From 672e4a5f4c47415ac9436aa5b1682c4d521bfec2 Mon Sep 17 00:00:00 2001 From: Frank Zhao Date: Fri, 3 Feb 2023 11:37:23 +0800 Subject: [PATCH 32/89] Update README.md Add contribution leaderboard badge to README --- packages/engine/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/engine/README.md b/packages/engine/README.md index 8b11e5a1a..31b0606dd 100644 --- a/packages/engine/README.md +++ b/packages/engine/README.md @@ -16,6 +16,8 @@ An enterprise-class low-code technology stack with scale-out design [![codecov][codecov-image-url]][codecov-url] +[![](https://img.shields.io/badge/Lowcode%20Engine-Check%20Your%20Contribution-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 [npm-url]: http://npmjs.org/package/@alilc/lowcode-engine @@ -166,4 +168,4 @@ Special thanks to everyone who contributed to this project.

-

\ No newline at end of file +

From 8e3f31f7019eb0f6152853a00b62f6746cd9213b Mon Sep 17 00:00:00 2001 From: Frank Zhao Date: Fri, 3 Feb 2023 11:43:18 +0800 Subject: [PATCH 33/89] Update README-zh_CN.md Add contribution leaderboard badge to readme --- packages/engine/README-zh_CN.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/engine/README-zh_CN.md b/packages/engine/README-zh_CN.md index 000a711f5..d25662bf4 100644 --- a/packages/engine/README-zh_CN.md +++ b/packages/engine/README-zh_CN.md @@ -15,6 +15,8 @@ [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url] [![codecov][codecov-image-url]][codecov-url] + +[![](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 [npm-url]: http://npmjs.org/package/@alilc/lowcode-engine @@ -166,4 +168,4 @@ lowcode-engine 启动后,提供了几个 umd 文件,可以结合 [lowcode-de

-

\ No newline at end of file +

From f4868b81c83360b7b35e42a6f4c9bb73227269a3 Mon Sep 17 00:00:00 2001 From: Frank Zhao Date: Fri, 3 Feb 2023 11:43:49 +0800 Subject: [PATCH 34/89] Update README.md Update badge label --- packages/engine/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/README.md b/packages/engine/README.md index 31b0606dd..7b06f2cb2 100644 --- a/packages/engine/README.md +++ b/packages/engine/README.md @@ -16,7 +16,7 @@ An enterprise-class low-code technology stack with scale-out design [![codecov][codecov-image-url]][codecov-url] -[![](https://img.shields.io/badge/Lowcode%20Engine-Check%20Your%20Contribution-orange)](https://opensource.alibaba.com/contribution_leaderboard/details?projectValue=lowcode-engine) +[![](https://img.shields.io/badge/LowCodeEngine-Check%20Your%20Contribution-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 [npm-url]: http://npmjs.org/package/@alilc/lowcode-engine From dbffb30b993a740535a261d9ed9f22faa5517b64 Mon Sep 17 00:00:00 2001 From: Frank Zhao Date: Fri, 3 Feb 2023 11:37:23 +0800 Subject: [PATCH 35/89] Update README.md Add contribution leaderboard badge to README --- packages/engine/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/engine/README.md b/packages/engine/README.md index 8ce675923..206b65d6d 100644 --- a/packages/engine/README.md +++ b/packages/engine/README.md @@ -16,6 +16,8 @@ An enterprise-class low-code technology stack with scale-out design [![codecov][codecov-image-url]][codecov-url] +[![](https://img.shields.io/badge/Lowcode%20Engine-Check%20Your%20Contribution-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 [npm-url]: http://npmjs.org/package/@alilc/lowcode-engine @@ -173,4 +175,4 @@ Special thanks to everyone who contributed to this project.

-

\ No newline at end of file +

From 3019a47f24ff113292c123c11ab1afe933bfc953 Mon Sep 17 00:00:00 2001 From: Frank Zhao Date: Fri, 3 Feb 2023 11:43:18 +0800 Subject: [PATCH 36/89] Update README-zh_CN.md Add contribution leaderboard badge to readme --- packages/engine/README-zh_CN.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/engine/README-zh_CN.md b/packages/engine/README-zh_CN.md index 793ee050b..276123391 100644 --- a/packages/engine/README-zh_CN.md +++ b/packages/engine/README-zh_CN.md @@ -15,6 +15,8 @@ [![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url] [![codecov][codecov-image-url]][codecov-url] + +[![](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 [npm-url]: http://npmjs.org/package/@alilc/lowcode-engine @@ -173,4 +175,4 @@ lowcode-engine 启动后,提供了几个 umd 文件,可以结合 [lowcode-de

-

\ No newline at end of file +

From b754e61bf8f7e798de70ed4c2ea0fdbac9ee65be Mon Sep 17 00:00:00 2001 From: Frank Zhao Date: Fri, 3 Feb 2023 11:43:49 +0800 Subject: [PATCH 37/89] Update README.md Update badge label --- packages/engine/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/README.md b/packages/engine/README.md index 206b65d6d..4f0543c7a 100644 --- a/packages/engine/README.md +++ b/packages/engine/README.md @@ -16,7 +16,7 @@ An enterprise-class low-code technology stack with scale-out design [![codecov][codecov-image-url]][codecov-url] -[![](https://img.shields.io/badge/Lowcode%20Engine-Check%20Your%20Contribution-orange)](https://opensource.alibaba.com/contribution_leaderboard/details?projectValue=lowcode-engine) +[![](https://img.shields.io/badge/LowCodeEngine-Check%20Your%20Contribution-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 [npm-url]: http://npmjs.org/package/@alilc/lowcode-engine From 83562989d57f2eba29d4d5b34e35216e7dbf0941 Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 6 Feb 2023 16:00:11 +0800 Subject: [PATCH 38/89] docs: add doc for api/model/component-meta --- docs/docs/api/canvas.md | 4 +- docs/docs/api/model/component-meta.md | 173 ++++++++++++++++++ docs/docs/api/model/resource.md | 4 +- packages/designer/src/component-meta.ts | 9 +- packages/designer/src/designer/designer.ts | 6 +- packages/designer/src/designer/scroller.ts | 22 +-- packages/designer/src/simulator.ts | 4 +- .../src/controllers/pane-controller.ts | 4 +- packages/shell/src/api/canvas.ts | 6 +- packages/shell/src/model/component-meta.ts | 4 +- packages/types/src/shell/api/canvas.ts | 6 +- .../types/src/shell/model/component-meta.ts | 45 +++-- packages/types/src/shell/model/dragon.ts | 2 +- .../types/src/shell/model/engine-config.ts | 2 +- packages/types/src/shell/model/index.ts | 3 +- .../types/src/shell/model/node-children.ts | 1 + packages/types/src/shell/model/preference.ts | 1 + .../src/shell/model/setting-prop-entry.ts | 2 +- .../src/shell/model/setting-top-entry.ts | 1 + .../types/src/shell/type/component-action.ts | 5 + packages/types/src/shell/type/field-config.ts | 8 + packages/types/src/shell/type/index.ts | 3 +- .../src/shell/{model => type}/scrollable.ts | 6 +- 23 files changed, 268 insertions(+), 53 deletions(-) create mode 100644 docs/docs/api/model/component-meta.md rename packages/types/src/shell/{model => type}/scrollable.ts (50%) diff --git a/docs/docs/api/canvas.md b/docs/docs/api/canvas.md index c16ba62c5..582f2354b 100644 --- a/docs/docs/api/canvas.md +++ b/docs/docs/api/canvas.md @@ -62,7 +62,7 @@ createLocation(locationData: IPublicTypeLocationData): IPublicModelDropLocation; ```typescript /** * 创建一个滚动控制器 Scroller,赋予一个视图滚动的基本能力, - * a Scroller is a controller that gives a view (IPublicModelScrollable) the ability scrolling + * a Scroller is a controller that gives a view (IPublicTypeScrollable) the ability scrolling * to some cordination by api scrollTo. * * when a scroller is inited, will need to pass is a scrollable, which has a scrollTarget. @@ -70,7 +70,7 @@ createLocation(locationData: IPublicTypeLocationData): IPublicModelDropLocation; * move scrollTarget`s top-left corner to (options.left, options.top) that passed in. * @since v1.1.0 */ -createScroller(scrollable: IPublicModelScrollable): IPublicModelScroller; +createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller; ``` diff --git a/docs/docs/api/model/component-meta.md b/docs/docs/api/model/component-meta.md new file mode 100644 index 000000000..28f7fe740 --- /dev/null +++ b/docs/docs/api/model/component-meta.md @@ -0,0 +1,173 @@ +--- +title: ComponentMeta +sidebar_position: 15 +--- + +> **@types** [IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)
+> **@since** v1.0.0 + +## 基本介绍 + +组件元数据信息模型 + +## 属性 + +### componentName + +组件名 + +`@type {string}` + +### isContainer + +是否是「容器型」组件 + +`@type {boolean}` + +### isMinimalRenderUnit +是否是最小渲染单元 + +当组件需要重新渲染时: +- 若为最小渲染单元,则只渲染当前组件, +- 若不为最小渲染单元,则寻找到上层最近的最小渲染单元进行重新渲染,直至根节点。 + +`@type {boolean}` + +### isModal + +是否为「模态框」组件 + +`@type {boolean}` + +### configure + +获取用于设置面板显示用的配置 + +`@type {IPublicTypeFieldConfig[]}` + +相关类型:[IPublicTypeFieldConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/field-config.ts) + +### title + +标题 + +`@type {string | IPublicTypeI18nData | ReactElement}` + +相关类型:[IPublicTypeI18nData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/i18n-data.ts) + +### icon + +图标 + +`@type {IPublicTypeIconType}` + +相关类型:[IPublicTypeIconType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/icon-type.ts) + +### npm + +组件 npm 信息 + +`@type {IPublicTypeNpmInfo}` + +相关类型:[IPublicTypeNpmInfo](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/npm-info.ts) + +### availableActions + +获取元数据 + +`@type {IPublicTypeTransformedComponentMetadata}` + +相关类型:[IPublicTypeTransformedComponentMetadata](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/transformed-component-metadata.ts) + +### advanced + +组件元数据中高级配置部分 + +`@type {IPublicTypeAdvanced}` + +相关类型:[IPublicTypeAdvanced](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/advanced.ts) + +## 方法 + +### setNpm + +设置 npm 信息 + +```typescript +/** + * 设置 npm 信息 + * set method for npm inforamtion + * @param npm + */ +setNpm(npm: IPublicTypeNpmInfo): void; +``` + +相关类型:[IPublicTypeNpmInfo](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/npm-info.ts) + +### getMetadata + +获取元数据 + +```typescript +/** + * 获取元数据 + * get component metadata + */ +getMetadata(): IPublicTypeTransformedComponentMetadata; +``` + +相关类型:[IPublicTypeTransformedComponentMetadata](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/transformed-component-metadata.ts) + +### checkNestingUp + +检测当前对应节点是否可被放置在父节点中 + +```typescript +/** + * 检测当前对应节点是否可被放置在父节点中 + * check if the current node could be placed in parent node + * @param my 当前节点 + * @param parent 父节点 + */ +checkNestingUp(my: IPublicModelNode | IPublicTypeNodeData, parent: any): boolean; +``` + +相关类型: +- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) +- [IPublicTypeNodeData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-data.ts) + + +### checkNestingDown + +检测目标节点是否可被放置在父节点中 + +```typescript +/** + * 检测目标节点是否可被放置在父节点中 + * check if the target node(s) could be placed in current node + * @param my 当前节点 + * @param parent 父节点 + */ +checkNestingDown( + my: IPublicModelNode | IPublicTypeNodeData, + target: IPublicTypeNodeSchema | IPublicModelNode | IPublicTypeNodeSchema[], + ): boolean; +``` + +相关类型: +- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) +- [IPublicTypeNodeData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-data.ts) +- [IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts) + + +### refreshMetadata + +刷新元数据,会触发元数据的重新解析和刷新 + +```typescript +/** + * 刷新元数据,会触发元数据的重新解析和刷新 + * refresh metadata + */ +refreshMetadata(): void; +``` diff --git a/docs/docs/api/model/resource.md b/docs/docs/api/model/resource.md index 74f8d8f71..397723454 100644 --- a/docs/docs/api/model/resource.md +++ b/docs/docs/api/model/resource.md @@ -4,7 +4,7 @@ sidebar_position: 13 --- > **[@experimental](./#experimental)**
-> **@types** [IPublicModelWindow](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/resource.ts)
+> **@types** [IPublicModelResource](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/resource.ts)
> **@since** v1.1.0 ## 属性 @@ -43,4 +43,4 @@ sidebar_position: 13 资源配置信息 -`@type {Object}` \ No newline at end of file +`@type {Object}` diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 4ca5a24dc..c361b21c9 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -110,7 +110,7 @@ export class ComponentMeta implements IComponentMeta { private _transformedMetadata?: IPublicTypeTransformedComponentMetadata; - get configure() { + get configure(): IPublicTypeFieldConfig[] { const config = this._transformedMetadata?.configure; return config?.combined || config?.props || []; } @@ -272,8 +272,11 @@ export class ComponentMeta implements IComponentMeta { this.parseMetadata(this.getMetadata()); } - private transformMetadata(metadta: IPublicTypeComponentMetadata): IPublicTypeTransformedComponentMetadata { - const result = this.designer.componentActions.getRegisteredMetadataTransducers().reduce((prevMetadata, current) => { + private transformMetadata( + metadta: IPublicTypeComponentMetadata, + ): IPublicTypeTransformedComponentMetadata { + const registeredTransducers = this.designer.componentActions.getRegisteredMetadataTransducers(); + const result = registeredTransducers.reduce((prevMetadata, current) => { return current(prevMetadata); }, preprocessMetadata(metadta)); diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 968b54ce5..c39e439aa 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -12,7 +12,7 @@ import { IPublicTypePropsTransducer, IShellModelFactory, IPublicModelDragObject, - IPublicModelScrollable, + IPublicTypeScrollable, IPublicModelScroller, IPublicTypeLocationData, IPublicEnumTransformStage, @@ -70,7 +70,7 @@ export interface IDesigner { get editor(): IPublicModelEditor; - createScroller(scrollable: IPublicModelScrollable): IPublicModelScroller; + createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller; /** * 创建插入位置,考虑放到 dragon 中 @@ -302,7 +302,7 @@ export class Designer implements IDesigner { this._dropLocation = undefined; } - createScroller(scrollable: IPublicModelScrollable): IPublicModelScroller { + createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller { return new Scroller(scrollable); } diff --git a/packages/designer/src/designer/scroller.ts b/packages/designer/src/designer/scroller.ts index b4dc7467e..67efe7f44 100644 --- a/packages/designer/src/designer/scroller.ts +++ b/packages/designer/src/designer/scroller.ts @@ -1,5 +1,5 @@ import { isElement } from '@alilc/lowcode-utils'; -import { IPublicModelScrollTarget, IPublicModelScrollable, IPublicModelScroller } from '@alilc/lowcode-types'; +import { IPublicModelScrollTarget, IPublicTypeScrollable, IPublicModelScroller } from '@alilc/lowcode-types'; export interface IScrollTarget extends IPublicModelScrollTarget { } @@ -13,6 +13,14 @@ export class ScrollTarget implements IScrollTarget { return 'scrollY' in this.target ? this.target.scrollY : this.target.scrollTop; } + private doc?: HTMLElement; + + constructor(private target: Window | Element) { + if (isWindow(target)) { + this.doc = target.document.documentElement; + } + } + scrollTo(options: { left?: number; top?: number }) { this.target.scrollTo(options); } @@ -28,14 +36,6 @@ export class ScrollTarget implements IScrollTarget { get scrollWidth(): number { return ((this.doc || this.target) as any).scrollWidth; } - - private doc?: HTMLElement; - - constructor(private target: Window | Element) { - if (isWindow(target)) { - this.doc = target.document.documentElement; - } - } } function isWindow(obj: any): obj is Window { @@ -53,9 +53,9 @@ export interface IScroller extends IPublicModelScroller { } export class Scroller implements IScroller { private pid: number | undefined; - scrollable: IPublicModelScrollable; + scrollable: IPublicTypeScrollable; - constructor(scrollable: IPublicModelScrollable) { + constructor(scrollable: IPublicTypeScrollable) { this.scrollable = scrollable; } diff --git a/packages/designer/src/simulator.ts b/packages/designer/src/simulator.ts index 642e5ad67..5a2fb8efc 100644 --- a/packages/designer/src/simulator.ts +++ b/packages/designer/src/simulator.ts @@ -1,5 +1,5 @@ import { ComponentType } from 'react'; -import { IPublicTypeComponentMetadata, IPublicTypeNodeSchema, IPublicModelScrollable, IPublicTypeComponentInstance, IPublicModelSensor, IPublicTypeNodeInstance } from '@alilc/lowcode-types'; +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'; @@ -8,7 +8,7 @@ export type AutoFit = '100%'; // eslint-disable-next-line no-redeclare export const AutoFit = '100%'; -export interface IScrollable extends IPublicModelScrollable { +export interface IScrollable extends IPublicTypeScrollable { } export interface IViewport extends IScrollable { diff --git a/packages/plugin-outline-pane/src/controllers/pane-controller.ts b/packages/plugin-outline-pane/src/controllers/pane-controller.ts index 0d565c15f..d3187687a 100644 --- a/packages/plugin-outline-pane/src/controllers/pane-controller.ts +++ b/packages/plugin-outline-pane/src/controllers/pane-controller.ts @@ -8,7 +8,7 @@ import { } from '@alilc/lowcode-utils'; import { IPublicModelDragObject, - IPublicModelScrollable, + IPublicTypeScrollable, IPublicModelSensor, IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType, @@ -24,7 +24,7 @@ import { IndentTrack } from '../helper/indent-track'; import DwellTimer from '../helper/dwell-timer'; import { ITreeBoard, TreeMaster } from './tree-master'; -export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicModelScrollable { +export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTypeScrollable { private pluginContext: IPublicModelPluginContext; private treeMaster?: TreeMaster; diff --git a/packages/shell/src/api/canvas.ts b/packages/shell/src/api/canvas.ts index 444894452..d20ebd9d9 100644 --- a/packages/shell/src/api/canvas.ts +++ b/packages/shell/src/api/canvas.ts @@ -2,7 +2,7 @@ import { IPublicApiCanvas, IPublicModelDropLocation, IPublicModelScrollTarget, - IPublicModelScrollable, + IPublicTypeScrollable, IPublicModelScroller, IPublicTypeLocationData, IPublicModelEditor, @@ -58,7 +58,7 @@ export class Canvas implements IPublicApiCanvas { return new InnerScrollTarget(shell); } - createScroller(scrollable: IPublicModelScrollable): IPublicModelScroller { + createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller { return this[designerSymbol].createScroller(scrollable); } @@ -78,4 +78,4 @@ export class Canvas implements IPublicApiCanvas { get dropLocation() { return ShellDropLocation.create((this[designerSymbol] as any).dropLocation || null); } -} \ No newline at end of file +} diff --git a/packages/shell/src/model/component-meta.ts b/packages/shell/src/model/component-meta.ts index c913c2c0f..448f0584e 100644 --- a/packages/shell/src/model/component-meta.ts +++ b/packages/shell/src/model/component-meta.ts @@ -2,7 +2,7 @@ import { IComponentMeta as InnerComponentMeta, INode, } from '@alilc/lowcode-designer'; -import { IPublicTypeNodeData, IPublicTypeNodeSchema, IPublicModelComponentMeta, IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeNpmInfo, IPublicTypeTransformedComponentMetadata, IPublicModelNode, IPublicTypeAdvanced } from '@alilc/lowcode-types'; +import { IPublicTypeNodeData, IPublicTypeNodeSchema, IPublicModelComponentMeta, IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeNpmInfo, IPublicTypeTransformedComponentMetadata, IPublicModelNode, IPublicTypeAdvanced, IPublicTypeFieldConfig } from '@alilc/lowcode-types'; import { componentMetaSymbol, nodeSymbol } from '../symbols'; import { ReactElement } from 'react'; @@ -56,7 +56,7 @@ export class ComponentMeta implements IPublicModelComponentMeta { /** * 元数据配置 */ - get configure(): any { + get configure(): IPublicTypeFieldConfig[] { return this[componentMetaSymbol].configure; } diff --git a/packages/types/src/shell/api/canvas.ts b/packages/types/src/shell/api/canvas.ts index 33fbc7781..699e1a35d 100644 --- a/packages/types/src/shell/api/canvas.ts +++ b/packages/types/src/shell/api/canvas.ts @@ -1,4 +1,4 @@ -import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, IPublicModelScrollable, IPublicModelScroller, IPublicModelActiveTracker, IPublicModelClipboard } from '../model'; +import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, IPublicTypeScrollable, IPublicModelScroller, IPublicModelActiveTracker, IPublicModelClipboard } from '../model'; import { IPublicTypeLocationData } from '../type'; /** @@ -8,7 +8,7 @@ export interface IPublicApiCanvas { /** * 创一个滚动控制器 Scroller,赋予一个视图滚动的基本能力, - * a Scroller is a controller that gives a view (IPublicModelScrollable) the ability scrolling + * a Scroller is a controller that gives a view (IPublicTypeScrollable) the ability scrolling * to some cordination by api scrollTo. * * when a scroller is inited, will need to pass is a scrollable, which has a scrollTarget. @@ -16,7 +16,7 @@ export interface IPublicApiCanvas { * move scrollTarget`s top-left corner to (options.left, options.top) that passed in. * @since v1.1.0 */ - createScroller(scrollable: IPublicModelScrollable): IPublicModelScroller; + createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller; /** * 创建一个 ScrollTarget,与 Scroller 一起发挥作用,详见 createScroller 中的描述 diff --git a/packages/types/src/shell/model/component-meta.ts b/packages/types/src/shell/model/component-meta.ts index 7a5f3fa8c..369680fd6 100644 --- a/packages/types/src/shell/model/component-meta.ts +++ b/packages/types/src/shell/model/component-meta.ts @@ -1,4 +1,4 @@ -import { IPublicTypeNodeSchema, IPublicTypeNodeData, IPublicTypeIconType, IPublicTypeTransformedComponentMetadata, IPublicTypeI18nData, IPublicTypeNpmInfo, IPublicTypeAdvanced } from '../type'; +import { IPublicTypeNodeSchema, IPublicTypeNodeData, IPublicTypeIconType, IPublicTypeTransformedComponentMetadata, IPublicTypeI18nData, IPublicTypeNpmInfo, IPublicTypeAdvanced, IPublicTypeFieldConfig, IPublicTypeComponentAction } from '../type'; import { ReactElement } from 'react'; import { IPublicModelNode } from './node'; @@ -6,11 +6,13 @@ export interface IPublicModelComponentMeta { /** * 组件名 + * component name */ get componentName(): string; /** * 是否是「容器型」组件 + * is container node or not */ get isContainer(): boolean; @@ -19,37 +21,53 @@ export interface IPublicModelComponentMeta { * 当组件需要重新渲染时: * 若为最小渲染单元,则只渲染当前组件, * 若不为最小渲染单元,则寻找到上层最近的最小渲染单元进行重新渲染,直至根节点。 + * + * check if this is a mininal render unit. + * when a rerender is needed for a component: + * case 'it`s a mininal render unit': only render itself. + * case 'it`s not a mininal render unit': find a mininal render unit to render in + * its ancesters until root node is reached. */ get isMinimalRenderUnit(): boolean; /** * 是否为「模态框」组件 + * check if this is a modal component or not. */ get isModal(): boolean; /** - * 元数据配置 + * 获取用于设置面板显示用的配置 + * get configs for Settings Panel */ - get configure(): any; + get configure(): IPublicTypeFieldConfig[]; /** * 标题 + * title for this component */ get title(): string | IPublicTypeI18nData | ReactElement; /** * 图标 + * icon config for this component */ get icon(): IPublicTypeIconType; /** * 组件 npm 信息 + * npm informations */ get npm(): IPublicTypeNpmInfo; - get availableActions(): any; + /** + * 当前组件的可用 Action + * available actions + */ + get availableActions(): IPublicTypeComponentAction[]; /** + * 组件元数据中高级配置部分 * configure.advanced * @since v1.1.0 */ @@ -57,34 +75,39 @@ export interface IPublicModelComponentMeta { /** * 设置 npm 信息 + * set method for npm inforamtion * @param npm */ setNpm(npm: IPublicTypeNpmInfo): void; /** * 获取元数据 - * @returns + * get component metadata */ getMetadata(): IPublicTypeTransformedComponentMetadata; /** + * 检测当前对应节点是否可被放置在父节点中 * check if the current node could be placed in parent node - * @param my - * @param parent - * @returns + * @param my 当前节点 + * @param parent 父节点 */ checkNestingUp(my: IPublicModelNode | IPublicTypeNodeData, parent: any): boolean; /** + * 检测目标节点是否可被放置在父节点中 * check if the target node(s) could be placed in current node - * @param my - * @param parent - * @returns + * @param my 当前节点 + * @param parent 父节点 */ checkNestingDown( my: IPublicModelNode | IPublicTypeNodeData, target: IPublicTypeNodeSchema | IPublicModelNode | IPublicTypeNodeSchema[], ): boolean; + /** + * 刷新元数据,会触发元数据的重新解析和刷新 + * refresh metadata + */ refreshMetadata(): void; } diff --git a/packages/types/src/shell/model/dragon.ts b/packages/types/src/shell/model/dragon.ts index 6a6daf034..602284e63 100644 --- a/packages/types/src/shell/model/dragon.ts +++ b/packages/types/src/shell/model/dragon.ts @@ -3,6 +3,7 @@ import { IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type'; import { IPublicModelDragObject, IPublicModelLocateEvent, IPublicModelNode } from './'; export interface IPublicModelDragon { + /** * 是否正在拖动 * is dragging or not @@ -33,7 +34,6 @@ export interface IPublicModelDragon { */ onDragend(func: (o: { dragObject: IPublicModelDragObject; copy?: boolean }) => any): () => void; - /** * 设置拖拽监听的区域 shell,以及自定义拖拽转换函数 boost * set a html element as shell to dragon as monitoring target, and diff --git a/packages/types/src/shell/model/engine-config.ts b/packages/types/src/shell/model/engine-config.ts index 99d3a9071..2b17d7e72 100644 --- a/packages/types/src/shell/model/engine-config.ts +++ b/packages/types/src/shell/model/engine-config.ts @@ -1,7 +1,7 @@ import { IPublicModelPreference } from './'; - export interface IPublicModelEngineConfig { + /** * 判断指定 key 是否有值 * check if config has certain key configed diff --git a/packages/types/src/shell/model/index.ts b/packages/types/src/shell/model/index.ts index 8f48f68f1..23b6a6431 100644 --- a/packages/types/src/shell/model/index.ts +++ b/packages/types/src/shell/model/index.ts @@ -18,7 +18,6 @@ export * from '../type/plugin'; export * from './window'; export * from './scroll-target'; export * from './scroller'; -export * from './scrollable'; export * from './active-tracker'; export * from './exclusive-group'; export * from './plugin-context'; @@ -29,4 +28,4 @@ export * from './preference'; export * from './plugin-instance'; export * from './sensor'; export * from './resource'; -export * from './clipboard'; \ No newline at end of file +export * from './clipboard'; diff --git a/packages/types/src/shell/model/node-children.ts b/packages/types/src/shell/model/node-children.ts index c6fde9403..d18bf78a3 100644 --- a/packages/types/src/shell/model/node-children.ts +++ b/packages/types/src/shell/model/node-children.ts @@ -3,6 +3,7 @@ import { IPublicEnumTransformStage } from '../enum'; import { IPublicModelNode } from './'; export interface IPublicModelNodeChildren { + /** * 返回当前 children 实例所属的节点实例 * get owner node of this nodeChildren diff --git a/packages/types/src/shell/model/preference.ts b/packages/types/src/shell/model/preference.ts index a58b76573..e200dae9d 100644 --- a/packages/types/src/shell/model/preference.ts +++ b/packages/types/src/shell/model/preference.ts @@ -1,5 +1,6 @@ export interface IPublicModelPreference { + /** * set value from local storage by module and key */ diff --git a/packages/types/src/shell/model/setting-prop-entry.ts b/packages/types/src/shell/model/setting-prop-entry.ts index 90785ff19..f392cda33 100644 --- a/packages/types/src/shell/model/setting-prop-entry.ts +++ b/packages/types/src/shell/model/setting-prop-entry.ts @@ -1,8 +1,8 @@ import { IPublicTypeCustomView, IPublicTypeCompositeValue, IPublicTypeSetterType, IPublicTypeSetValueOptions, IPublicTypeFieldConfig, IPublicTypeFieldExtraProps } from '../type'; import { IPublicModelNode, IPublicModelComponentMeta, IPublicModelSettingTopEntry } from './'; - export interface IPublicModelSettingPropEntry { + /** * 获取设置属性的 isGroup */ diff --git a/packages/types/src/shell/model/setting-top-entry.ts b/packages/types/src/shell/model/setting-top-entry.ts index da2e586d3..b609d24f3 100644 --- a/packages/types/src/shell/model/setting-top-entry.ts +++ b/packages/types/src/shell/model/setting-top-entry.ts @@ -1,6 +1,7 @@ import { IPublicModelNode, IPublicModelSettingPropEntry } from './'; export interface IPublicModelSettingTopEntry { + /** * 返回所属的节点实例 */ diff --git a/packages/types/src/shell/type/component-action.ts b/packages/types/src/shell/type/component-action.ts index 853e82ce0..f86324e7a 100644 --- a/packages/types/src/shell/type/component-action.ts +++ b/packages/types/src/shell/type/component-action.ts @@ -6,23 +6,28 @@ import { IPublicTypeActionContentObject } from './'; */ export interface IPublicTypeComponentAction { + /** * behaviorName */ name: string; + /** * 菜单名称 */ content: string | ReactNode | IPublicTypeActionContentObject; + /** * 子集 */ items?: IPublicTypeComponentAction[]; + /** * 显示与否 * always: 无法禁用 */ condition?: boolean | ((currentNode: any) => boolean) | 'always'; + /** * 显示在工具条上 */ diff --git a/packages/types/src/shell/type/field-config.ts b/packages/types/src/shell/type/field-config.ts index 41b737807..32b40f157 100644 --- a/packages/types/src/shell/type/field-config.ts +++ b/packages/types/src/shell/type/field-config.ts @@ -4,38 +4,46 @@ import { IPublicTypeTitleContent, IPublicTypeSetterType, IPublicTypeFieldExtraPr * 属性面板配置 */ export interface IPublicTypeFieldConfig extends IPublicTypeFieldExtraProps { + /** * 面板配置隶属于单个 field 还是分组 */ type?: 'field' | 'group'; + /** * the name of this setting field, which used in quickEditor */ name: string | number; + /** * the field title * @default sameas .name */ title?: IPublicTypeTitleContent; + /** * 单个属性的 setter 配置 * * the field body contains when .type = 'field' */ setter?: IPublicTypeSetterType | IPublicTypeDynamicSetter; + /** * the setting items which group body contains when .type = 'group' */ items?: IPublicTypeFieldConfig[]; + /** * extra props for field * 其他配置属性(不做流通要求) */ extraProps?: IPublicTypeFieldExtraProps; + /** * @deprecated */ description?: IPublicTypeTitleContent; + /** * @deprecated */ diff --git a/packages/types/src/shell/type/index.ts b/packages/types/src/shell/type/index.ts index a066e1f57..b5dad9bb6 100644 --- a/packages/types/src/shell/type/index.ts +++ b/packages/types/src/shell/type/index.ts @@ -88,4 +88,5 @@ export * from './resource-type'; export * from './resource-type-config'; export * from './editor-view-config'; export * from './hotkey-callback-config'; -export * from './hotkey-callbacks'; \ No newline at end of file +export * from './hotkey-callbacks'; +export * from './scrollable'; diff --git a/packages/types/src/shell/model/scrollable.ts b/packages/types/src/shell/type/scrollable.ts similarity index 50% rename from packages/types/src/shell/model/scrollable.ts rename to packages/types/src/shell/type/scrollable.ts index d97a2984c..b308637e0 100644 --- a/packages/types/src/shell/model/scrollable.ts +++ b/packages/types/src/shell/type/scrollable.ts @@ -1,7 +1,7 @@ -import { IPublicModelScrollTarget } from './'; +import { IPublicModelScrollTarget } from '../model'; -export interface IPublicModelScrollable { +export interface IPublicTypeScrollable { scrollTarget?: IPublicModelScrollTarget | Element; bounds?: DOMRect | null; scale?: number; -} \ No newline at end of file +} From 69ab81a14719db266723b185de46a7047890a11a Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 6 Feb 2023 17:24:40 +0800 Subject: [PATCH 39/89] feat: the event supplements the dispose function as the return value --- docs/docs/api/material.md | 5 +- docs/docs/api/model/document-model.md | 14 +++-- docs/docs/api/skeleton.md | 15 +++-- docs/docs/api/workspace.md | 62 +++++++++++-------- packages/designer/src/project/project.ts | 2 - packages/shell/src/api/material.ts | 3 +- packages/shell/src/api/skeleton.ts | 10 +-- packages/shell/src/api/workspace.ts | 8 +-- packages/shell/src/model/document-model.ts | 36 ++++++----- packages/types/src/shell/api/material.ts | 4 +- packages/types/src/shell/api/skeleton.ts | 11 ++-- packages/types/src/shell/api/workspace.ts | 8 +-- .../types/src/shell/model/document-model.ts | 26 ++++---- 13 files changed, 117 insertions(+), 87 deletions(-) diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index 0732c568e..b52ad8cb2 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -358,8 +358,11 @@ material.getRegisteredMetadataTransducers(); * add callback for assets changed event * @param fn */ -onChangeAssets(fn: () => void): void; +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/model/document-model.md b/docs/docs/api/model/document-model.md index c9f338609..4da765d30 100644 --- a/docs/docs/api/model/document-model.md +++ b/docs/docs/api/model/document-model.md @@ -327,27 +327,31 @@ onChangeSelection(fn: (ids: string[]) => void): IPublicTypeDisposable; * set callback for event on visibility changed for certain node * @param fn */ -onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): void; +onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): IPublicTypeDisposable; ``` -相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) +- 相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) +- 相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) ### onChangeNodeChildren -onChangeNodeChildren(fn: (info?: IPublicTypeOnChangeOptions) => void) - 当前 document 的节点 children 变更事件 ```typescript +onChangeNodeChildren(fn: (info?: IPublicTypeOnChangeOptions) => void): IPublicTypeDisposable; ``` +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + ### onChangeNodeProp 当前 document 节点属性修改事件 ```typescript -onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void) +onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable; ``` +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + ### onImportSchema 当前 document 导入新的 schema 事件 ```typescript diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index e7ae391eb..6c8d898ff 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -295,9 +295,11 @@ hideArea(areaName: string): void; * @param listener * @returns */ -onShowPanel(listener: (...args: any[]) => void): () => void; +onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable; ``` +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + ### onHidePanel 监听 Panel 实例隐藏事件 @@ -309,9 +311,11 @@ onShowPanel(listener: (...args: any[]) => void): () => void; * @param listener * @returns */ -onHidePanel(listener: (...args: any[]) => void): () => void; +onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable; ``` +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + ### onShowWidget @@ -324,9 +328,10 @@ onHidePanel(listener: (...args: any[]) => void): () => void; * @param listener * @returns */ -onShowWidget(listener: (...args: any[]) => void): () => void; +onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; ``` +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) ### onHideWidget @@ -339,9 +344,11 @@ onShowWidget(listener: (...args: any[]) => void): () => void; * @param listener * @returns */ -onHideWidget(listener: (...args: any[]) => void): () => void; +onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; ``` +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + ## 使用示例 ```typescript diff --git a/docs/docs/api/workspace.md b/docs/docs/api/workspace.md index 81301d110..9d9960927 100644 --- a/docs/docs/api/workspace.md +++ b/docs/docs/api/workspace.md @@ -69,22 +69,6 @@ registerResourceType(resourceTypeModel: IPublicTypeResourceType): void; 相关类型:[IPublicTypeResourceType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-type.ts) -### onChangeWindows - -窗口新增/删除的事件 - -```typescript -function onChangeWindows(fn: () => void): void; -``` - -### onChangeActiveWindow - -active 窗口变更事件 - -```typescript -function onChangeActiveWindow(fn: () => void): void; -``` - ### setResourceList 设置设计器资源列表数据 @@ -95,16 +79,6 @@ setResourceList(resourceList: IPublicResourceList) {} 相关类型:[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts) -### onResourceListChange - -设计器资源列表数据变更事件 - -```typescript -onResourceListChange(fn: (resourceList: IPublicResourceList): void): (): void; -``` - -相关类型:[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts) - ### openEditorWindow 打开视图窗口 @@ -135,4 +109,38 @@ removeEditorWindow(resourceName: string, title: string): void; ```typescript removeEditorWindowById(id: string): void; -``` \ No newline at end of file +``` + +## 事件 + +### onChangeWindows + +窗口新增/删除的事件 + +```typescript +function onChangeWindows(fn: () => void): IPublicTypeDisposable; +``` + +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + +### onChangeActiveWindow + +active 窗口变更事件 + +```typescript +function onChangeActiveWindow(fn: () => void): IPublicTypeDisposable; +``` + +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + + +### onResourceListChange + +设计器资源列表数据变更事件 + +```typescript +onResourceListChange(fn: (resourceList: IPublicResourceList): void): (): IPublicTypeDisposable; +``` + +- 相关类型:[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts) +- 相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 582d5fdeb..082554846 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -85,8 +85,6 @@ export class Project implements IProject { return this._simulator || null; } - key = Math.random(); - @computed get currentDocument(): IDocumentModel | null { return this.documents.find((doc) => doc.active); } diff --git a/packages/shell/src/api/material.ts b/packages/shell/src/api/material.ts index cfc84620f..fb12ab8c0 100644 --- a/packages/shell/src/api/material.ts +++ b/packages/shell/src/api/material.ts @@ -12,6 +12,7 @@ import { IPublicModelComponentMeta, IPublicTypeNpmInfo, IPublicModelEditor, + IPublicTypeDisposable, } from '@alilc/lowcode-types'; import { Workspace as InnerWorkspace } from '@alilc/lowcode-workspace'; import { editorSymbol, designerSymbol } from '../symbols'; @@ -170,7 +171,7 @@ export class Material implements IPublicApiMaterial { * 监听 assets 变化的事件 * @param fn */ - onChangeAssets(fn: () => void): Function { + onChangeAssets(fn: () => void): IPublicTypeDisposable { const dispose = [ // 设置 assets,经过 setAssets 赋值 this[editorSymbol].onGot('assets', fn), diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index 8d5e2dc75..a60746803 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, IPublicTypeWidgetBaseConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; +import { IPublicApiSkeleton, IPublicTypeDisposable, IPublicTypeWidgetBaseConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; const innerSkeletonSymbol = Symbol('skeleton'); export class Skeleton implements IPublicApiSkeleton { @@ -129,7 +129,7 @@ export class Skeleton implements IPublicApiSkeleton { * @param listener * @returns */ - onShowPanel(listener: (...args: any[]) => void) { + onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable { const { editor } = this[skeletonSymbol]; editor.eventBus.on(SkeletonEvents.PANEL_SHOW, (name: any, panel: any) => { // 不泄漏 skeleton @@ -144,7 +144,7 @@ export class Skeleton implements IPublicApiSkeleton { * @param listener * @returns */ - onHidePanel(listener: (...args: any[]) => void) { + onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable { const { editor } = this[skeletonSymbol]; editor.eventBus.on(SkeletonEvents.PANEL_HIDE, (name: any, panel: any) => { // 不泄漏 skeleton @@ -159,7 +159,7 @@ export class Skeleton implements IPublicApiSkeleton { * @param listener * @returns */ - onShowWidget(listener: (...args: any[]) => void) { + onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable { const { editor } = this[skeletonSymbol]; editor.eventBus.on(SkeletonEvents.WIDGET_SHOW, (name: any, panel: any) => { // 不泄漏 skeleton @@ -174,7 +174,7 @@ export class Skeleton implements IPublicApiSkeleton { * @param listener * @returns */ - onHideWidget(listener: (...args: any[]) => void) { + onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable { const { editor } = this[skeletonSymbol]; editor.eventBus.on(SkeletonEvents.WIDGET_HIDE, (name: any, panel: any) => { // 不泄漏 skeleton diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index be6eb3ef7..54fccf426 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -1,4 +1,4 @@ -import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types'; +import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; import { Workspace as InnerWorkSpace } from '@alilc/lowcode-workspace'; import { Plugins } from '@alilc/lowcode-shell'; import { workspaceSymbol } from '../symbols'; @@ -19,7 +19,7 @@ export class Workspace implements IPublicApiWorkspace { this[workspaceSymbol].setResourceList(resourceList); } - onResourceListChange(fn: (resourceList: IPublicResourceList) => void): () => void { + onResourceListChange(fn: (resourceList: IPublicResourceList) => void): IPublicTypeDisposable { return this[workspaceSymbol].onResourceListChange(fn); } @@ -59,11 +59,11 @@ export class Workspace implements IPublicApiWorkspace { return this[workspaceSymbol].windows.map((d) => new ShellWindow(d)); } - onChangeWindows(fn: () => void) { + onChangeWindows(fn: () => void): IPublicTypeDisposable { return this[workspaceSymbol].onChangeWindows(fn); } - onChangeActiveWindow(fn: () => void) { + onChangeActiveWindow(fn: () => void): IPublicTypeDisposable { return this[workspaceSymbol].onChangeActiveWindow(fn); } } diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts index ba371543a..85d44c2cc 100644 --- a/packages/shell/src/model/document-model.ts +++ b/packages/shell/src/model/document-model.ts @@ -288,8 +288,8 @@ export class DocumentModel implements IPublicModelDocumentModel { * 当前 document 的节点显隐状态变更事件 * @param fn */ - onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): void { - this[documentSymbol].onChangeNodeVisible((node: IPublicModelNode, visible: boolean) => { + onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): IPublicTypeDisposable { + return this[documentSymbol].onChangeNodeVisible((node: IPublicModelNode, visible: boolean) => { fn(ShellNode.create(node)!, visible); }); } @@ -298,8 +298,8 @@ export class DocumentModel implements IPublicModelDocumentModel { * 当前 document 的节点 children 变更事件 * @param fn */ - onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): void { - this[documentSymbol].onChangeNodeChildren((info?: IPublicTypeOnChangeOptions) => { + onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): IPublicTypeDisposable { + return this[documentSymbol].onChangeNodeChildren((info?: IPublicTypeOnChangeOptions) => { if (!info) { return; } @@ -314,19 +314,27 @@ export class DocumentModel implements IPublicModelDocumentModel { * 当前 document 节点属性修改事件 * @param fn */ - onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void): void { + onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable { + const callback = (info: GlobalEvent.Node.Prop.ChangeOptions) => { + fn({ + key: info.key, + oldValue: info.oldValue, + newValue: info.newValue, + prop: ShellProp.create(info.prop)!, + node: ShellNode.create(info.node as any)!, + }); + }; this[editorSymbol].on( GlobalEvent.Node.Prop.InnerChange, - (info: GlobalEvent.Node.Prop.ChangeOptions) => { - fn({ - key: info.key, - oldValue: info.oldValue, - newValue: info.newValue, - prop: ShellProp.create(info.prop)!, - node: ShellNode.create(info.node as any)!, - }); - }, + callback, ); + + return () => { + this[editorSymbol].off( + GlobalEvent.Node.Prop.InnerChange, + callback, + ); + }; } /** diff --git a/packages/types/src/shell/api/material.ts b/packages/types/src/shell/api/material.ts index c8834816b..19e42e4a8 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 } from '../type'; +import { IPublicTypeAssetsJson, IPublicTypeMetadataTransducer, IPublicTypeComponentAction, IPublicTypeNpmInfo, IPublicTypeDisposable } from '../type'; import { IPublicModelComponentMeta } from '../model'; import { ComponentType } from 'react'; @@ -104,5 +104,5 @@ export interface IPublicApiMaterial { * add callback for assets changed event * @param fn */ - onChangeAssets(fn: () => void): Function; + onChangeAssets(fn: () => void): IPublicTypeDisposable; } diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts index bfd81532a..5c1f69c02 100644 --- a/packages/types/src/shell/api/skeleton.ts +++ b/packages/types/src/shell/api/skeleton.ts @@ -1,6 +1,7 @@ -import { IPublicTypeWidgetBaseConfig } from '../type'; +import { IPublicTypeDisposable, IPublicTypeWidgetBaseConfig } from '../type'; export interface IPublicApiSkeleton { + /** * 增加一个面板实例 * add a new panel @@ -80,7 +81,7 @@ export interface IPublicApiSkeleton { * @param listener * @returns */ - onShowPanel(listener: (...args: any[]) => void): () => void; + onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable; /** * 监听 Panel 实例隐藏事件 @@ -88,7 +89,7 @@ export interface IPublicApiSkeleton { * @param listener * @returns */ - onHidePanel(listener: (...args: any[]) => void): () => void; + onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable; /** * 监听 Widget 显示事件 @@ -96,7 +97,7 @@ export interface IPublicApiSkeleton { * @param listener * @returns */ - onShowWidget(listener: (...args: any[]) => void): () => void; + onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; /** * 监听 Widget 隐藏事件 @@ -104,5 +105,5 @@ export interface IPublicApiSkeleton { * @param listener * @returns */ - onHideWidget(listener: (...args: any[]) => void): () => void; + onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; } diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index ca4b3cc34..ee05bbe56 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -1,5 +1,5 @@ import { IPublicModelWindow } from '../model'; -import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types'; +import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; export interface IPublicApiWorkspace { @@ -21,7 +21,7 @@ export interface IPublicApiWorkspace { setResourceList(resourceList: IPublicResourceList): void; /** 资源树列表更新事件 */ - onResourceListChange(fn: (resourceList: IPublicResourceList) => void): () => void; + onResourceListChange(fn: (resourceList: IPublicResourceList) => void): () => IPublicTypeDisposable; /** 注册资源 */ registerResourceType(resourceTypeModel: IPublicTypeResourceType): void; @@ -39,8 +39,8 @@ export interface IPublicApiWorkspace { removeEditorWindowById(id: string): void; /** 窗口新增/删除的事件 */ - onChangeWindows(fn: () => void): void; + onChangeWindows(fn: () => void): IPublicTypeDisposable; /** active 窗口变更事件 */ - onChangeActiveWindow(fn: () => void): void; + onChangeActiveWindow(fn: () => void): IPublicTypeDisposable; } \ 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 e43d409a9..72d20ceb0 100644 --- a/packages/types/src/shell/model/document-model.ts +++ b/packages/types/src/shell/model/document-model.ts @@ -7,16 +7,9 @@ import { IPublicTypeOnChangeOptions } from '@alilc/lowcode-types'; export interface IPublicModelDocumentModel { /** - * id - */ - get id(): string; - - set id(id); - - /** - * 节点选中区模型实例 - * instance of selection - */ + * 节点选中区模型实例 + * instance of selection + */ selection: IPublicModelSelection; /** @@ -31,6 +24,13 @@ export interface IPublicModelDocumentModel { */ history: IPublicModelHistory; + /** + * id + */ + get id(): string; + + set id(id); + /** * 获取当前文档所属的 project * get project which this documentModel belongs to @@ -166,19 +166,19 @@ export interface IPublicModelDocumentModel { * set callback for event on visibility changed for certain node * @param fn */ - onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): void; + onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): IPublicTypeDisposable; /** * 当前 document 的节点 children 变更事件 * @param fn */ - onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): void; + onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): IPublicTypeDisposable; /** * 当前 document 节点属性修改事件 * @param fn */ - onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void): void; + onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable; /** * import schema event From 59cb9ef30add8d070c35a00715a523dd399ae175 Mon Sep 17 00:00:00 2001 From: haoziqaq <357229046@qq.com> Date: Mon, 6 Feb 2023 18:13:17 +0800 Subject: [PATCH 40/89] fix(designer): fix i18n --- .../src/designer/setting/setting-field.ts | 116 +++++++++++------- packages/designer/src/locale/en-US.json | 3 +- packages/designer/src/locale/zh-CN.json | 3 +- 3 files changed, 79 insertions(+), 43 deletions(-) diff --git a/packages/designer/src/designer/setting/setting-field.ts b/packages/designer/src/designer/setting/setting-field.ts index ab5b8eadb..c8bdf52e8 100644 --- a/packages/designer/src/designer/setting/setting-field.ts +++ b/packages/designer/src/designer/setting/setting-field.ts @@ -1,8 +1,16 @@ -import { IPublicTypeTitleContent, IPublicTypeSetterType, IPublicTypeDynamicSetter, IPublicTypeFieldExtraProps, IPublicTypeFieldConfig, IPublicTypeCustomView, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; +import { + IPublicTypeTitleContent, + IPublicTypeSetterType, + IPublicTypeDynamicSetter, + IPublicTypeFieldExtraProps, + IPublicTypeFieldConfig, + IPublicTypeCustomView, + IPublicTypeSetValueOptions, +} from '@alilc/lowcode-types'; import { Transducer } from './utils'; import { SettingPropEntry } from './setting-prop-entry'; import { SettingEntry } from './setting-entry'; -import { computed, obx, makeObservable, action, untracked } from '@alilc/lowcode-editor-core'; +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) { @@ -26,44 +34,32 @@ export class SettingField extends SettingPropEntry implements SettingEntry { private _config: IPublicTypeFieldConfig; + private hotValue: any; + + parent: SettingEntry; + extraProps: IPublicTypeFieldExtraProps; // ==== dynamic properties ==== private _title?: IPublicTypeTitleContent; get title() { - // FIXME! intl - return this._title || (typeof this.name === 'number' ? `项目 ${this.name}` : this.name); + return ( + this._title || (typeof this.name === 'number' ? `${intl('Item')} ${this.name}` : this.name) + ); } private _setter?: IPublicTypeSetterType | IPublicTypeDynamicSetter; - @computed get setter(): IPublicTypeSetterType | null { - if (!this._setter) { - return null; - } - if (isDynamicSetter(this._setter)) { - return untracked(() => { - const shellThis = this.internalToShellPropEntry(); - return this._setter.call(shellThis, shellThis); - }); - } - return this._setter; - } - @obx.ref private _expanded = true; - get expanded(): boolean { - return this._expanded; - } + private _items: Array = []; - setExpanded(value: boolean) { - this._expanded = value; - } - - parent: SettingEntry; - - constructor(parent: SettingEntry, config: IPublicTypeFieldConfig, settingFieldCollector?: (name: string | number, field: SettingField) => void) { + constructor( + parent: SettingEntry, + config: IPublicTypeFieldConfig, + settingFieldCollector?: (name: string | number, field: SettingField) => void, + ) { super(parent, config.name, config.type); makeObservable(this); const { title, items, setter, extraProps, ...rest } = config; @@ -90,7 +86,26 @@ export class SettingField extends SettingPropEntry implements SettingEntry { this.transducer = new Transducer(this, { setter }); } - private _items: Array = []; + @computed get setter(): IPublicTypeSetterType | null { + if (!this._setter) { + return null; + } + if (isDynamicSetter(this._setter)) { + return untracked(() => { + const shellThis = this.internalToShellPropEntry(); + return this._setter.call(shellThis, shellThis); + }); + } + return this._setter; + } + + get expanded(): boolean { + return this._expanded; + } + + setExpanded(value: boolean) { + this._expanded = value; + } get items(): Array { return this._items; @@ -100,7 +115,13 @@ export class SettingField extends SettingPropEntry implements SettingEntry { return this._config; } - private initItems(items: Array, settingFieldCollector?: { (name: string | number, field: SettingField): void; (name: string, field: SettingField): void }) { + private initItems( + items: Array, + settingFieldCollector?: { + (name: string | number, field: SettingField): void; + (name: string, field: SettingField): void; + }, + ) { this._items = items.map((item) => { if (isCustomView(item)) { return item; @@ -110,7 +131,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry { } private disposeItems() { - this._items.forEach(item => isSettingField(item) && item.purge()); + this._items.forEach((item) => isSettingField(item) && item.purge()); this._items = []; } @@ -125,15 +146,19 @@ export class SettingField extends SettingPropEntry implements SettingEntry { // ======= compatibles for vision ====== - getConfig(configName?: K): IPublicTypeFieldConfig[K] | IPublicTypeFieldConfig { + getConfig( + configName?: K, + ): IPublicTypeFieldConfig[K] | IPublicTypeFieldConfig { if (configName) { return this.config[configName]; } return this._config; } - getItems(filter?: (item: SettingField | IPublicTypeCustomView) => boolean): Array { - return this._items.filter(item => { + getItems( + filter?: (item: SettingField | IPublicTypeCustomView) => boolean, + ): Array { + return this._items.filter((item) => { if (filter) { return filter(item); } @@ -141,10 +166,13 @@ export class SettingField extends SettingPropEntry implements SettingEntry { }); } - private hotValue: any; - @action - setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: IPublicTypeSetValueOptions) { + setValue( + val: any, + isHotValue?: boolean, + force?: boolean, + extraOptions?: IPublicTypeSetValueOptions, + ) { if (isHotValue) { this.setHotValue(val, extraOptions); return; @@ -189,11 +217,16 @@ export class SettingField extends SettingPropEntry implements SettingEntry { } if (this.isUseVariable()) { const oldValue = this.getValue(); - this.setValue({ - type: 'JSExpression', - value: oldValue.value, - mock: value, - }, false, false, options); + this.setValue( + { + type: 'JSExpression', + value: oldValue.value, + mock: value, + }, + false, + false, + options, + ); } else { this.setValue(value, false, false, options); } @@ -210,6 +243,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry { return this.designer.autorun(action, true); } } + /** * @deprecated use same function from '@alilc/lowcode-utils' instead */ diff --git a/packages/designer/src/locale/en-US.json b/packages/designer/src/locale/en-US.json index 50fca66ca..28b489c8a 100644 --- a/packages/designer/src/locale/en-US.json +++ b/packages/designer/src/locale/en-US.json @@ -6,5 +6,6 @@ "unlock": "Unlock", "Condition Group": "Condition Group", "No opened document": "No opened document, open some document to editing", - "locked": "locked" + "locked": "locked", + "Item": "Item" } diff --git a/packages/designer/src/locale/zh-CN.json b/packages/designer/src/locale/zh-CN.json index 50d46dbf2..6ecf79786 100644 --- a/packages/designer/src/locale/zh-CN.json +++ b/packages/designer/src/locale/zh-CN.json @@ -6,5 +6,6 @@ "unlock": "解锁", "Condition Group": "条件组", "No opened document": "没有打开的页面,请选择页面打开编辑", - "locked": "已锁定" + "locked": "已锁定", + "Item": "项目" } From 3dc402bab17b1080687a6bebfec5d63a777a88db Mon Sep 17 00:00:00 2001 From: JackLian Date: Tue, 7 Feb 2023 11:27:54 +0800 Subject: [PATCH 41/89] chore: publish docs 1.0.18 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 613cb4831..3a07ecd67 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.17", + "version": "1.0.18", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 0184dcd9384a3145dff92e96bca2de414c02d99d Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 7 Feb 2023 14:35:10 +0800 Subject: [PATCH 42/89] feat: added onChangeViewType event to window model --- docs/docs/api/model/window.md | 12 ++++++++++++ packages/shell/src/model/window.ts | 8 ++++++-- packages/types/src/shell/model/window.ts | 5 ++++- packages/workspace/src/window.ts | 18 ++++++++++++++++-- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/docs/docs/api/model/window.md b/docs/docs/api/model/window.md index 7814ae6ea..f102c0cab 100644 --- a/docs/docs/api/model/window.md +++ b/docs/docs/api/model/window.md @@ -62,3 +62,15 @@ function changeViewType(viewName: string): void ```typescript function save(): Promise(void) ``` + +## 事件 + +### onChangeViewType + +窗口视图变更事件 + +``` +onChangeViewType(fn: (viewName: string) => void): IPublicTypeDisposable; +``` + +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index 06e408a96..e2f17b889 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -1,5 +1,5 @@ import { windowSymbol } from '../symbols'; -import { IPublicModelResource, IPublicModelWindow } from '@alilc/lowcode-types'; +import { IPublicModelResource, IPublicModelWindow, IPublicTypeDisposable } from '@alilc/lowcode-types'; import { EditorWindow } from '@alilc/lowcode-workspace'; import { Resource as ShellResource } from './resource'; @@ -31,7 +31,11 @@ export class Window implements IPublicModelWindow { } changeViewType(viewName: string) { - this[windowSymbol].changeViewType(viewName); + this[windowSymbol].changeViewType(viewName, false); + } + + onChangeViewType(fun: (viewName: string) => void): IPublicTypeDisposable { + return this[windowSymbol].onChangeViewType(fun); } async save() { diff --git a/packages/types/src/shell/model/window.ts b/packages/types/src/shell/model/window.ts index 741ac1c8e..f772dc9f4 100644 --- a/packages/types/src/shell/model/window.ts +++ b/packages/types/src/shell/model/window.ts @@ -1,5 +1,5 @@ import { ReactElement } from 'react'; -import { IPublicTypeNodeSchema } from '../type'; +import { IPublicTypeDisposable, IPublicTypeNodeSchema } from '../type'; import { IPublicModelResource } from './resource'; export interface IPublicModelWindow { @@ -24,4 +24,7 @@ export interface IPublicModelWindow { /** 调用当前窗口视图保存钩子 */ save(): Promise; + + /** 窗口视图变更事件 */ + onChangeViewType(fn: (viewName: string) => void): IPublicTypeDisposable; } \ No newline at end of file diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index 73064c6b4..06993d2e3 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -1,13 +1,16 @@ import { uniqueId } from '@alilc/lowcode-utils'; -import { makeObservable, obx } from '@alilc/lowcode-editor-core'; +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 { IPublicTypeDisposable } from '../../types/es/shell/type/disposable'; export class EditorWindow { id: string = uniqueId('window'); icon: React.ReactElement | undefined; + private emitter: IEventBus = createModuleEventBus('Project'); + @obx.ref editorView: Context; @obx editorViews: Map = new Map(); @@ -59,6 +62,14 @@ export class EditorWindow { } }; + onChangeViewType(fn: (viewName: string) => void): IPublicTypeDisposable { + this.emitter.on('window.change.view.type', fn); + + return () => { + this.emitter.off('window.change.view.type', fn); + }; + } + execViewTypesInit = async () => { const editorViews = this.resource.editorViews; for (let i = 0; i < editorViews.length; i++) { @@ -81,10 +92,13 @@ export class EditorWindow { this.editorViews.set(name, editorView); }; - changeViewType = (name: string) => { + changeViewType = (name: string, ignoreEmit: boolean = true) => { this.editorView?.setActivate(false); this.editorView = this.editorViews.get(name)!; + if (!ignoreEmit) { + this.emitter.emit('window.change.view.type', name); + } this.editorView.setActivate(true); }; From c3ce042c835b0c6c8f319dc9c286bc43a903c61a Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 7 Feb 2023 17:18:47 +0800 Subject: [PATCH 43/89] feat: the renderer-core leaf component removes the react.createElement call --- .../src/builtin-simulator/renderer.ts | 3 + .../designer/src/document/document-model.ts | 1 + packages/designer/src/document/node/node.ts | 9 +- packages/renderer-core/src/hoc/leaf.tsx | 166 +++++++++--------- packages/renderer-core/src/renderer/base.tsx | 14 +- .../renderer-core/src/renderer/renderer.tsx | 2 + packages/renderer-core/src/types/index.ts | 54 ++++-- .../renderer-core/tests/hoc/leaf.test.tsx | 2 + .../tests/renderer/base.test.tsx | 3 +- packages/renderer-core/tests/utils/node.ts | 4 + 10 files changed, 160 insertions(+), 98 deletions(-) diff --git a/packages/designer/src/builtin-simulator/renderer.ts b/packages/designer/src/builtin-simulator/renderer.ts index be32b6be6..d9171c355 100644 --- a/packages/designer/src/builtin-simulator/renderer.ts +++ b/packages/designer/src/builtin-simulator/renderer.ts @@ -3,6 +3,9 @@ import { IPublicTypeNodeSchema, IPublicTypeComponentInstance, IPublicTypeNodeIns export interface BuiltinSimulatorRenderer { readonly isSimulatorRenderer: true; + autoRepaintNode?: boolean; + components: Record; + rerender: () => void; createComponent(schema: IPublicTypeNodeSchema): Component | null; getComponent(componentName: string): Component; getClosestNodeInstance( diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 5eb60c396..9600e8008 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -64,6 +64,7 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'select dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject, ): boolean; + getNodeCount(): number; } export class DocumentModel implements IDocumentModel { diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 7baa5ad0a..7739bcf1c 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -15,6 +15,7 @@ import { IPublicModelNode, IPublicModelExclusiveGroup, IPublicEnumTransformStage, + IPublicTypeDisposable, } from '@alilc/lowcode-types'; import { compatStage, isDOMText, isJSExpression, isNode } from '@alilc/lowcode-utils'; import { SettingTopEntry } from '@alilc/lowcode-designer'; @@ -112,6 +113,10 @@ export interface INode extends IPublicModelNode { replaceChild(node: INode, data: any): INode; getSuitablePlace(node: INode, ref: any): any; + + onChildrenChange(fn: (param?: { type: string; node: INode }) => void): IPublicTypeDisposable; + + onPropChange(func: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable; } /** @@ -1080,7 +1085,7 @@ export class Node return this.props; } - onChildrenChange(fn: (param?: { type: string; node: Node }) => void): (() => void) | undefined { + onChildrenChange(fn: (param?: { type: string; node: Node }) => void): IPublicTypeDisposable { const wrappedFunc = wrapWithEventSwitch(fn); return this.children?.onChange(wrappedFunc); } @@ -1273,7 +1278,7 @@ export class Node this.emitter?.emit('propChange', val); } - onPropChange(func: (info: IPublicTypePropChangeOptions) => void): Function { + onPropChange(func: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable { const wrappedFunc = wrapWithEventSwitch(func); this.emitter.on('propChange', wrappedFunc); return () => { diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index 8af892f05..5df988048 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -1,4 +1,4 @@ -import { BuiltinSimulatorHost, Node, IPublicTypePropChangeOptions } from '@alilc/lowcode-designer'; +import { INode, IPublicTypePropChangeOptions } from '@alilc/lowcode-designer'; import { GlobalEvent, IPublicEnumTransformStage, IPublicTypeNodeSchema, IPublicTypeEngineOptions } from '@alilc/lowcode-types'; import { isReactComponent, cloneEnumerableProperty } from '@alilc/lowcode-utils'; import { debounce } from '../utils/common'; @@ -16,15 +16,17 @@ export interface IComponentHocProps { __tag: any; componentId: any; _leaf: any; - forwardedRef: any; + forwardedRef?: any; } export interface IComponentHocState { childrenInState: boolean; nodeChildren: any; nodeCacheProps: any; + /** 控制是否显示隐藏 */ visible: boolean; + /** 控制是否渲染 */ condition: boolean; nodeProps: any; @@ -40,15 +42,17 @@ export interface IComponentHoc { export type IComponentConstruct = (Comp: types.IBaseRenderComponent, info: IComponentHocInfo) => types.IGeneralConstructor; interface IProps { - _leaf: Node | undefined; + _leaf: INode | undefined; visible: boolean; - componentId?: number; + componentId: number; - children?: Node[]; + children?: INode[]; - __tag?: number; + __tag: number; + + forwardedRef?: any; } enum RerenderType { @@ -61,8 +65,7 @@ enum RerenderType { // 缓存 Leaf 层组件,防止重新渲染问题 class LeafCache { - constructor(public documentId: string, public device: string) { - } + /** 组件缓存 */ component = new Map(); @@ -77,6 +80,9 @@ class LeafCache { event = new Map(); ref = new Map(); + + constructor(public documentId: string, public device: string) { + } } let cache: LeafCache; @@ -155,11 +161,11 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { const curDocumentId = baseRenderer.props?.documentId ?? ''; const curDevice = baseRenderer.props?.device ?? ''; const getNode = baseRenderer.props?.getNode; - const container: BuiltinSimulatorHost = baseRenderer.props?.__container; + const container = baseRenderer.props?.__container; const setSchemaChangedSymbol = baseRenderer.props?.setSchemaChangedSymbol; const editor = host?.designer?.editor; const runtime = adapter.getRuntime(); - const { forwardRef } = runtime; + const { forwardRef, createElement } = runtime; const Component = runtime.Component as types.IGeneralConstructor< IComponentHocProps, IComponentHocState >; @@ -192,14 +198,64 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { recordInfo: { startTime?: number | null; type?: string; - node?: Node; + node?: INode; } = {}; + + private curEventLeaf: INode | undefined; + static displayName = schema.componentName; disposeFunctions: Array<((() => void) | Function)> = []; __component_tag = 'leafWrapper'; + renderUnitInfo: { + minimalUnitId?: string; + minimalUnitName?: string; + singleRender?: boolean; + }; + + // 最小渲染单元做防抖处理 + makeUnitRenderDebounced = debounce(() => { + this.beforeRender(RerenderType.MinimalRenderUnit); + const schema = this.leaf?.export?.(IPublicEnumTransformStage.Render); + if (!schema) { + return; + } + const nextProps = getProps(schema, scope, Comp, componentInfo); + const children = getChildren(schema, scope, Comp); + const nextState = { + nodeProps: nextProps, + nodeChildren: children, + childrenInState: true, + }; + if ('children' in nextProps) { + nextState.nodeChildren = nextProps.children; + } + + __debug(`${this.leaf?.componentName}(${this.props.componentId}) MinimalRenderUnit Render!`); + this.setState(nextState); + }, 20); + + constructor(props: IProps, context: any) { + super(props, context); + // 监听以下事件,当变化时更新自己 + __debug(`${schema.componentName}[${this.props.componentId}] leaf render in SimulatorRendererView`); + clearRerenderEvent(componentCacheId); + this.curEventLeaf = this.leaf; + + cache.ref.set(componentCacheId, { + makeUnitRender: this.makeUnitRender, + }); + + let cacheState = cache.state.get(componentCacheId); + if (!cacheState || cacheState.__tag !== props.__tag) { + cacheState = this.getDefaultState(props); + } + + this.state = cacheState; + } + recordTime = () => { if (!this.recordInfo.startTime) { return; @@ -216,6 +272,14 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { this.recordInfo.startTime = null; }; + makeUnitRender = () => { + this.makeUnitRenderDebounced(); + }; + + get autoRepaintNode() { + return container?.autoRepaintNode; + } + componentDidUpdate() { this.recordTime(); } @@ -243,27 +307,6 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { }; } - constructor(props: IProps, context: any) { - super(props, context); - // 监听以下事件,当变化时更新自己 - __debug(`${schema.componentName}[${this.props.componentId}] leaf render in SimulatorRendererView`); - clearRerenderEvent(componentCacheId); - this.curEventLeaf = this.leaf; - - cache.ref.set(componentCacheId, { - makeUnitRender: this.makeUnitRender, - }); - - let cacheState = cache.state.get(componentCacheId); - if (!cacheState || cacheState.__tag !== props.__tag) { - cacheState = this.getDefaultState(props); - } - - this.state = cacheState; - } - - private curEventLeaf: Node | undefined; - setState(state: any) { cache.state.set(componentCacheId, { ...this.state, @@ -274,23 +317,13 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { } /** 由于内部属性变化,在触发渲染前,会执行该函数 */ - beforeRender(type: string, node?: Node): void { + beforeRender(type: string, node?: INode): void { this.recordInfo.startTime = Date.now(); this.recordInfo.type = type; this.recordInfo.node = node; setSchemaChangedSymbol?.(true); } - renderUnitInfo: { - minimalUnitId?: string; - minimalUnitName?: string; - singleRender?: boolean; - }; - - get autoRepaintNode() { - return container.autoRepaintNode; - } - judgeMiniUnitRender() { if (!this.renderUnitInfo) { this.getRenderUnitInfo(); @@ -308,7 +341,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { if (!ref) { __debug('Cant find minimalRenderUnit ref! This make rerender!'); - container.rerender(); + container?.rerender(); return; } __debug(`${this.leaf?.componentName}(${this.props.componentId}) need render, make its minimalRenderUnit ${renderUnitInfo.minimalUnitName}(${renderUnitInfo.minimalUnitId})`); @@ -321,7 +354,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { return; } - if (leaf.isRoot()) { + if (leaf.isRootNode) { this.renderUnitInfo = { singleRender: true, ...(this.renderUnitInfo || {}), @@ -347,32 +380,6 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { } } - // 最小渲染单元做防抖处理 - makeUnitRenderDebounced = debounce(() => { - this.beforeRender(RerenderType.MinimalRenderUnit); - const schema = this.leaf?.export?.(IPublicEnumTransformStage.Render); - if (!schema) { - return; - } - const nextProps = getProps(schema, scope, Comp, componentInfo); - const children = getChildren(schema, scope, Comp); - const nextState = { - nodeProps: nextProps, - nodeChildren: children, - childrenInState: true, - }; - if ('children' in nextProps) { - nextState.nodeChildren = nextProps.children; - } - - __debug(`${this.leaf?.componentName}(${this.props.componentId}) MinimalRenderUnit Render!`); - this.setState(nextState); - }, 20); - - makeUnitRender = () => { - this.makeUnitRenderDebounced(); - }; - componentWillReceiveProps(nextProps: any) { let { componentId } = nextProps; if (nextProps.__tag === this.props.__tag) { @@ -420,7 +427,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { // 目前多层循坏无法判断需要从哪一层开始渲染,故先粗暴解决 if (key === '___loop___') { __debug('key is ___loop___, render a page!'); - container.rerender(); + container?.rerender(); // 由于 scope 变化,需要清空缓存,使用新的 scope cache.component.delete(componentCacheId); return; @@ -536,7 +543,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { return []; } - get leaf(): Node | undefined { + get leaf(): INode | undefined { if (this.props._leaf?.isMock) { // 低代码组件作为一个整体更新,其内部的组件不需要监听相关事件 return undefined; @@ -570,13 +577,12 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { } } - let LeafWrapper = forwardRef((props: any, ref: any) => ( - // @ts-ignore - - )); + let LeafWrapper = forwardRef((props: any, ref: any) => { + return createElement(LeafHoc, { + ...props, + forwardedRef: ref, + }); + }); LeafWrapper = cloneEnumerableProperty(LeafWrapper, Comp); diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 601faf6a9..b4439f4fe 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -3,7 +3,7 @@ /* eslint-disable react/prop-types */ import classnames from 'classnames'; import { create as createDataSourceEngine } from '@alilc/lowcode-datasource-engine/interpret'; -import { IPublicTypeNodeSchema, IPublicTypeNodeData, JSONValue, IPublicTypeCompositeValue } from '@alilc/lowcode-types'; +import { IPublicTypeNodeSchema, IPublicTypeNodeData, IPublicTypeJSONValue, IPublicTypeCompositeValue } from '@alilc/lowcode-types'; import { isI18nData, isJSExpression, isJSFunction } from '@alilc/lowcode-utils'; import adapter from '../adapter'; import divFactory from '../components/Div'; @@ -121,6 +121,8 @@ export default function baseRendererFactory(): IBaseRenderComponent { let scopeIdx = 0; return class BaseRenderer extends Component> { + [key: string]: any; + static displayName = 'BaseRenderer'; static defaultProps = { @@ -139,6 +141,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { __compScopes: Record = {}; __instanceMap: Record = {}; __dataHelper: any; + /** * keep track of customMethods added to this context * @@ -155,8 +158,6 @@ export default function baseRendererFactory(): IBaseRenderComponent { */ __styleElement: any; - [key: string]: any; - constructor(props: IBaseRendererProps, context: IBaseRendererContext) { super(props, context); this.context = context; @@ -242,6 +243,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { super.forceUpdate(); } } + /** * execute method in schema.lifeCycles * @PRIVATE @@ -490,6 +492,10 @@ export default function baseRendererFactory(): IBaseRenderComponent { } const _children = getSchemaChildren(schema); + if (!schema.componentName) { + logger.error('The componentName in the schema is invalid, please check the schema: ', schema); + return; + } // 解析占位组件 if (schema.componentName === 'Fragment' && _children) { const tarChildren = isJSExpression(_children) ? this.__parseExpression(_children, scope) : _children; @@ -758,7 +764,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { const itemArg = (schema.loopArgs && schema.loopArgs[0]) || DEFAULT_LOOP_ARG_ITEM; const indexArg = (schema.loopArgs && schema.loopArgs[1]) || DEFAULT_LOOP_ARG_INDEX; const { loop } = schema; - return loop.map((item: JSONValue | IPublicTypeCompositeValue, i: number) => { + return loop.map((item: IPublicTypeJSONValue | IPublicTypeCompositeValue, i: number) => { const loopSelf: any = { [itemArg]: item, [indexArg]: i, diff --git a/packages/renderer-core/src/renderer/renderer.tsx b/packages/renderer-core/src/renderer/renderer.tsx index a1ed88701..c0f1c2afc 100644 --- a/packages/renderer-core/src/renderer/renderer.tsx +++ b/packages/renderer-core/src/renderer/renderer.tsx @@ -6,6 +6,7 @@ import baseRendererFactory from './base'; import divFactory from '../components/Div'; import { IRenderComponent, IRendererProps, IRendererState } from '../types'; import { IPublicTypeNodeSchema, IPublicTypeRootSchema } from '@alilc/lowcode-types'; +import logger from '../utils/logger'; export default function rendererFactory(): IRenderComponent { const { PureComponent, Component, createElement, findDOMNode } = adapter.getRuntime(); @@ -168,6 +169,7 @@ export default function rendererFactory(): IRenderComponent { } // 兼容乐高区块模板 if (schema.componentName !== 'Div' && !isFileSchema(schema)) { + logger.error('The root component name needs to be one of Page、Block、Component, please check the schema: ', schema); return '模型结构异常'; } debug('entry.render'); diff --git a/packages/renderer-core/src/types/index.ts b/packages/renderer-core/src/types/index.ts index 9c2aaa143..8d619737c 100644 --- a/packages/renderer-core/src/types/index.ts +++ b/packages/renderer-core/src/types/index.ts @@ -1,5 +1,5 @@ import type { ComponentLifecycle, CSSProperties } from 'react'; -import { BuiltinSimulatorHost } from '@alilc/lowcode-designer'; +import { BuiltinSimulatorHost, BuiltinSimulatorRenderer } from '@alilc/lowcode-designer'; import { RequestHandler, IPublicTypeNodeSchema, IPublicTypeRootSchema, IPublicTypeJSONObject } from '@alilc/lowcode-types'; export type ISchema = IPublicTypeNodeSchema | IPublicTypeRootSchema; @@ -8,16 +8,16 @@ export type ISchema = IPublicTypeNodeSchema | IPublicTypeRootSchema; ** Duck typed component type supporting both react and rax */ interface IGeneralComponent

extends ComponentLifecycle { + readonly props: Readonly

& Readonly<{ children?: any | undefined }>; + state: Readonly; + refs: Record; + context: any; setState( state: ((prevState: Readonly, props: Readonly

) => (Pick | S | null)) | (Pick | S | null), callback?: () => void ): void; forceUpdate(callback?: () => void): void; render(): any; - readonly props: Readonly

& Readonly<{ children?: any | undefined }>; - state: Readonly; - refs: Record; - context: any; } export type IGeneralConstructor< @@ -60,20 +60,28 @@ export interface ILocationLike { } export type IRendererAppHelper = Partial<{ + /** 全局公共函数 */ utils: Record; + /** 全局常量 */ constants: Record; + /** react-router 的 location 实例 */ location: ILocationLike; + /** react-router 的 history 实例 */ history: IHistoryLike; + /** @deprecated 已无业务使用 */ match: any; + /** @experimental 内部使用 */ logParams: Record; + /** @experimental 内部使用 */ addons: Record; + /** @experimental 内部使用 */ requestHandlersMap: Record; + /** CSS 类名 */ className?: string; + /** style */ style?: CSSProperties; + /** id */ id?: string | number; + /** 语言 */ locale?: string; + /** * 多语言语料 * 配置规范参见《低代码搭建组件描述协议》https://lowcode-engine.cn/lowcode 中 2.6 国际化多语言支持 * */ messages?: Record; + /** 主要用于设置渲染模块的全局上下文,里面定义的内容可以在低代码中通过 this 来访问,比如 this.utils */ appHelper?: IRendererAppHelper; + /** * 配置规范参见《低代码搭建组件描述协议》https://lowcode-engine.cn/lowcode * 主要在搭建场景中使用,用于提升用户搭建体验。 @@ -112,33 +129,46 @@ export interface IRendererProps { * > 在生产环境下不需要设置 */ componentsMap?: { [key: string]: any }; + /** 设计模式,可选值:live、design */ designMode?: string; + /** 渲染模块是否挂起,当设置为 true 时,渲染模块最外层容器的 shouldComponentUpdate 将始终返回false,在下钻编辑或者多引擎渲染的场景会用到该参数。 */ suspended?: boolean; + /** 组件获取 ref 时触发的钩子 */ onCompGetRef?: (schema: IPublicTypeNodeSchema, ref: any) => void; + /** 组件 ctx 更新回调 */ onCompGetCtx?: (schema: IPublicTypeNodeSchema, ref: any) => void; + /** 传入的 schema 是否有变更 */ getSchemaChangedSymbol?: () => boolean; + /** 设置 schema 是否有变更 */ setSchemaChangedSymbol?: (symbol: boolean) => void; + /** 自定义创建 element 的钩子 */ customCreateElement?: (Component: any, props: any, children: any) => any; + /** 渲染类型,标识当前模块是以什么类型进行渲染的 */ rendererName?: 'LowCodeRenderer' | 'PageRenderer' | string; + /** 当找不到组件时,显示的组件 */ notFoundComponent?: IGeneralComponent; + /** 当组件渲染异常时,显示的组件 */ faultComponent?: IGeneralComponent; + /** 设备信息 */ device?: string; + /** * @default true * JSExpression 是否只支持使用 this 来访问上下文变量 */ thisRequiredInJSE?: boolean; + /** * @default false * 当开启组件未找到严格模式时,渲染模块不会默认给一个容器组件 @@ -162,7 +192,7 @@ export interface IBaseRendererProps { __ctx: Record; __schema: IPublicTypeRootSchema; __host?: BuiltinSimulatorHost; - __container?: any; + __container?: BuiltinSimulatorRenderer; config?: Record; designMode?: 'design'; className?: string; @@ -173,6 +203,7 @@ export interface IBaseRendererProps { thisRequiredInJSE?: boolean; documentId?: string; getNode?: any; + /** * 设备类型,默认值:'default' */ @@ -213,13 +244,13 @@ export interface DataSource { } export interface IRuntime { + [key: string]: any; Component: IGeneralConstructor; PureComponent: IGeneralConstructor; createElement: (...args: any) => any; createContext: (...args: any) => any; forwardRef: (...args: any) => any; findDOMNode: (...args: any) => any; - [key: string]: any; } export interface IRendererModules { @@ -285,21 +316,22 @@ export interface IBaseRenderComponent { } export interface IRenderComponent { + displayName: string; + defaultProps: IRendererProps; + findDOMNode: (...args: any) => any; + new(props: IRendererProps, context: any): IGeneralComponent & { [x: string]: any; + __getRef: (ref: any) => void; componentDidMount(): Promise; componentDidUpdate(): Promise; componentWillUnmount(): Promise; componentDidCatch(e: any): Promise; shouldComponentUpdate(nextProps: IRendererProps): boolean; - __getRef: (ref: any) => void; isValidComponent(SetComponent: any): any; patchDidCatch(SetComponent: any): void; createElement(SetComponent: any, props: any, children?: any): any; getNotFoundComponent(): any; getFaultComponent(): any; }; - displayName: string; - defaultProps: IRendererProps; - findDOMNode: (...args: any) => any; } diff --git a/packages/renderer-core/tests/hoc/leaf.test.tsx b/packages/renderer-core/tests/hoc/leaf.test.tsx index 86675c771..94d50f87a 100644 --- a/packages/renderer-core/tests/hoc/leaf.test.tsx +++ b/packages/renderer-core/tests/hoc/leaf.test.tsx @@ -324,6 +324,7 @@ describe('mini unit render', () => { it('change component leaf isRoot is true', () => { const TextNode = new Node(textSchema, { isRoot: true, + isRootNode: true, }); nodeMap.set(textSchema.id, TextNode); @@ -356,6 +357,7 @@ describe('mini unit render', () => { id: 'rootId', }, { isRoot: true, + isRootNode: true }), }) }); diff --git a/packages/renderer-core/tests/renderer/base.test.tsx b/packages/renderer-core/tests/renderer/base.test.tsx index fd9b45345..3d19e324b 100644 --- a/packages/renderer-core/tests/renderer/base.test.tsx +++ b/packages/renderer-core/tests/renderer/base.test.tsx @@ -1,5 +1,5 @@ -import React, { Component, createElement, PureComponent, createContext } from 'react'; +import React, { Component, createElement, forwardRef, PureComponent, createContext } from 'react'; const mockGetRenderers = jest.fn(); const mockGetRuntime = jest.fn(); const mockParseExpression = jest.fn(); @@ -59,6 +59,7 @@ describe('Base Render methods', () => { createElement, PureComponent, createContext, + forwardRef, }); RendererClass = baseRendererFactory(); }) diff --git a/packages/renderer-core/tests/utils/node.ts b/packages/renderer-core/tests/utils/node.ts index 9f8eeb420..01c6ab507 100644 --- a/packages/renderer-core/tests/utils/node.ts +++ b/packages/renderer-core/tests/utils/node.ts @@ -40,6 +40,10 @@ export default class Node { isRoot = () => this._isRoot; + get isRootNode () { + return this._isRoot; + }; + // componentMeta() { // return this.componentMeta; // } From da1450ea1abc52f34d9329deeddeca28be187189 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 9 Feb 2023 15:21:28 +0800 Subject: [PATCH 44/89] fix: fix the problem of white screen in custom initialization method --- packages/editor-skeleton/src/layouts/workbench.less | 5 +++++ packages/engine/src/engine-core.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 4e96badcf..34018aa86 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -170,6 +170,11 @@ body { } .lc-workbench { + height: 100%; + display: flex; + flex-direction: column; + background-color: #edeff3; + &.engine-main { height: 100%; display: flex; diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 05033873a..acab43506 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -156,6 +156,8 @@ let engineContainer: HTMLElement; export const version = VERSION_PLACEHOLDER; engineConfig.set('ENGINE_VERSION', version); +registryInnerPlugin(designer, editor, plugins); + export async function init( container?: HTMLElement, options?: IPublicTypeEngineOptions, @@ -179,8 +181,6 @@ export async function init( } engineConfig.setEngineOptions(engineOptions as any); - await registryInnerPlugin(designer, editor, plugins); - await plugins.init(pluginPreference as any); const { Workbench } = common.skeletonCabin; From f44b5aca899f4e02b07faa2e7bf9a9d4530fdcd1 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 9 Feb 2023 15:25:15 +0800 Subject: [PATCH 45/89] feat: added export of SimulatorHost class and simulatorHostSymbol --- packages/engine/src/modules/classes.ts | 2 ++ packages/engine/src/modules/symbols.ts | 2 ++ packages/shell/src/index.ts | 2 ++ 3 files changed, 6 insertions(+) diff --git a/packages/engine/src/modules/classes.ts b/packages/engine/src/modules/classes.ts index 9547eba7a..44aeed965 100644 --- a/packages/engine/src/modules/classes.ts +++ b/packages/engine/src/modules/classes.ts @@ -9,6 +9,7 @@ import { SettingTopEntry, Selection, Prop, + SimulatorHost, } from '@alilc/lowcode-shell'; import { Node as InnerNode } from '@alilc/lowcode-designer'; @@ -24,4 +25,5 @@ export default { InnerNode, Selection, Prop, + SimulatorHost, }; diff --git a/packages/engine/src/modules/symbols.ts b/packages/engine/src/modules/symbols.ts index 7f72f53e0..8ac1d95a8 100644 --- a/packages/engine/src/modules/symbols.ts +++ b/packages/engine/src/modules/symbols.ts @@ -10,6 +10,7 @@ import { settingTopEntrySymbol, designerCabinSymbol, propSymbol, + simulatorHostSymbol, } from '@alilc/lowcode-shell'; export default { @@ -24,4 +25,5 @@ export default { settingTopEntrySymbol, designerCabinSymbol, propSymbol, + simulatorHostSymbol, }; diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index 0307349ab..74d11288e 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -24,6 +24,7 @@ import { Event, Canvas, Workspace, + SimulatorHost, } from './api'; export * from './symbols'; @@ -59,4 +60,5 @@ export { Canvas, Workspace, Clipboard, + SimulatorHost, }; \ No newline at end of file From bf5fece16b7e93cabe775cd12e50152d2cea2f0b Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 9 Feb 2023 15:27:27 +0800 Subject: [PATCH 46/89] feat: fix poroject.onSimulatorHostReady in workspace mode --- packages/designer/src/project/project.ts | 4 ++++ packages/shell/src/api/project.ts | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 082554846..b5a553627 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -369,6 +369,10 @@ export class Project implements IProject { } onSimulatorReady(fn: (args: any) => void): () => void { + if (this._simulator) { + fn(this._simulator); + return () => {}; + } this.emitter.on('lowcode_engine_simulator_ready', fn); return () => { this.emitter.removeListener('lowcode_engine_simulator_ready', fn); diff --git a/packages/shell/src/api/project.ts b/packages/shell/src/api/project.ts index 04feb81f3..a409cbcd5 100644 --- a/packages/shell/src/api/project.ts +++ b/packages/shell/src/api/project.ts @@ -192,12 +192,8 @@ export class Project implements IPublicApiProject { */ onSimulatorHostReady(fn: (host: IPublicApiSimulatorHost) => void): IPublicTypeDisposable { const offFn = this[projectSymbol].onSimulatorReady((simulator: BuiltinSimulatorHost) => { - this[simulatorHostSymbol] = simulator; fn(SimulatorHost.create(simulator)!); }); - if (this[simulatorHostSymbol]) { - fn(SimulatorHost.create(this[simulatorHostSymbol])!); - } return offFn; } From b629ca55e596d6d9ac98f358ea96f36d0a53faa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LeoYuan=20=E8=A2=81=E5=8A=9B=E7=9A=93?= Date: Thu, 9 Feb 2023 11:18:48 +0800 Subject: [PATCH 47/89] fix: getting slot children incorrectly --- packages/designer/src/document/node/props/prop.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 84cceb919..f23c686e7 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -404,7 +404,7 @@ export class Prop implements IProp, IPropParent { id: data.id, name: value.name || value.props?.slotName, params: value.params || value.props?.slotParams, - children: data.value, + children: value.children, } as IPublicTypeSlotSchema; } else { slotSchema = { From ac211009b4ae6c6a45120acdbd2d2718c2a66299 Mon Sep 17 00:00:00 2001 From: Cap <18879890225@163.com> Date: Fri, 10 Feb 2023 14:10:17 +0800 Subject: [PATCH 48/89] =?UTF-8?q?docs():=E4=BF=AE=E6=94=B9=E5=BF=AB?= =?UTF-8?q?=E9=80=9F=E5=BC=80=E5=A7=8B=E6=96=87=E6=A1=A3=E4=B8=AD=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=99=A8=E5=85=A5=E5=8F=A3=E6=96=87=E4=BB=B6=E8=B7=AF?= =?UTF-8?q?=E5=BE=84[/]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 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 6d4f829ec..7999d1701 100644 --- a/docs/docs/guide/quickStart/start.md +++ b/docs/docs/guide/quickStart/start.md @@ -132,7 +132,7 @@ Demo 根据**不同的设计器所需要的物料不同**,分为了下面的 8 介绍下其中主要的内容 -- 设计器入口文件 `source/index.ts` 这个文件做了下述几个事情: +- 设计器入口文件 `src/index.ts` 这个文件做了下述几个事情: - 通过 plugins.register 注册各种插件,包括官方插件 (已发布 npm 包形式的插件) 和 `plugins` 目录下内置的示例插件 - 通过 init 初始化低代码设计器 - plugins 目录,存放的都是示例插件,方便用户从中看到一个插件是如何实现的 From c905aa27c3ace6e756987d1437f8086c4d8fa0a3 Mon Sep 17 00:00:00 2001 From: liujuping Date: Fri, 10 Feb 2023 17:53:16 +0800 Subject: [PATCH 49/89] feat: added detailed definition of some skeleton.add parameters --- packages/editor-skeleton/src/skeleton.ts | 8 +++++--- packages/editor-skeleton/src/types.ts | 10 +++------- packages/shell/src/api/skeleton.ts | 6 +++--- packages/types/src/shell/api/skeleton.ts | 6 +++--- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 90fba2e1b..22f165b1d 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -26,6 +26,7 @@ import { PluginClassSet, IPublicTypeWidgetBaseConfig, IPublicTypeWidgetConfigArea, + IPublicTypeSkeletonConfig, } from '@alilc/lowcode-types'; const logger = new Logger({ level: 'warn', bizName: 'skeleton' }); @@ -66,6 +67,8 @@ export class Skeleton { readonly stages: Area; + readonly widgets: IWidget[] = []; + constructor(readonly editor: Editor, readonly viewName: string = 'global') { makeObservable(this); this.leftArea = new Area( @@ -179,6 +182,7 @@ export class Skeleton { this.setupPlugins(); this.setupEvents(); } + /** * setup events * @@ -277,8 +281,6 @@ export class Skeleton { this.editor.eventBus.emit(event, ...args); } - readonly widgets: IWidget[] = []; - createWidget(config: IPublicTypeWidgetBaseConfig | IWidget) { if (isWidget(config)) { return config; @@ -377,7 +379,7 @@ export class Skeleton { return restConfig; } - add(config: IPublicTypeWidgetBaseConfig, extraConfig?: Record) { + add(config: IPublicTypeSkeletonConfig, extraConfig?: Record) { const parsedConfig = { ...this.parseConfig(config), ...extraConfig, diff --git a/packages/editor-skeleton/src/types.ts b/packages/editor-skeleton/src/types.ts index e8579005c..b3e5a0408 100644 --- a/packages/editor-skeleton/src/types.ts +++ b/packages/editor-skeleton/src/types.ts @@ -6,6 +6,7 @@ import { TipContent, IPublicTypeWidgetConfigArea, IPublicTypeWidgetBaseConfig, + IPublicTypePanelDockPanelProps, } from '@alilc/lowcode-types'; import { IWidget } from './widget/widget'; @@ -63,8 +64,8 @@ export function isDockConfig(obj: any): obj is DockConfig { export interface DialogDockConfig extends IDockBaseConfig { type: 'DialogDock'; dialogProps?: { - title?: IPublicTypeTitleContent; [key: string]: any; + title?: IPublicTypeTitleContent; }; } @@ -85,16 +86,11 @@ export function isPanelConfig(obj: any): obj is PanelConfig { export type HelpTipConfig = string | { url?: string; content?: string | ReactElement }; -export interface PanelProps { +export interface PanelProps extends IPublicTypePanelDockPanelProps { title?: IPublicTypeTitleContent; icon?: any; // 冗余字段 description?: string | IPublicTypeI18nData; - hideTitleBar?: boolean; // panel.props 兼容,不暴露 help?: HelpTipConfig; // 显示问号帮助 - width?: number; // panel.props - height?: number; // panel.props - maxWidth?: number; // panel.props - maxHeight?: number; // panel.props hiddenWhenInit?: boolean; // when this is true, by default will be hidden condition?: (widget: IWidget) => any; onInit?: (widget: IWidget) => any; diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index a60746803..e9bb28328 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, IPublicTypeDisposable, IPublicTypeWidgetBaseConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; +import { IPublicApiSkeleton, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; const innerSkeletonSymbol = Symbol('skeleton'); export class Skeleton implements IPublicApiSkeleton { @@ -38,7 +38,7 @@ export class Skeleton implements IPublicApiSkeleton { * @param extraConfig * @returns */ - add(config: IPublicTypeWidgetBaseConfig, extraConfig?: Record) { + add(config: IPublicTypeSkeletonConfig, extraConfig?: Record) { const configWithName = { ...config, pluginName: this.pluginName, @@ -51,7 +51,7 @@ export class Skeleton implements IPublicApiSkeleton { * @param config * @returns */ - remove(config: IPublicTypeWidgetBaseConfig): number | undefined { + remove(config: IPublicTypeSkeletonConfig): number | undefined { const { area, name } = config; const skeleton = this[skeletonSymbol]; if (!normalizeArea(area)) { diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts index 5c1f69c02..b22b3586c 100644 --- a/packages/types/src/shell/api/skeleton.ts +++ b/packages/types/src/shell/api/skeleton.ts @@ -1,4 +1,4 @@ -import { IPublicTypeDisposable, IPublicTypeWidgetBaseConfig } from '../type'; +import { IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type'; export interface IPublicApiSkeleton { @@ -9,7 +9,7 @@ export interface IPublicApiSkeleton { * @param extraConfig * @returns */ - add(config: IPublicTypeWidgetBaseConfig, extraConfig?: Record): any; + add(config: IPublicTypeSkeletonConfig, extraConfig?: Record): any; /** * 移除一个面板实例 @@ -17,7 +17,7 @@ export interface IPublicApiSkeleton { * @param config * @returns */ - remove(config: IPublicTypeWidgetBaseConfig): number | undefined; + remove(config: IPublicTypeSkeletonConfig): number | undefined; /** * 展示指定 Panel 实例 From 19b997cd5ef652f7cdeef667362b251bdcba0446 Mon Sep 17 00:00:00 2001 From: JackLian Date: Tue, 14 Feb 2023 09:41:12 +0800 Subject: [PATCH 50/89] chore(release): publish 1.1.0 --- 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 ++++++------ 16 files changed, 66 insertions(+), 66 deletions(-) diff --git a/packages/designer/package.json b/packages/designer/package.json index e147ac312..88ca8d173 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.0.18", + "version": "1.1.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.0.18", - "@alilc/lowcode-types": "1.0.18", - "@alilc/lowcode-utils": "1.0.18", + "@alilc/lowcode-editor-core": "1.1.0", + "@alilc/lowcode-types": "1.1.0", + "@alilc/lowcode-utils": "1.1.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 36a1990d9..3bdda2288 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.0.18", + "version": "1.1.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.0.18", - "@alilc/lowcode-utils": "1.0.18", + "@alilc/lowcode-types": "1.1.0", + "@alilc/lowcode-utils": "1.1.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 757fddca0..586d543d5 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.0.18", + "version": "1.1.0", "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.0.18", - "@alilc/lowcode-editor-core": "1.0.18", - "@alilc/lowcode-types": "1.0.18", - "@alilc/lowcode-utils": "1.0.18", + "@alilc/lowcode-designer": "1.1.0", + "@alilc/lowcode-editor-core": "1.1.0", + "@alilc/lowcode-types": "1.1.0", + "@alilc/lowcode-utils": "1.1.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 c72c4a49b..5cc6ab8c9 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.0.18", + "version": "1.1.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.0.18", - "@alilc/lowcode-editor-core": "1.0.18", - "@alilc/lowcode-editor-skeleton": "1.0.18", + "@alilc/lowcode-designer": "1.1.0", + "@alilc/lowcode-editor-core": "1.1.0", + "@alilc/lowcode-editor-skeleton": "1.1.0", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.0.18", - "@alilc/lowcode-plugin-outline-pane": "1.0.18", - "@alilc/lowcode-shell": "1.0.18", - "@alilc/lowcode-utils": "1.0.18", - "@alilc/lowcode-workspace": "1.0.18", + "@alilc/lowcode-plugin-designer": "1.1.0", + "@alilc/lowcode-plugin-outline-pane": "1.1.0", + "@alilc/lowcode-shell": "1.1.0", + "@alilc/lowcode-utils": "1.1.0", + "@alilc/lowcode-workspace": "1.1.0", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 62a9d4661..3e5ac8ed8 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.0.18", + "version": "1.1.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 ab5da4ef6..c9820700a 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.0.18", + "version": "1.1.0", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.0.18", - "@alilc/lowcode-editor-core": "1.0.18", - "@alilc/lowcode-utils": "1.0.18", + "@alilc/lowcode-designer": "1.1.0", + "@alilc/lowcode-editor-core": "1.1.0", + "@alilc/lowcode-utils": "1.1.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 37e7fe3af..5c5eccab0 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.0.18", + "version": "1.1.0", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,10 +13,10 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-designer": "1.0.18", - "@alilc/lowcode-editor-core": "1.0.18", - "@alilc/lowcode-types": "1.0.18", - "@alilc/lowcode-utils": "1.0.18", + "@alilc/lowcode-designer": "1.1.0", + "@alilc/lowcode-editor-core": "1.1.0", + "@alilc/lowcode-types": "1.1.0", + "@alilc/lowcode-utils": "1.1.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 98fc5d868..36276669c 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.0.18", + "version": "1.1.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.0.18", - "@alilc/lowcode-utils": "1.0.18", + "@alilc/lowcode-renderer-core": "1.1.0", + "@alilc/lowcode-utils": "1.1.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 f5e058490..ae042fdda 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.0.18", + "version": "1.1.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.0.18", - "@alilc/lowcode-rax-renderer": "1.0.18", - "@alilc/lowcode-types": "1.0.18", - "@alilc/lowcode-utils": "1.0.18", + "@alilc/lowcode-designer": "1.1.0", + "@alilc/lowcode-rax-renderer": "1.1.0", + "@alilc/lowcode-types": "1.1.0", + "@alilc/lowcode-utils": "1.1.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 6e3e254dd..55fd0074d 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.0.18", + "version": "1.1.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.0.18" + "@alilc/lowcode-renderer-core": "1.1.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 f2d84ee6e..6699b12b3 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.0.18", + "version": "1.1.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.0.18", - "@alilc/lowcode-react-renderer": "1.0.18", - "@alilc/lowcode-types": "1.0.18", - "@alilc/lowcode-utils": "1.0.18", + "@alilc/lowcode-designer": "1.1.0", + "@alilc/lowcode-react-renderer": "1.1.0", + "@alilc/lowcode-types": "1.1.0", + "@alilc/lowcode-utils": "1.1.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 16913aa91..d589ad2ee 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.0.18", + "version": "1.1.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.0.18", - "@alilc/lowcode-utils": "1.0.18", + "@alilc/lowcode-types": "1.1.0", + "@alilc/lowcode-utils": "1.1.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.0.18", + "@alilc/lowcode-designer": "1.1.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 7e2bce3fb..3ff5529b5 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.0.18", + "version": "1.1.0", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,12 +15,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.0.18", - "@alilc/lowcode-editor-core": "1.0.18", - "@alilc/lowcode-editor-skeleton": "1.0.18", - "@alilc/lowcode-types": "1.0.18", - "@alilc/lowcode-utils": "1.0.18", - "@alilc/lowcode-workspace": "1.0.18", + "@alilc/lowcode-designer": "1.1.0", + "@alilc/lowcode-editor-core": "1.1.0", + "@alilc/lowcode-editor-skeleton": "1.1.0", + "@alilc/lowcode-types": "1.1.0", + "@alilc/lowcode-utils": "1.1.0", + "@alilc/lowcode-workspace": "1.1.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 07dbab834..95c7fe887 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.0.18", + "version": "1.1.0", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index ae86e6a40..274fc34c2 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.0.18", + "version": "1.1.0", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.0.18", + "@alilc/lowcode-types": "1.1.0", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 74888c70b..98f175987 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.0.18", + "version": "1.1.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.0.18", - "@alilc/lowcode-editor-core": "1.0.18", - "@alilc/lowcode-editor-skeleton": "1.0.18", - "@alilc/lowcode-types": "1.0.18", - "@alilc/lowcode-utils": "1.0.18", + "@alilc/lowcode-designer": "1.1.0", + "@alilc/lowcode-editor-core": "1.1.0", + "@alilc/lowcode-editor-skeleton": "1.1.0", + "@alilc/lowcode-types": "1.1.0", + "@alilc/lowcode-utils": "1.1.0", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 2f69837002304c39b50fd8a0b4caebeb5a3b5c46 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 14 Feb 2023 12:07:11 +0800 Subject: [PATCH 51/89] fix: fix the problem that the default setter is not registered successfully --- 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 acab43506..f32506303 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -63,7 +63,7 @@ async function registryInnerPlugin(designer: Designer, editor: Editor, plugins: // 注册一批内置插件 await plugins.register(OutlinePlugin, {}, { autoInit: true }); await plugins.register(componentMetaParser(designer)); - await plugins.register(setterRegistry, {}, { autoInit: true }); + await plugins.register(setterRegistry, {}); await plugins.register(defaultPanelRegistry(editor)); await plugins.register(builtinHotkey); await plugins.register(registerDefaults, {}, { autoInit: true }); From 631b5669327436b8fe7870bd474d2690a265ace5 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 14 Feb 2023 16:16:00 +0800 Subject: [PATCH 52/89] feat: fix the problem of plugin outline tree in workspace mode --- .../src/controllers/tree-master.ts | 20 ++++--------------- packages/plugin-outline-pane/src/index.tsx | 4 ++-- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/plugin-outline-pane/src/controllers/tree-master.ts b/packages/plugin-outline-pane/src/controllers/tree-master.ts index 38b723a98..074ed3447 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-master.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-master.ts @@ -11,6 +11,10 @@ export interface ITreeBoard { export class TreeMaster { readonly pluginContext: IPublicModelPluginContext; + private boards = new Set(); + + private treeMap = new Map(); + constructor(pluginContext: IPublicModelPluginContext) { this.pluginContext = pluginContext; let startTime: any; @@ -70,8 +74,6 @@ export class TreeMaster { } } - private boards = new Set(); - addBoard(board: ITreeBoard) { this.boards.add(board); } @@ -84,8 +86,6 @@ export class TreeMaster { // todo others purge } - private treeMap = new Map(); - get currentTree(): Tree | null { const doc = this.pluginContext.project.getCurrentDocument(); if (doc) { @@ -100,15 +100,3 @@ export class TreeMaster { return null; } } - -const mastersMap = new Map(); -export function getTreeMaster(pluginContext: IPublicModelPluginContext): TreeMaster { - const key = pluginContext.project.currentDocument?.id || 'unknown'; - let master = mastersMap.get(key); - if (!master) { - master = new TreeMaster(pluginContext); - pluginContext.logger.info('TreeMaster is created'); - mastersMap.set(key, master); - } - return master; -} diff --git a/packages/plugin-outline-pane/src/index.tsx b/packages/plugin-outline-pane/src/index.tsx index bf3c95b1a..701e46540 100644 --- a/packages/plugin-outline-pane/src/index.tsx +++ b/packages/plugin-outline-pane/src/index.tsx @@ -3,7 +3,7 @@ import { IconOutline } from './icons/outline'; import { IPublicModelPluginContext, IPublicModelDocumentModel } from '@alilc/lowcode-types'; import { enUS, zhCN } from './locale'; import { MasterPaneName, BackupPaneName } from './helper/consts'; -import { getTreeMaster } from './controllers/tree-master'; +import { TreeMaster } from './controllers/tree-master'; import { PaneController } from './controllers/pane-controller'; export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { @@ -26,7 +26,7 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { masterPane: false, backupPane: false, }; - const treeMaster = getTreeMaster(ctx); + const treeMaster = new TreeMaster(ctx); let masterPaneController: PaneController | null = null; let backupPaneController: PaneController | null = null; return { From 5448d0d4a943a0de7f22e78e5ff065c198efca9b Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Tue, 14 Feb 2023 21:02:29 +0900 Subject: [PATCH 53/89] docs: fix typo in modal-nodes-manager.md specfic -> specific --- docs/docs/api/model/modal-nodes-manager.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/api/model/modal-nodes-manager.md b/docs/docs/api/model/modal-nodes-manager.md index acff26734..fbab6a83a 100644 --- a/docs/docs/api/model/modal-nodes-manager.md +++ b/docs/docs/api/model/modal-nodes-manager.md @@ -70,7 +70,7 @@ hideModalNodes(): void; ```typescript /** * 设置指定节点为可见态 - * set specfic model node as visible + * set specific model node as visible * @param node Node */ setVisible(node: IPublicModelNode): void; @@ -85,7 +85,7 @@ setVisible(node: IPublicModelNode): void; ```typescript /** * 设置指定节点为不可见态 - * set specfic model node as invisible + * set specific model node as invisible * @param node Node */ setInvisible(node: IPublicModelNode): void; From 0eac230905e153e8fc43231eb6417efed69e5b83 Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 15 Feb 2023 10:30:06 +0800 Subject: [PATCH 54/89] feat: add IPublicTypeSkeletonConfig type --- .../src/shell/type/widget-base-config.ts | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/types/src/shell/type/widget-base-config.ts b/packages/types/src/shell/type/widget-base-config.ts index 9c2819da3..08c14c8db 100644 --- a/packages/types/src/shell/type/widget-base-config.ts +++ b/packages/types/src/shell/type/widget-base-config.ts @@ -1,8 +1,10 @@ import { IPublicTypeWidgetConfigArea } from './'; export interface IPublicTypeWidgetBaseConfig { + [extra: string]: any; type: string; name: string; + /** * 停靠位置: * - 当 type 为 'Panel' 时自动为 'leftFloatArea'; @@ -13,6 +15,29 @@ export interface IPublicTypeWidgetBaseConfig { props?: Record; content?: any; contentProps?: Record; - // index?: number; - [extra: string]: any; } + +export interface IPublicTypePanelDockConfig extends IPublicTypeWidgetBaseConfig { + type: 'PanelDock'; + + panelProps?: IPublicTypePanelDockPanelProps; +} + +export interface IPublicTypePanelDockPanelProps { + [key: string]: any; + + /** 是否隐藏面板顶部条 */ + hideTitleBar?: boolean; + + width?: number; + + height?: number; + + maxWidth?: number; + + maxHeight?: number; + + area?: IPublicTypeWidgetConfigArea; +} + +export type IPublicTypeSkeletonConfig = IPublicTypePanelDockConfig | IPublicTypeWidgetBaseConfig; \ No newline at end of file From becdfecd5ab2410ee48bcbfbb137aaf41668a441 Mon Sep 17 00:00:00 2001 From: JackLian Date: Wed, 15 Feb 2023 10:36:15 +0800 Subject: [PATCH 55/89] fix: solve ut failure for code-generator --- modules/code-generator/package.json | 5 +++-- packages/types/src/shell/api/canvas.ts | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index 97863584c..ee4ef1970 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -143,5 +143,6 @@ "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" - } -} + }, + "repository": "git@github.com:alibaba/lowcode-engine.git" +} \ No newline at end of file diff --git a/packages/types/src/shell/api/canvas.ts b/packages/types/src/shell/api/canvas.ts index 699e1a35d..b7ad196ce 100644 --- a/packages/types/src/shell/api/canvas.ts +++ b/packages/types/src/shell/api/canvas.ts @@ -1,5 +1,5 @@ -import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, IPublicTypeScrollable, IPublicModelScroller, IPublicModelActiveTracker, IPublicModelClipboard } from '../model'; -import { IPublicTypeLocationData } from '../type'; +import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, IPublicModelScroller, IPublicModelActiveTracker, IPublicModelClipboard } from '../model'; +import { IPublicTypeLocationData, IPublicTypeScrollable } from '../type'; /** * @since v1.1.0 From 8c82fe8f00ffd92931b9ffa6db3f0ee032c07c55 Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 15 Feb 2023 15:24:58 +0800 Subject: [PATCH 56/89] feat: disable global hotkey binding shortcuts in workspace mode --- packages/engine/src/engine-core.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index f32506303..abe378d64 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -195,6 +195,7 @@ export async function init( engineContainer, ); innerWorkspace.setActive(true); + innerHotkey.activate(false); await innerWorkspace.plugins.init(pluginPreference); return; } From 36d1d3bef1d613c06219bab63e578d1939da1c56 Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 15 Feb 2023 15:30:05 +0800 Subject: [PATCH 57/89] feat: support webview type resource in workspace mode --- packages/shell/src/model/resource.ts | 8 +++++ packages/types/src/shell/api/workspace.ts | 2 +- .../src/shell/type/editor-view-config.ts | 3 ++ .../types/src/shell/type/resource-list.ts | 5 +++ .../src/shell/type/resource-type-config.ts | 3 ++ .../types/src/shell/type/resource-type.ts | 4 +-- .../workspace/src/context/base-context.ts | 9 ++++- .../workspace/src/context/view-context.ts | 6 ++-- .../workspace/src/inner-plugins/webview.tsx | 2 +- packages/workspace/src/resource.ts | 18 ++++++++-- packages/workspace/src/view/window-view.tsx | 12 +++++-- packages/workspace/src/window.ts | 35 +++++++++++++++++-- packages/workspace/src/workspace.ts | 26 ++++++++------ 13 files changed, 105 insertions(+), 28 deletions(-) diff --git a/packages/shell/src/model/resource.ts b/packages/shell/src/model/resource.ts index 3fa625ed6..1f037c606 100644 --- a/packages/shell/src/model/resource.ts +++ b/packages/shell/src/model/resource.ts @@ -32,4 +32,12 @@ export class Resource implements IPublicModelResource { get category() { return this[resourceSymbol].category; } + + get children() { + return this[resourceSymbol].children.map((child) => new Resource(child)); + } + + get viewType() { + return this[resourceSymbol].viewType; + } } \ No newline at end of file diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index ee05bbe56..8f8b16e39 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -21,7 +21,7 @@ export interface IPublicApiWorkspace { setResourceList(resourceList: IPublicResourceList): void; /** 资源树列表更新事件 */ - onResourceListChange(fn: (resourceList: IPublicResourceList) => void): () => IPublicTypeDisposable; + onResourceListChange(fn: (resourceList: IPublicResourceList) => void): IPublicTypeDisposable; /** 注册资源 */ registerResourceType(resourceTypeModel: IPublicTypeResourceType): void; diff --git a/packages/types/src/shell/type/editor-view-config.ts b/packages/types/src/shell/type/editor-view-config.ts index 2b36a718a..9bb3b7555 100644 --- a/packages/types/src/shell/type/editor-view-config.ts +++ b/packages/types/src/shell/type/editor-view-config.ts @@ -5,4 +5,7 @@ export interface IPublicEditorViewConfig { /** 资源保存时,会调用视图的钩子 */ save?: () => Promise; + + /** viewType 类型为 'webview' 时渲染的地址 */ + url?: () => Promise; } \ No newline at end of file diff --git a/packages/types/src/shell/type/resource-list.ts b/packages/types/src/shell/type/resource-list.ts index 9b8cc3272..bd5e4a3b0 100644 --- a/packages/types/src/shell/type/resource-list.ts +++ b/packages/types/src/shell/type/resource-list.ts @@ -1,10 +1,15 @@ +import { ReactElement } from 'react'; + export interface IPublicResourceData { resourceName: string; title: string; category?: string; + viewType?: string; + icon?: ReactElement; options: { [key: string]: any; }; + children?: IPublicResourceData[]; } export type IPublicResourceList = IPublicResourceData[]; \ No newline at end of file diff --git a/packages/types/src/shell/type/resource-type-config.ts b/packages/types/src/shell/type/resource-type-config.ts index 93534fea2..e47afb53d 100644 --- a/packages/types/src/shell/type/resource-type-config.ts +++ b/packages/types/src/shell/type/resource-type-config.ts @@ -28,4 +28,7 @@ export interface IPublicResourceTypeConfig { /** 默认标题 */ defaultTitle?: string; + + /** resourceType 类型为 'webview' 时渲染的地址 */ + url?: () => Promise; } diff --git a/packages/types/src/shell/type/resource-type.ts b/packages/types/src/shell/type/resource-type.ts index 64ec85c79..7cfb125aa 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: string; + resourceType: 'editor' | 'webview'; - (ctx: IPublicModelPluginContext): IPublicResourceTypeConfig; + (ctx: IPublicModelPluginContext, options: Object): IPublicResourceTypeConfig; } \ 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 b90a131a3..37ce7fafa 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -28,18 +28,22 @@ import { Canvas, } from '@alilc/lowcode-shell'; import { + IPluginPreferenceMananger, + IPublicApiEvent, + IPublicModelPluginContext, IPublicTypePluginMeta, } from '@alilc/lowcode-types'; import { getLogger } from '@alilc/lowcode-utils'; import { Workspace as InnerWorkspace } from '../workspace'; import { EditorWindow } from '../window'; -export class BasicContext { +export class BasicContext implements IPublicModelPluginContext { skeleton: Skeleton; plugins: Plugins; project: Project; setters: Setters; material: Material; + common: Common; config; event; logger; @@ -53,6 +57,8 @@ export class BasicContext { innerHotkey: InnerHotkey; innerPlugins: LowCodePluginManager; canvas: Canvas; + pluginEvent: IPublicApiEvent; + preference: IPluginPreferenceMananger; constructor(innerWorkspace: InnerWorkspace, viewName: string, public editorWindow?: EditorWindow) { const editor = new Editor(viewName, true); @@ -101,6 +107,7 @@ export class BasicContext { this.designer = designer; this.canvas = canvas; const common = new Common(editor, innerSkeleton); + this.common = common; let plugins: any; const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { diff --git a/packages/workspace/src/context/view-context.ts b/packages/workspace/src/context/view-context.ts index 55bbf2d57..d14549667 100644 --- a/packages/workspace/src/context/view-context.ts +++ b/packages/workspace/src/context/view-context.ts @@ -1,4 +1,4 @@ -import { makeObservable, obx } from '@alilc/lowcode-editor-core'; +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'; @@ -17,7 +17,7 @@ export class Context extends BasicContext { @obx isInit: boolean = false; - get active() { + @computed get active() { return this._activate; } @@ -33,7 +33,7 @@ export class Context extends BasicContext { this.isInit = true; }); - constructor(public workspace: InnerWorkspace, public editorWindow: EditorWindow, public editorView: IPublicTypeEditorView, options: Object) { + constructor(public workspace: InnerWorkspace, public editorWindow: EditorWindow, 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/inner-plugins/webview.tsx b/packages/workspace/src/inner-plugins/webview.tsx index be9c15f8b..de40bb521 100644 --- a/packages/workspace/src/inner-plugins/webview.tsx +++ b/packages/workspace/src/inner-plugins/webview.tsx @@ -1,6 +1,6 @@ import { IPublicModelPluginContext } from '@alilc/lowcode-types'; -function DesignerView(props: { +export function DesignerView(props: { url: string; viewName: string; }) { diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index effa6abee..119bcc488 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -17,12 +17,16 @@ export class Resource implements IPublicModelResource { return this.resourceType.name; } + get viewType() { + return this.resourceData.viewType; + } + get description() { return this.resourceTypeInstance?.description; } get icon() { - return this.resourceTypeInstance?.icon; + return this.resourceData.icon || this.resourceTypeInstance?.icon; } get type() { @@ -45,9 +49,13 @@ export class Resource implements IPublicModelResource { return this.context.innerSkeleton; } - constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, workspace: InnerWorkSpace) { + get children(): Resource[] { + return this.resourceData?.children?.map(d => new Resource(d, this.resourceType, this.workspace)) || []; + } + + constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, readonly workspace: InnerWorkSpace) { this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`); - this.resourceTypeInstance = resourceType.resourceTypeModel(this.context, {}); + this.resourceTypeInstance = resourceType.resourceTypeModel(this.context, this.options); this.init(); if (this.resourceTypeInstance.editorViews) { this.resourceTypeInstance.editorViews.forEach((d: any) => { @@ -68,6 +76,10 @@ export class Resource implements IPublicModelResource { return await this.resourceTypeInstance.import?.(schema); } + async url() { + return await this.resourceTypeInstance.url?.(); + } + async save(value: any) { return await this.resourceTypeInstance.save?.(value); } diff --git a/packages/workspace/src/view/window-view.tsx b/packages/workspace/src/view/window-view.tsx index 396582a02..c468b084d 100644 --- a/packages/workspace/src/view/window-view.tsx +++ b/packages/workspace/src/view/window-view.tsx @@ -3,6 +3,7 @@ import { ResourceView } from './resource-view'; import { engineConfig, observer } from '@alilc/lowcode-editor-core'; import { EditorWindow } from '../window'; import { BuiltinLoading } from '@alilc/lowcode-designer'; +import { DesignerView } from '../inner-plugins/webview'; @observer export class WindowView extends PureComponent<{ @@ -11,16 +12,21 @@ export class WindowView extends PureComponent<{ }, any> { render() { const { active } = this.props; - const { editorView, resource } = this.props.window; - if (!editorView) { + const { resource, initReady, url } = this.props.window; + + if (!initReady) { const Loading = engineConfig.get('loadingComponent', BuiltinLoading); return ( -

+
); } + if (resource.type === 'webview' && url) { + return ; + } + return (
= new Map(); - constructor(readonly resource: Resource, readonly workspace: Workspace, public title: string | undefined = '', private options: Object = {}) { + @obx initReady = false; + + constructor(readonly resource: Resource, readonly workspace: Workspace, private config: IWindowCOnfig) { makeObservable(this); this.init(); + this.title = config.title; this.icon = resource.icon; } @@ -48,11 +61,16 @@ export class EditorWindow { async init() { await this.initViewTypes(); await this.execViewTypesInit(); + this.url = await this.resource.url(); this.setDefaultViewType(); + this.initReady = true; } initViewTypes = async () => { const editorViews = this.resource.editorViews; + if (!editorViews) { + return; + } for (let i = 0; i < editorViews.length; i++) { const name = editorViews[i].viewName; await this.initViewType(name); @@ -72,6 +90,9 @@ export class EditorWindow { execViewTypesInit = async () => { const editorViews = this.resource.editorViews; + if (!editorViews) { + return; + } for (let i = 0; i < editorViews.length; i++) { const name = editorViews[i].viewName; this.changeViewType(name); @@ -80,15 +101,19 @@ export class EditorWindow { }; setDefaultViewType = () => { - this.changeViewType(this.resource.defaultViewType); + this.changeViewType(this.config.viewType ?? this.resource.defaultViewType); }; + get resourceType() { + return this.resource.resourceType.type; + } + initViewType = async (name: string) => { const viewInfo = this.resource.getEditorView(name); if (this.editorViews.get(name)) { return; } - const editorView = new Context(this.workspace, this, viewInfo as any, this.options); + const editorView = new Context(this.workspace, this, viewInfo as any, this.config.options); this.editorViews.set(name, editorView); }; @@ -96,6 +121,10 @@ export class EditorWindow { this.editorView?.setActivate(false); this.editorView = this.editorViews.get(name)!; + if (!this.editorView) { + return; + } + if (!ignoreEmit) { this.emitter.emit('window.change.view.type', name); } diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 509ca9d9d..0b7181cd8 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -46,7 +46,7 @@ export class Workspace implements IPublicApiWorkspace { return null; } - windows: EditorWindow[] = []; + @obx.ref windows: EditorWindow[] = []; editorWindowMap: Map = new Map(); @@ -71,7 +71,9 @@ export class Workspace implements IPublicApiWorkspace { } const title = this.defaultResourceType.name; const resource = new Resource({}, this.defaultResourceType, this); - this.window = new EditorWindow(resource, this, title); + this.window = new EditorWindow(resource, this, { + title, + }); this.editorWindowMap.set(this.window.id, this.window); this.windows.push(this.window); this.emitChangeWindow(); @@ -83,13 +85,11 @@ export class Workspace implements IPublicApiWorkspace { } async registerResourceType(resourceTypeModel: IPublicTypeResourceType): Promise { - if (resourceTypeModel.resourceType === 'editor') { - const resourceType = new ResourceType(resourceTypeModel); - this.resourceTypeMap.set(resourceTypeModel.resourceName, resourceType); + const resourceType = new ResourceType(resourceTypeModel); + this.resourceTypeMap.set(resourceTypeModel.resourceName, resourceType); - if (!this.window && this.defaultResourceType) { - this.initWindow(); - } + if (!this.window && this.defaultResourceType) { + this.initWindow(); } } @@ -150,7 +150,7 @@ export class Workspace implements IPublicApiWorkspace { openEditorWindow(name: string, title: string, options: Object, viewType?: string) { const resourceType = this.resourceTypeMap.get(name); if (!resourceType) { - console.error(`${name} is not available`); + console.error(`${name} resourceType is not available`); return; } const filterWindows = this.windows.filter(d => (d.resource.name === name && d.resource.title == title)); @@ -164,8 +164,12 @@ export class Workspace implements IPublicApiWorkspace { title, options, }, resourceType, this); - this.window = new EditorWindow(resource, this, title, options); - this.windows.push(this.window); + this.window = new EditorWindow(resource, this, { + title, + options, + viewType, + }); + this.windows = [...this.windows, this.window]; this.editorWindowMap.set(this.window.id, this.window); this.emitChangeWindow(); this.emitChangeActiveWindow(); From 9d83b8b5b9a916b9598e37d713fd4d2ffebbdff9 Mon Sep 17 00:00:00 2001 From: JackLian Date: Wed, 15 Feb 2023 17:07:04 +0800 Subject: [PATCH 58/89] docs: improve doc for plugin related apis --- docs/docs/api/plugins.md | 51 ++++++++++++++----- packages/designer/src/plugin/plugin-types.ts | 2 +- packages/shell/src/model/plugin-instance.ts | 2 +- packages/types/src/shell/api/plugins.ts | 25 ++++++--- .../types/src/shell/model/plugin-context.ts | 19 +++++-- .../types/src/shell/model/plugin-instance.ts | 27 ++++++++-- 6 files changed, 98 insertions(+), 28 deletions(-) diff --git a/docs/docs/api/plugins.md b/docs/docs/api/plugins.md index 58be1fde0..e35411d3a 100644 --- a/docs/docs/api/plugins.md +++ b/docs/docs/api/plugins.md @@ -118,11 +118,13 @@ import { IPublicModelPluginContext } from '@alilc/lowcode-types'; const BuiltinPluginRegistry = (ctx: IPublicModelPluginContext, options: any) => { return { async init() { - // 1.0.4 之后的传值方式,通过 register(xxx, options) - // 取值通过 options + // 直接传值方式: + // 通过 register(xxx, options) 传入 + // 通过 options 取出 - // 1.0.4 之前的传值方式,通过 init(..., preference) - // 取值通过 ctx.preference.getValue() + // 引擎初始化时也可以设置某插件的全局配置项: + // 通过 engine.init(..., preference) 传入 + // 通过 ctx.preference.getValue() 取出 }, }; } @@ -155,7 +157,6 @@ BuiltinPluginRegistry.meta = { }, } -// 从 1.0.4 开始,支持直接在 pluginCreator 的第二个参数 options 获取入参 await plugins.register(BuiltinPluginRegistry, { key1: 'abc', key5: 'willNotPassToPlugin' }); ``` @@ -164,8 +165,11 @@ await plugins.register(BuiltinPluginRegistry, { key1: 'abc', key5: 'willNotPassT 获取指定插件 ```typescript -function get(pluginName: string): IPublicModelPluginInstance; - +/** + * 获取指定插件 + * get plugin instance by name + */ +get(pluginName: string): IPublicModelPluginInstance | null; ``` 关联模型 [IPublicModelPluginInstance](./model/plugin-instance) @@ -175,8 +179,11 @@ function get(pluginName: string): IPublicModelPluginInstance; 获取所有的插件实例 ```typescript -function getAll(): IPublicModelPluginInstance[]; - +/** + * 获取所有的插件实例 + * get all plugin instances + */ +getAll(): IPublicModelPluginInstance[]; ``` 关联模型 [IPublicModelPluginInstance](./model/plugin-instance) @@ -186,8 +193,11 @@ function getAll(): IPublicModelPluginInstance[]; 判断是否有指定插件 ```typescript -function has(pluginName: string): boolean; - +/** + * 判断是否有指定插件 + * check if plugin with certain name exists + */ +has(pluginName: string): boolean; ``` ### delete @@ -195,8 +205,25 @@ function has(pluginName: string): boolean; 删除指定插件 ```typescript -function delete(pluginName: string): void; +/** + * 删除指定插件 + * delete plugin instance by name + */ +delete(pluginName: string): void; +``` +### getPluginPreference + +引擎初始化时可以提供全局配置给到各插件,通过这个方法可以获得本插件对应的配置 + +```typescript +/** + * 引擎初始化时可以提供全局配置给到各插件,通过这个方法可以获得本插件对应的配置 + * use this to get preference config for this plugin when engine.init() called + */ +getPluginPreference( + pluginName: string, + ): Record | null | undefined; ``` ## 相关类型定义 diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index 8c246a5d2..837fae4b1 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -26,12 +26,12 @@ export interface ILowCodePluginRuntimeCore { disabled: boolean; config: IPublicTypePluginConfig; logger: IPublicApiLogger; + meta: IPublicTypePluginMeta; init(forceInit?: boolean): void; isInited(): boolean; destroy(): void; toProxy(): any; setDisabled(flag: boolean): void; - meta: IPublicTypePluginMeta; } interface ILowCodePluginRuntimeExportsAccessor { diff --git a/packages/shell/src/model/plugin-instance.ts b/packages/shell/src/model/plugin-instance.ts index 47a619482..156ec7579 100644 --- a/packages/shell/src/model/plugin-instance.ts +++ b/packages/shell/src/model/plugin-instance.ts @@ -28,4 +28,4 @@ export class PluginInstance implements IPublicModelPluginInstance { get meta() { return this[pluginInstanceSymbol].meta; } -} \ No newline at end of file +} diff --git a/packages/types/src/shell/api/plugins.ts b/packages/types/src/shell/api/plugins.ts index 32e13c3b6..518362b97 100644 --- a/packages/types/src/shell/api/plugins.ts +++ b/packages/types/src/shell/api/plugins.ts @@ -20,21 +20,34 @@ export interface IPublicApiPlugins { ): Promise; /** - * @deprecated use options instead + * 引擎初始化时可以提供全局配置给到各插件,通过这个方法可以获得本插件对应的配置 + * use this to get preference config for this plugin when engine.init() called */ getPluginPreference( pluginName: string, ): Record | null | undefined; - /** 获取指定插件 */ + /** + * 获取指定插件 + * 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; -} \ 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 cc989ac76..ae7ef8bbb 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -14,11 +14,26 @@ import { 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 + */ + preference: IPluginPreferenceMananger; get skeleton(): IPublicApiSkeleton; get hotkey(): IPublicApiHotkey; get setters(): IPublicApiSetters; get config(): IPublicModelEngineConfig; get material(): IPublicApiMaterial; + /** * this event works globally, can be used between plugins and engine. */ @@ -33,8 +48,6 @@ export interface IPublicModelPluginContext { */ get pluginEvent(): IPublicApiEvent; get canvas(): IPublicApiCanvas; - preference: IPluginPreferenceMananger; - [key: string]: any; } /** @@ -44,4 +57,4 @@ export interface IPublicModelPluginContext { */ export interface ILowCodePluginContext extends IPublicModelPluginContext { -} \ No newline at end of file +} diff --git a/packages/types/src/shell/model/plugin-instance.ts b/packages/types/src/shell/model/plugin-instance.ts index 7855d903b..88904205d 100644 --- a/packages/types/src/shell/model/plugin-instance.ts +++ b/packages/types/src/shell/model/plugin-instance.ts @@ -1,11 +1,28 @@ import { IPublicTypePluginMeta } from '../type/plugin-meta'; export interface IPublicModelPluginInstance { - pluginName: string; - - dep: string[]; + /** + * 是否 disable + * current plugin instance is disabled or not + */ disabled: boolean; - meta: IPublicTypePluginMeta; -} \ No newline at end of file + /** + * 插件名称 + * plugin name + */ + get pluginName(): string; + + /** + * 依赖信息,依赖的其他插件 + * depenency info + */ + get dep(): string[]; + + /** + * 插件配置元数据 + * meta info of this plugin + */ + get meta(): IPublicTypePluginMeta; +} From 18eeff953a687ae756433696b99e0c442ba99ea7 Mon Sep 17 00:00:00 2001 From: JackLian Date: Wed, 15 Feb 2023 17:23:11 +0800 Subject: [PATCH 59/89] chore(release): publish 1.1.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 | 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 dc8950db4..2e2f55ad3 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.0", + "version": "1.1.1", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 88ca8d173..b76dc8b02 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.0", + "version": "1.1.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.1.0", - "@alilc/lowcode-types": "1.1.0", - "@alilc/lowcode-utils": "1.1.0", + "@alilc/lowcode-editor-core": "1.1.1", + "@alilc/lowcode-types": "1.1.1", + "@alilc/lowcode-utils": "1.1.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 3bdda2288..09b7d96af 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.0", + "version": "1.1.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.1.0", - "@alilc/lowcode-utils": "1.1.0", + "@alilc/lowcode-types": "1.1.1", + "@alilc/lowcode-utils": "1.1.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 586d543d5..45e4b1fd0 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.0", + "version": "1.1.1", "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.0", - "@alilc/lowcode-editor-core": "1.1.0", - "@alilc/lowcode-types": "1.1.0", - "@alilc/lowcode-utils": "1.1.0", + "@alilc/lowcode-designer": "1.1.1", + "@alilc/lowcode-editor-core": "1.1.1", + "@alilc/lowcode-types": "1.1.1", + "@alilc/lowcode-utils": "1.1.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 5cc6ab8c9..23014a38b 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.0", + "version": "1.1.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.1.0", - "@alilc/lowcode-editor-core": "1.1.0", - "@alilc/lowcode-editor-skeleton": "1.1.0", + "@alilc/lowcode-designer": "1.1.1", + "@alilc/lowcode-editor-core": "1.1.1", + "@alilc/lowcode-editor-skeleton": "1.1.1", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.0", - "@alilc/lowcode-plugin-outline-pane": "1.1.0", - "@alilc/lowcode-shell": "1.1.0", - "@alilc/lowcode-utils": "1.1.0", - "@alilc/lowcode-workspace": "1.1.0", + "@alilc/lowcode-plugin-designer": "1.1.1", + "@alilc/lowcode-plugin-outline-pane": "1.1.1", + "@alilc/lowcode-shell": "1.1.1", + "@alilc/lowcode-utils": "1.1.1", + "@alilc/lowcode-workspace": "1.1.1", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 3e5ac8ed8..d9658e8d0 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.0", + "version": "1.1.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 c9820700a..bd7ac8261 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.0", + "version": "1.1.1", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.0", - "@alilc/lowcode-editor-core": "1.1.0", - "@alilc/lowcode-utils": "1.1.0", + "@alilc/lowcode-designer": "1.1.1", + "@alilc/lowcode-editor-core": "1.1.1", + "@alilc/lowcode-utils": "1.1.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 5c5eccab0..af974b044 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.0", + "version": "1.1.1", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,10 +13,10 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-designer": "1.1.0", - "@alilc/lowcode-editor-core": "1.1.0", - "@alilc/lowcode-types": "1.1.0", - "@alilc/lowcode-utils": "1.1.0", + "@alilc/lowcode-designer": "1.1.1", + "@alilc/lowcode-editor-core": "1.1.1", + "@alilc/lowcode-types": "1.1.1", + "@alilc/lowcode-utils": "1.1.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 36276669c..ba03dfb9b 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.0", + "version": "1.1.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.1.0", - "@alilc/lowcode-utils": "1.1.0", + "@alilc/lowcode-renderer-core": "1.1.1", + "@alilc/lowcode-utils": "1.1.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 ae042fdda..a196120c4 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.0", + "version": "1.1.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.1.0", - "@alilc/lowcode-rax-renderer": "1.1.0", - "@alilc/lowcode-types": "1.1.0", - "@alilc/lowcode-utils": "1.1.0", + "@alilc/lowcode-designer": "1.1.1", + "@alilc/lowcode-rax-renderer": "1.1.1", + "@alilc/lowcode-types": "1.1.1", + "@alilc/lowcode-utils": "1.1.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 55fd0074d..bcc28aa11 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.0", + "version": "1.1.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.1.0" + "@alilc/lowcode-renderer-core": "1.1.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 6699b12b3..278b6f508 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.0", + "version": "1.1.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.1.0", - "@alilc/lowcode-react-renderer": "1.1.0", - "@alilc/lowcode-types": "1.1.0", - "@alilc/lowcode-utils": "1.1.0", + "@alilc/lowcode-designer": "1.1.1", + "@alilc/lowcode-react-renderer": "1.1.1", + "@alilc/lowcode-types": "1.1.1", + "@alilc/lowcode-utils": "1.1.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 d589ad2ee..0f4b9132e 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.0", + "version": "1.1.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.1.0", - "@alilc/lowcode-utils": "1.1.0", + "@alilc/lowcode-types": "1.1.1", + "@alilc/lowcode-utils": "1.1.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.1.0", + "@alilc/lowcode-designer": "1.1.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 3ff5529b5..4566424f0 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.0", + "version": "1.1.1", "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.0", - "@alilc/lowcode-editor-core": "1.1.0", - "@alilc/lowcode-editor-skeleton": "1.1.0", - "@alilc/lowcode-types": "1.1.0", - "@alilc/lowcode-utils": "1.1.0", - "@alilc/lowcode-workspace": "1.1.0", + "@alilc/lowcode-designer": "1.1.1", + "@alilc/lowcode-editor-core": "1.1.1", + "@alilc/lowcode-editor-skeleton": "1.1.1", + "@alilc/lowcode-types": "1.1.1", + "@alilc/lowcode-utils": "1.1.1", + "@alilc/lowcode-workspace": "1.1.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 95c7fe887..a023cdd3f 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.0", + "version": "1.1.1", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 274fc34c2..4c351236f 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.0", + "version": "1.1.1", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.0", + "@alilc/lowcode-types": "1.1.1", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 98f175987..54b468acb 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.0", + "version": "1.1.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.1.0", - "@alilc/lowcode-editor-core": "1.1.0", - "@alilc/lowcode-editor-skeleton": "1.1.0", - "@alilc/lowcode-types": "1.1.0", - "@alilc/lowcode-utils": "1.1.0", + "@alilc/lowcode-designer": "1.1.1", + "@alilc/lowcode-editor-core": "1.1.1", + "@alilc/lowcode-editor-skeleton": "1.1.1", + "@alilc/lowcode-types": "1.1.1", + "@alilc/lowcode-utils": "1.1.1", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 69070441c0eb554c87f9503ab6ca4b8587785291 Mon Sep 17 00:00:00 2001 From: test005 Date: Thu, 16 Feb 2023 10:01:35 +0800 Subject: [PATCH 60/89] fix: fix componentsMap spell mistake --- packages/designer/src/project/project.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index b5a553627..42ba0b4fc 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -115,13 +115,13 @@ export class Project implements IProject { private getComponentsMap(): IPublicTypeComponentsMap { return this.documents.reduce(( - compomentsMap: IPublicTypeComponentsMap, + componentsMap: IPublicTypeComponentsMap, curDoc: DocumentModel, ) => { const curComponentsMap = curDoc.getComponentsMap(); if (Array.isArray(curComponentsMap)) { curComponentsMap.forEach((item) => { - const found = compomentsMap.find((eItem) => { + const found = componentsMap.find((eItem) => { if ( isProCodeComponentType(eItem) && isProCodeComponentType(item) && @@ -138,10 +138,10 @@ export class Project implements IProject { return false; }); if (found) return; - compomentsMap.push(item); + componentsMap.push(item); }); } - return compomentsMap; + return componentsMap; }, [] as IPublicTypeComponentsMap); } From f1519b7f5cf1d9750215d2badc7c637e0fbae59e Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 16 Feb 2023 10:50:44 +0800 Subject: [PATCH 61/89] feat: remove extra classname --- packages/workspace/src/view/window-view.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/workspace/src/view/window-view.tsx b/packages/workspace/src/view/window-view.tsx index c468b084d..65378bc9c 100644 --- a/packages/workspace/src/view/window-view.tsx +++ b/packages/workspace/src/view/window-view.tsx @@ -17,7 +17,7 @@ export class WindowView extends PureComponent<{ if (!initReady) { const Loading = engineConfig.get('loadingComponent', BuiltinLoading); return ( -
+
); From 762189cc565418f57edde2b22e8b95b486a1555c Mon Sep 17 00:00:00 2001 From: JackLian Date: Thu, 16 Feb 2023 12:10:29 +0800 Subject: [PATCH 62/89] chore: publish docs 1.0.20 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 3a07ecd67..c72e1804e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.0.18", + "version": "1.0.20", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From a4c93c43b9ee955e632e068063a032d5dd4aff55 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 16 Feb 2023 14:24:36 +0800 Subject: [PATCH 63/89] fix: fix issues with build-components --- packages/utils/src/build-components.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/utils/src/build-components.ts b/packages/utils/src/build-components.ts index 9ed278996..af4c64699 100644 --- a/packages/utils/src/build-components.ts +++ b/packages/utils/src/build-components.ts @@ -36,7 +36,7 @@ export function getSubComponent(library: any, paths: string[]) { const key = paths[i]!; let ex: any; try { - component = library[key]; + component = library[key] || component; } catch (e) { ex = e; component = null; @@ -51,9 +51,6 @@ export function getSubComponent(library: any, paths: string[]) { } library = component; i++; - if (isReactComponent(component)) { - break; - } } return component; } From 6753bf660b3a3b9c66684f8f8cdd125d35a1d857 Mon Sep 17 00:00:00 2001 From: jn Date: Thu, 9 Feb 2023 20:37:21 +0800 Subject: [PATCH 64/89] fix: designer i18n locale is not correct --- 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 b4439f4fe..054628c5f 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -830,7 +830,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { } } - const handleI18nData = (innerProps: any) => innerProps[innerProps.use || 'zh-CN']; + const handleI18nData = (innerProps: any) => innerProps[innerProps.use || (this.getLocale && this.getLocale()) || 'zh-CN']; // @LEGACY 兼容老平台设计态 i18n 数据 if (isI18nData(props)) { From f3f7703f98302e6bfab65409a53f512c4a998553 Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 20 Feb 2023 10:36:57 +0800 Subject: [PATCH 65/89] chore(release): publish 1.1.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 | 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 2e2f55ad3..8ca861e34 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.1", + "version": "1.1.2", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index b76dc8b02..663e5d91c 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.1", + "version": "1.1.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.1.1", - "@alilc/lowcode-types": "1.1.1", - "@alilc/lowcode-utils": "1.1.1", + "@alilc/lowcode-editor-core": "1.1.2", + "@alilc/lowcode-types": "1.1.2", + "@alilc/lowcode-utils": "1.1.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 09b7d96af..a3e799761 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.1", + "version": "1.1.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.1.1", - "@alilc/lowcode-utils": "1.1.1", + "@alilc/lowcode-types": "1.1.2", + "@alilc/lowcode-utils": "1.1.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 45e4b1fd0..3477ba1d5 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.1", + "version": "1.1.2", "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.1", - "@alilc/lowcode-editor-core": "1.1.1", - "@alilc/lowcode-types": "1.1.1", - "@alilc/lowcode-utils": "1.1.1", + "@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", "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 23014a38b..6edbe7ac0 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.1", + "version": "1.1.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.1.1", - "@alilc/lowcode-editor-core": "1.1.1", - "@alilc/lowcode-editor-skeleton": "1.1.1", + "@alilc/lowcode-designer": "1.1.2", + "@alilc/lowcode-editor-core": "1.1.2", + "@alilc/lowcode-editor-skeleton": "1.1.2", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.1", - "@alilc/lowcode-plugin-outline-pane": "1.1.1", - "@alilc/lowcode-shell": "1.1.1", - "@alilc/lowcode-utils": "1.1.1", - "@alilc/lowcode-workspace": "1.1.1", + "@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", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index d9658e8d0..92f19ca67 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.1", + "version": "1.1.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 bd7ac8261..fd0a246a6 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.1", + "version": "1.1.2", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.1", - "@alilc/lowcode-editor-core": "1.1.1", - "@alilc/lowcode-utils": "1.1.1", + "@alilc/lowcode-designer": "1.1.2", + "@alilc/lowcode-editor-core": "1.1.2", + "@alilc/lowcode-utils": "1.1.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 af974b044..5a9147a8d 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.1", + "version": "1.1.2", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,10 +13,10 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-designer": "1.1.1", - "@alilc/lowcode-editor-core": "1.1.1", - "@alilc/lowcode-types": "1.1.1", - "@alilc/lowcode-utils": "1.1.1", + "@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", "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 ba03dfb9b..d6270e1f8 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.1", + "version": "1.1.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.1.1", - "@alilc/lowcode-utils": "1.1.1", + "@alilc/lowcode-renderer-core": "1.1.2", + "@alilc/lowcode-utils": "1.1.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 a196120c4..2ff493c2e 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.1", + "version": "1.1.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.1.1", - "@alilc/lowcode-rax-renderer": "1.1.1", - "@alilc/lowcode-types": "1.1.1", - "@alilc/lowcode-utils": "1.1.1", + "@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", "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 bcc28aa11..7ac933647 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.1", + "version": "1.1.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.1.1" + "@alilc/lowcode-renderer-core": "1.1.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 278b6f508..7c5868f3c 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.1", + "version": "1.1.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.1.1", - "@alilc/lowcode-react-renderer": "1.1.1", - "@alilc/lowcode-types": "1.1.1", - "@alilc/lowcode-utils": "1.1.1", + "@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", "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 0f4b9132e..deb30be11 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.1", + "version": "1.1.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.1.1", - "@alilc/lowcode-utils": "1.1.1", + "@alilc/lowcode-types": "1.1.2", + "@alilc/lowcode-utils": "1.1.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.1.1", + "@alilc/lowcode-designer": "1.1.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 4566424f0..a475a05bf 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.1", + "version": "1.1.2", "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.1", - "@alilc/lowcode-editor-core": "1.1.1", - "@alilc/lowcode-editor-skeleton": "1.1.1", - "@alilc/lowcode-types": "1.1.1", - "@alilc/lowcode-utils": "1.1.1", - "@alilc/lowcode-workspace": "1.1.1", + "@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", "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 a023cdd3f..d36e7fb21 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.1", + "version": "1.1.2", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 4c351236f..7ed3787a7 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.1", + "version": "1.1.2", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.1", + "@alilc/lowcode-types": "1.1.2", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 54b468acb..4bd99eaf9 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.1", + "version": "1.1.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.1.1", - "@alilc/lowcode-editor-core": "1.1.1", - "@alilc/lowcode-editor-skeleton": "1.1.1", - "@alilc/lowcode-types": "1.1.1", - "@alilc/lowcode-utils": "1.1.1", + "@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", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From bbe438cf83c8c92ba7c2896eff4d27cd991525ea Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 20 Feb 2023 14:06:00 +0800 Subject: [PATCH 66/89] 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 228e1cf98..499750282 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 000000000..5662aa12c --- /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 000000000..216f3db42 --- /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 000000000..ca91bb230 --- /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 67/89] 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 c1a7ddee8..f43134c75 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 ae7ef8bbb..5d97b5472 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 68/89] 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 62aeddbba..9cb114bee 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 054628c5f..311493736 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 560b5924b..5132997f0 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 58d5c0093..4be33f5c1 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 9875f8d73..9ba49c723 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 8d619737c..4e44dd312 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 3d19e324b..63c5cfbb2 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 69/89] 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 c8bdf52e8..50e2819d6 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 3c3cee9d3..d523a0d35 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 f23c686e7..f16f24c84 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 948411c89..2977da1d8 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 70/89] 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 000000000..854aa1a04 --- /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 91ef33adb..12ef865ec 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 abe378d64..ea0554cad 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 74d11288e..aed56fb95 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 000000000..d84120878 --- /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 f2805342e..8e18c36bb 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 dac981e96..91ad609ac 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 2b17d7e72..c9473cd12 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 71/89] 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 606c7fc08..787b6bc9b 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 72/89] 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 10488a733..219e6bbc1 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 d370a797b..12a9e75ba 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 0192268bc..4d1cc0a22 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 d18bf78a3..0379194bf 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 73/89] 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 f16f24c84..81675aa57 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 787b6bc9b..932733b1a 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 68e66fc02..e8c7ce52e 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 65a040390fe516bfef154cdb8c35fbf1a30f63e7 Mon Sep 17 00:00:00 2001 From: za-liyong002 Date: Mon, 27 Feb 2023 23:48:09 +0800 Subject: [PATCH 74/89] =?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 12ef865ec..ef889e727 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 5fa6bb894..062b7e669 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 75/89] 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 | 181 +++++++++++------- .../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, 454 insertions(+), 302 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 1ec3834e6..f3ebedbbe 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 c361b21c9..2691a8971 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 c39e439aa..d40082d82 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 3a6082d5c..568639c37 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 08c168091..ccf26e325 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 16a80dbc4..1c36f8e1b 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 9600e8008..63fe094db 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: Designer; + readonly designer: IDesigner; - /** - * 选区控制 - */ - 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 585b52f5f..8e04f72fc 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 12a9e75ba..ff85b2231 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 7739bcf1c..efa860c8d 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 81675aa57..90d72668a 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 bcbf778ea..2456de759 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 42ba0b4fc..6516d67aa 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 5a2fb8efc..32b9233c9 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 85d44c2cc..b1015b8de 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 ba2412e89..9b407de5c 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 ff2124bec..073083a65 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 369680fd6..f2b0032a7 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 9bc215f9a..ec6320ad2 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 72d20ceb0..99086d20d 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 bfbba50ec..07656c070 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 0379194bf..ecab5fd33 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 70c92016b..dd6db71bf 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 9c862a008..3c390a8cf 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 3b2fdb2f5..317a49837 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 ec375cbc0..21f14b2bc 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 32b40f157..bd09e7b90 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 2977da1d8..79466389e 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 918074c58..7ee0228c9 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 ddca72829..ac8a05aa3 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 6f17abf23..4b08f67fa 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 79b28fb58..1b6c131e9 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 9fe27b29d..14c2e2f74 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 76/89] 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 a625e9424..39f978a70 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 50e2819d6..c073e2854 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 d523a0d35..ed20964ba 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 1c36f8e1b..5c3c1c250 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 8972c4ad7..0b470557b 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 05c7b19cb..bd3f795eb 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 88861cac4..94d39a522 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 ddcd16471..7947baffa 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 77/89] 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 1293cec2e..66a514364 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 78/89] 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 f3ebedbbe..4f9620d3d 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 9af2dbd09..eb2084508 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 b7ad196ce..6cb3df9fc 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 19e42e4a8..7771aa6ba 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 8f8b16e39..c1be4cb7e 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 ecab5fd33..f2be13250 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 58dfb3045..2e7dec70f 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 37ce7fafa..b67842fe8 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 0b7181cd8..f7d49ed49 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 79/89] 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 e76bfb585..766150028 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 c0f1c2afc..d936b7d91 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 4e44dd312..067bf2153 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 964833128b92aafe3266f5096b3d83e7af261372 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 28 Feb 2023 17:41:19 +0800 Subject: [PATCH 80/89] 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 | 172 +++++++++--------- 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, 334 insertions(+), 228 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 333e973f0..bbf8e559f 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 788c0ac79..594eb6f36 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 d40082d82..3e2ff6dd2 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 5c3c1c250..04f00afc3 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 63fe094db..7c4344c31 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 014715fd1..8cf993095 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 ff85b2231..51e921a93 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 efa860c8d..77f5bddd4 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 90d72668a..bb6797d45 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 753c840a5..b47200cba 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 bede02196..87a4222cd 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 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 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 000000000..22b926615 --- /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 9b407de5c..249e87f46 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 91ad609ac..83d831747 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 1fbfe089a..b930a1344 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 dd6db71bf..ba924d6d5 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 7ac906762..71442e64a 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 7ee0228c9..39022d48f 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 47edec139..950954440 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 0bfb4d035..bfc3ff3f2 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 81/89] 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 062b7e669..737a9fa26 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 5db418efe41f8421a644d54926db6ce8d2164eed Mon Sep 17 00:00:00 2001 From: liujuping Date: Fri, 3 Mar 2023 17:08:04 +0800 Subject: [PATCH 82/89] 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 311493736..a96554908 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 518362b97..a93016290 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 e43095757..1b93f4625 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 c0c012544..16fb789a2 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 83/89] 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 d936b7d91..4968f269a 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 84/89] 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 7a3718366..05fa0f7be 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 85/89] =?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 89757bac9..11d50baad 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 e174c4ad6..29401ca6b 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 86/89] 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 1babdbe61..1f15405e5 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 eb2084508..d9b0f83a8 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 05fa0f7be..51d0fcf80 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 87/89] 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 276123391..b5256af9c 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 4f0543c7a..2d1254e4a 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 88/89] 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 7c4344c31..89856d2eb 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 8e04f72fc..21c31ab46 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 ea0554cad..b038df818 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 1f037c606..63435cdea 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 99086d20d..b11ac6f08 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 5f26c8d7b..c81776659 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 a1b0c314d..47b88d72f 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 2a351a2d6..b515aec53 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 bd5e4a3b0..db5e33dc8 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 119bcc488..ffb60ff6a 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 53ada7bf104cb5412eed6cd69b56c19cd57304d4 Mon Sep 17 00:00:00 2001 From: kit101 <qkssk1711@163.com> Date: Thu, 9 Mar 2023 14:04:47 +0800 Subject: [PATCH 89/89] 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 0eb8b9738..9e2bdf641 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 18e76febe..02b8bc5b3 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