From bbe438cf83c8c92ba7c2896eff4d27cd991525ea Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 20 Feb 2023 14:06:00 +0800 Subject: [PATCH 01/25] 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 02/25] 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 03/25] 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 04/25] 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 05/25] 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 06/25] 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 07/25] 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 08/25] 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 09/25] =?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 10/25] 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 11/25] 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 12/25] 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 13/25] 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 14/25] 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 15/25] 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 16/25] 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 17/25] 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 18/25] 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 19/25] 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 20/25] =?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 21/25] 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 22/25] 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 23/25] 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 24/25] 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 From 531cc9c09d94ca137517c1a320dd703c5c583cb9 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 10 Mar 2023 11:43:14 +0800 Subject: [PATCH 25/25] chore(release): publish 1.1.3 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 10 +++++----- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 67 insertions(+), 67 deletions(-) diff --git a/lerna.json b/lerna.json index 8ca861e34..b1ce00bbf 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.2", + "version": "1.1.3", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 663e5d91c..ec63d191c 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.2", + "version": "1.1.3", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index a3e799761..87022ad09 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.1.2", + "version": "1.1.3", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 3477ba1d5..d799bb68b 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.1.2", + "version": "1.1.3", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -18,10 +18,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 6edbe7ac0..768b80ffd 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.2", + "version": "1.1.3", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-editor-skeleton": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-editor-skeleton": "1.1.3", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.2", - "@alilc/lowcode-plugin-outline-pane": "1.1.2", - "@alilc/lowcode-shell": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", - "@alilc/lowcode-workspace": "1.1.2", + "@alilc/lowcode-plugin-designer": "1.1.3", + "@alilc/lowcode-plugin-outline-pane": "1.1.3", + "@alilc/lowcode-shell": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-workspace": "1.1.3", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 92f19ca67..71ea2b4c0 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.2", + "version": "1.1.3", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index fd0a246a6..ca426b6eb 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.1.2", + "version": "1.1.3", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 5a9147a8d..ff05813c4 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.1.2", + "version": "1.1.3", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,10 +13,10 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index d6270e1f8..50209be4e 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.1.2", + "version": "1.1.3", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-renderer-core": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 2ff493c2e..e5b08717d 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.1.2", + "version": "1.1.3", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-rax-renderer": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-rax-renderer": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 7ac933647..b897eea68 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.1.2", + "version": "1.1.3", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.1.2" + "@alilc/lowcode-renderer-core": "1.1.3" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 7c5868f3c..49c991f2a 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.1.2", + "version": "1.1.3", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-react-renderer": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-react-renderer": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index deb30be11..aa1c7d204 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.1.2", + "version": "1.1.3", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index a475a05bf..7608df5f5 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.2", + "version": "1.1.3", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,12 +15,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-editor-skeleton": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", - "@alilc/lowcode-workspace": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-editor-skeleton": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", + "@alilc/lowcode-workspace": "1.1.3", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index d36e7fb21..351c0311d 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.2", + "version": "1.1.3", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 7ed3787a7..4f391d23c 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.2", + "version": "1.1.3", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.2", + "@alilc/lowcode-types": "1.1.3", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 4bd99eaf9..ef80c7d67 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.2", + "version": "1.1.3", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.2", - "@alilc/lowcode-editor-core": "1.1.2", - "@alilc/lowcode-editor-skeleton": "1.1.2", - "@alilc/lowcode-types": "1.1.2", - "@alilc/lowcode-utils": "1.1.2", + "@alilc/lowcode-designer": "1.1.3", + "@alilc/lowcode-editor-core": "1.1.3", + "@alilc/lowcode-editor-skeleton": "1.1.3", + "@alilc/lowcode-types": "1.1.3", + "@alilc/lowcode-utils": "1.1.3", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5",