Merge branch 'release/1.1.3'

This commit is contained in:
JackLian 2023-03-16 09:26:10 +08:00
commit faa524e5e0
120 changed files with 2090 additions and 874 deletions

View File

@ -20,7 +20,7 @@ module.exports = {
'no-await-in-loop': 0, 'no-await-in-loop': 0,
'no-plusplus': 0, 'no-plusplus': 0,
'@typescript-eslint/no-parameter-properties': 0, '@typescript-eslint/no-parameter-properties': 0,
'@typescript-eslint/no-unused-vars': 1, 'no-restricted-exports': ['error'],
'no-multi-assign': 1, 'no-multi-assign': 1,
'no-dupe-class-members': 1, 'no-dupe-class-members': 1,
'react/no-deprecated': 1, 'react/no-deprecated': 1,
@ -48,6 +48,7 @@ module.exports = {
"afterLineComment": false, "afterLineComment": false,
"allowBlockStart": true, "allowBlockStart": true,
}], }],
"no-unused-vars": ['error', { "destructuredArrayIgnorePattern": "^_" }],
"@typescript-eslint/member-ordering": [ "@typescript-eslint/member-ordering": [
"error", "error",
{ "default": ["signature", "field", "constructor", "method"] } { "default": ["signature", "field", "constructor", "method"] }

View File

@ -71,4 +71,26 @@ jobs:
working-directory: packages/react-simulator-renderer working-directory: packages/react-simulator-renderer
test-script: npm test -- --jest-ci --jest-json --jest-coverage --jest-testLocationInResults --jest-outputFile=report.json test-script: npm test -- --jest-ci --jest-json --jest-coverage --jest-testLocationInResults --jest-outputFile=report.json
package-manager: yarn 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 annotations: none

View File

@ -24,5 +24,6 @@
- [Ychangqing](https://github.com/Ychangqing) - [Ychangqing](https://github.com/Ychangqing)
- [yize](https://github.com/yize) - [yize](https://github.com/yize)
- [youluna](https://github.com/youluna) - [youluna](https://github.com/youluna)
- [ibreathebsb](https://github.com/ibreathebsb)
如果您贡献过低代码引擎,但是没有看到您的名字,为我们的疏忽感到抱歉。欢迎您通过 PR 补充上自己的名字。 如果您贡献过低代码引擎,但是没有看到您的名字,为我们的疏忽感到抱歉。欢迎您通过 PR 补充上自己的名字。

View File

@ -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)<br/>
> **@since** v1.1.3
## 方法
### has
判断指定 key 是否有值
```typescript
/**
* 判断指定 key 是否有值
* check if config has certain key configed
* @param key
* @returns
*/
has(key: string): boolean;
```
### get
获取指定 key 的值
```typescript
/**
* 获取指定 key 的值
* get value by key
* @param key
* @param defaultValue
* @returns
*/
get(key: string, defaultValue?: any): any;
```
### set
设置指定 key 的值
```typescript
/**
* 设置指定 key 的值
* set value for certain key
* @param key
* @param value
*/
set(key: string, value: any): void;
```
### setConfig
批量设值set 的对象版本
```typescript
/**
* 批量设值set 的对象版本
* set multiple config key-values
* @param config
*/
setConfig(config: { [key: string]: any }): void;
```
### getPreference
获取全局 Preference, 用于管理全局浏览器侧用户 Preference如 Panel 是否钉住
```typescript
/**
* 获取全局 Preference, 用于管理全局浏览器侧用户 Preference如 Panel 是否钉住
* get global user preference manager, which can be use to store
* user`s preference in user localstorage, such as a panel is pinned or not.
* @returns {IPublicModelPreference}
* @since v1.1.0
*/
getPreference(): IPublicModelPreference;
```
相关类型:[IPublicModelPreference](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/preference.ts)
## 事件
### onGot
获取指定 key 的值,函数回调模式,若多次被赋值,回调会被多次调用
```typescript
/**
* 获取指定 key 的值,函数回调模式,若多次被赋值,回调会被多次调用
* set callback for event of value set for some key
* this will be called each time the value is set
* @param key
* @param fn
* @returns
*/
onGot(key: string, fn: (data: any) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onceGot
获取指定 key 的值,若此时还未赋值,则等待,若已有值,则直接返回值
> 注:此函数返回 Promise 实例只会执行fullfill一次
```typescript
/**
* 获取指定 key 的值,若此时还未赋值,则等待,若已有值,则直接返回值
* 注:此函数返回 Promise 实例只会执行fullfill一次
* wait until value of certain key is set, will only be
* triggered once.
* @param key
* @returns
*/
onceGot(key: string): Promise<any>;
```

View File

@ -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) 相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### reverse
类似数组的 reverse
```typescript
/**
* 类似数组的 reverse
* provide the same function with {Array.prototype.reverse}
*/
reverse(): IPublicModelNode[];
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### map ### map

View File

@ -645,3 +645,14 @@ setConditionalVisible(): void;
``` ```
**@since v1.1.0** **@since v1.1.0**
### getDOMNode
获取节点实例对应的 dom 节点
```typescript
/**
* 获取节点实例对应的 dom 节点
*/
getDOMNode(): HTMLElement;
```

View File

@ -1,6 +1,6 @@
{ {
"lerna": "4.0.0", "lerna": "4.0.0",
"version": "1.1.2", "version": "1.1.3",
"npmClient": "yarn", "npmClient": "yarn",
"useWorkspaces": true, "useWorkspaces": true,
"packages": [ "packages": [

View File

@ -15,6 +15,7 @@ const jestConfig = {
// testMatch: ['**/document-model.test.ts'], // testMatch: ['**/document-model.test.ts'],
// testMatch: ['**/prop.test.ts'], // testMatch: ['**/prop.test.ts'],
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'], // testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
// testMatch: ['**/document/node/node.add.test.ts'],
transformIgnorePatterns: [ transformIgnorePatterns: [
`/node_modules/(?!${esModules})/`, `/node_modules/(?!${esModules})/`,
], ],

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-designer", "name": "@alilc/lowcode-designer",
"version": "1.1.2", "version": "1.1.3",
"description": "Designer for Ali LowCode Engine", "description": "Designer for Ali LowCode Engine",
"main": "lib/index.js", "main": "lib/index.js",
"module": "es/index.js", "module": "es/index.js",
@ -15,9 +15,9 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@alilc/lowcode-editor-core": "1.1.2", "@alilc/lowcode-editor-core": "1.1.3",
"@alilc/lowcode-types": "1.1.2", "@alilc/lowcode-types": "1.1.3",
"@alilc/lowcode-utils": "1.1.2", "@alilc/lowcode-utils": "1.1.3",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"react": "^16", "react": "^16",
"react-dom": "^16.7.0", "react-dom": "^16.7.0",

View File

@ -236,17 +236,22 @@ export class BoxResizingInstance extends Component<{
render() { render() {
const { observed } = this.props; const { observed } = this.props;
if (!observed.hasOffset) {
return null;
}
const { node, offsetWidth, offsetHeight, offsetTop, offsetLeft } = observed;
let triggerVisible: any = []; let triggerVisible: any = [];
const { advanced } = node.componentMeta; let offsetWidth = 0;
if (advanced.getResizingHandlers) { let offsetHeight = 0;
triggerVisible = advanced.getResizingHandlers(node.internalToShellNode()); 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); triggerVisible = normalizeTriggers(triggerVisible);
const baseSideClass = 'lc-borders lc-resize-side'; const baseSideClass = 'lc-borders lc-resize-side';
@ -254,90 +259,100 @@ export class BoxResizingInstance extends Component<{
return ( return (
<div> <div>
{triggerVisible.includes('N') && ( <div
<div ref={(ref) => {
ref={(ref) => { this.outlineN = ref; }} this.outlineN = ref;
className={classNames(baseSideClass, 'n')} }}
style={{ className={classNames(baseSideClass, 'n')}
height: 20, style={{
transform: `translate(${offsetLeft}px, ${offsetTop - 10}px)`, height: 20,
width: offsetWidth, transform: `translate(${offsetLeft}px, ${offsetTop - 10}px)`,
}} width: offsetWidth,
/> display: triggerVisible.includes('N') ? 'flex' : 'none',
)} }}
{triggerVisible.includes('NE') && ( />
<div <div
ref={(ref) => { this.outlineNE = ref; }} ref={(ref) => {
className={classNames(baseCornerClass, 'ne')} this.outlineNE = ref;
style={{ }}
transform: `translate(${offsetLeft + offsetWidth - 5}px, ${offsetTop - 3}px)`, className={classNames(baseCornerClass, 'ne')}
cursor: 'nesw-resize', style={{
}} transform: `translate(${offsetLeft + offsetWidth - 5}px, ${offsetTop - 3}px)`,
/> cursor: 'nesw-resize',
)} display: triggerVisible.includes('NE') ? 'flex' : 'none',
{triggerVisible.includes('E') && ( }}
<div />
className={classNames(baseSideClass, 'e')} <div
ref={(ref) => { this.outlineE = ref; }} className={classNames(baseSideClass, 'e')}
style={{ ref={(ref) => {
height: offsetHeight, this.outlineE = ref;
transform: `translate(${offsetLeft + offsetWidth - 10}px, ${offsetTop}px)`, }}
width: 20, style={{
}} height: offsetHeight,
/> transform: `translate(${offsetLeft + offsetWidth - 10}px, ${offsetTop}px)`,
)} width: 20,
{triggerVisible.includes('SE') && ( display: triggerVisible.includes('E') ? 'flex' : 'none',
<div }}
ref={(ref) => { this.outlineSE = ref; }} />
className={classNames(baseCornerClass, 'se')} <div
style={{ ref={(ref) => {
transform: `translate(${offsetLeft + offsetWidth - 5}px, ${offsetTop + offsetHeight - 5}px)`, this.outlineSE = ref;
cursor: 'nwse-resize', }}
}} className={classNames(baseCornerClass, 'se')}
/> style={{
)} transform: `translate(${offsetLeft + offsetWidth - 5}px, ${
{triggerVisible.includes('S') && ( offsetTop + offsetHeight - 5
<div }px)`,
ref={(ref) => { this.outlineS = ref; }} cursor: 'nwse-resize',
className={classNames(baseSideClass, 's')} display: triggerVisible.includes('SE') ? 'flex' : 'none',
style={{ }}
height: 20, />
transform: `translate(${offsetLeft}px, ${offsetTop + offsetHeight - 10}px)`, <div
width: offsetWidth, ref={(ref) => {
}} this.outlineS = ref;
/> }}
)} className={classNames(baseSideClass, 's')}
{triggerVisible.includes('SW') && ( style={{
<div height: 20,
ref={(ref) => { this.outlineSW = ref; }} transform: `translate(${offsetLeft}px, ${offsetTop + offsetHeight - 10}px)`,
className={classNames(baseCornerClass, 'sw')} width: offsetWidth,
style={{ display: triggerVisible.includes('S') ? 'flex' : 'none',
transform: `translate(${offsetLeft - 3}px, ${offsetTop + offsetHeight - 5}px)`, }}
cursor: 'nesw-resize', />
}} <div
/> ref={(ref) => {
)} this.outlineSW = ref;
{triggerVisible.includes('W') && ( }}
<div className={classNames(baseCornerClass, 'sw')}
ref={(ref) => { this.outlineW = ref; }} style={{
className={classNames(baseSideClass, 'w')} transform: `translate(${offsetLeft - 3}px, ${offsetTop + offsetHeight - 5}px)`,
style={{ cursor: 'nesw-resize',
height: offsetHeight, display: triggerVisible.includes('SW') ? 'flex' : 'none',
transform: `translate(${offsetLeft - 10}px, ${offsetTop}px)`, }}
width: 20, />
}} <div
/> ref={(ref) => {
)} this.outlineW = ref;
{triggerVisible.includes('NW') && ( }}
<div className={classNames(baseSideClass, 'w')}
ref={(ref) => { this.outlineNW = ref; }} style={{
className={classNames(baseCornerClass, 'nw')} height: offsetHeight,
style={{ transform: `translate(${offsetLeft - 10}px, ${offsetTop}px)`,
transform: `translate(${offsetLeft - 3}px, ${offsetTop - 3}px)`, width: 20,
cursor: 'nwse-resize', display: triggerVisible.includes('W') ? 'flex' : 'none',
}} }}
/> />
)} <div
ref={(ref) => {
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',
}}
/>
</div> </div>
); );
} }

View File

@ -56,7 +56,8 @@ export function buildFilter(rule?: string | string[] | RegExp | IPublicTypeNesti
return (testNode: Node | IPublicTypeNodeSchema) => list.includes(testNode.componentName); return (testNode: Node | IPublicTypeNodeSchema) => list.includes(testNode.componentName);
} }
export interface IComponentMeta extends IPublicModelComponentMeta { export interface IComponentMeta extends IPublicModelComponentMeta<INode> {
prototype?: any;
} }
export class ComponentMeta implements IComponentMeta { export class ComponentMeta implements IComponentMeta {

View File

@ -30,7 +30,7 @@ import { ActiveTracker, IActiveTracker } from './active-tracker';
import { Detecting } from './detecting'; import { Detecting } from './detecting';
import { DropLocation } from './location'; import { DropLocation } from './location';
import { OffsetObserver, createOffsetObserver } from './offset-observer'; import { OffsetObserver, createOffsetObserver } from './offset-observer';
import { SettingTopEntry } from './setting'; import { ISettingTopEntry, SettingTopEntry } from './setting';
import { BemToolsManager } from '../builtin-simulator/bem-tools/manager'; import { BemToolsManager } from '../builtin-simulator/bem-tools/manager';
import { ComponentActions } from '../component-actions'; import { ComponentActions } from '../component-actions';
@ -61,6 +61,7 @@ export interface DesignerProps {
} }
export interface IDesigner { export interface IDesigner {
readonly shellModelFactory: IShellModelFactory;
get dragon(): IPublicModelDragon; get dragon(): IPublicModelDragon;
@ -70,6 +71,8 @@ export interface IDesigner {
get editor(): IPublicModelEditor; get editor(): IPublicModelEditor;
get detecting(): Detecting;
createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller; createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller;
/** /**
@ -91,6 +94,12 @@ export interface IDesigner {
getComponentMetasMap(): Map<string, IComponentMeta>; getComponentMetasMap(): Map<string, IComponentMeta>;
addPropsReducer(reducer: IPublicTypePropsTransducer, stage: IPublicEnumTransformStage): void; 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 { export class Designer implements IDesigner {
@ -331,7 +340,7 @@ export class Designer implements IDesigner {
this.oobxList.forEach((item) => item.compute()); this.oobxList.forEach((item) => item.compute());
} }
createSettingEntry(nodes: Node[]) { createSettingEntry(nodes: INode[]): ISettingTopEntry {
return new SettingTopEntry(this.editor, nodes); return new SettingTopEntry(this.editor, nodes);
} }

View File

@ -4,8 +4,11 @@ import { IDocumentModel } from '../document/document-model';
import { INode } from '../document/node/node'; import { INode } from '../document/node/node';
const DETECTING_CHANGE_EVENT = 'detectingChange'; const DETECTING_CHANGE_EVENT = 'detectingChange';
export interface IDetecting extends Omit< IPublicModelDetecting, 'capture' | 'release' | 'leave' > { export interface IDetecting extends Omit< IPublicModelDetecting<INode>,
'capture' |
'release' |
'leave'
> {
capture(node: INode | null): void; capture(node: INode | null): void;
release(node: INode | null): void; release(node: INode | null): void;

View File

@ -1,7 +1,6 @@
import { INode } from '../document'; import { IDocumentModel, INode } from '../document';
import { ILocateEvent } from './dragon'; import { ILocateEvent } from './dragon';
import { import {
IPublicModelDocumentModel,
IPublicModelDropLocation, IPublicModelDropLocation,
IPublicTypeLocationDetailType, IPublicTypeLocationDetailType,
IPublicTypeRect, IPublicTypeRect,
@ -105,7 +104,7 @@ export interface IDropLocation extends Omit< IPublicModelDropLocation, 'target'
get target(): INode; get target(): INode;
get document(): IPublicModelDocumentModel; get document(): IDocumentModel | null;
clone(event: IPublicModelLocateEvent): IDropLocation; clone(event: IPublicModelLocateEvent): IDropLocation;
} }
@ -119,7 +118,7 @@ export class DropLocation implements IDropLocation {
readonly source: string; readonly source: string;
get document(): IPublicModelDocumentModel { get document(): IDocumentModel | null {
return this.target.document; return this.target.document;
} }
@ -159,7 +158,7 @@ export class DropLocation implements IDropLocation {
if (this.detail.index <= 0) { if (this.detail.index <= 0) {
return null; 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; return (this.detail as any)?.near?.node;
} }

View File

@ -3,15 +3,15 @@ import { IComponentMeta } from '../../component-meta';
import { Designer } from '../designer'; import { Designer } from '../designer';
import { INode } from '../../document'; import { INode } from '../../document';
export interface SettingEntry extends IPublicModelSettingTarget { export interface ISettingEntry extends IPublicModelSettingTarget {
readonly nodes: INode[]; readonly nodes: INode[];
readonly componentMeta: IComponentMeta | null; readonly componentMeta: IComponentMeta | null;
readonly designer: Designer; 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;
} }

View File

@ -9,11 +9,11 @@ import {
} from '@alilc/lowcode-types'; } from '@alilc/lowcode-types';
import { Transducer } from './utils'; import { Transducer } from './utils';
import { SettingPropEntry } from './setting-prop-entry'; 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 { computed, obx, makeObservable, action, untracked, intl } from '@alilc/lowcode-editor-core';
import { cloneDeep, isCustomView, isDynamicSetter } from '@alilc/lowcode-utils'; import { cloneDeep, isCustomView, isDynamicSetter } from '@alilc/lowcode-utils';
function getSettingFieldCollectorKey(parent: SettingEntry, config: IPublicTypeFieldConfig) { function getSettingFieldCollectorKey(parent: ISettingEntry, config: IPublicTypeFieldConfig) {
let cur = parent; let cur = parent;
const path = [config.name]; const path = [config.name];
while (cur !== parent.top) { while (cur !== parent.top) {
@ -25,7 +25,11 @@ function getSettingFieldCollectorKey(parent: SettingEntry, config: IPublicTypeFi
return path.join('.'); 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 isSettingField = true;
readonly isRequired: boolean; readonly isRequired: boolean;
@ -36,7 +40,7 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
private hotValue: any; private hotValue: any;
parent: SettingEntry; parent: ISettingEntry;
extraProps: IPublicTypeFieldExtraProps; extraProps: IPublicTypeFieldExtraProps;
@ -56,9 +60,9 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
private _items: Array<SettingField | IPublicTypeCustomView> = []; private _items: Array<SettingField | IPublicTypeCustomView> = [];
constructor( constructor(
parent: SettingEntry, parent: ISettingEntry,
config: IPublicTypeFieldConfig, config: IPublicTypeFieldConfig,
settingFieldCollector?: (name: string | number, field: SettingField) => void, private settingFieldCollector?: (name: string | number, field: SettingField) => void,
) { ) {
super(parent, config.name, config.type); super(parent, config.name, config.type);
makeObservable(this); makeObservable(this);
@ -137,7 +141,8 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
// 创建子配置项,通常用于 object/array 类型数据 // 创建子配置项,通常用于 object/array 类型数据
createField(config: IPublicTypeFieldConfig): SettingField { createField(config: IPublicTypeFieldConfig): SettingField {
return new SettingField(this, config); this.settingFieldCollector?.(getSettingFieldCollectorKey(this.parent, config), this);
return new SettingField(this, config, this.settingFieldCollector);
} }
purge() { purge() {

View File

@ -1,13 +1,14 @@
import { obx, computed, makeObservable, runInAction, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { obx, computed, makeObservable, runInAction, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
import { GlobalEvent, IPublicModelEditor, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; import { GlobalEvent, IPublicModelEditor, IPublicTypeSetValueOptions } from '@alilc/lowcode-types';
import { uniqueId, isJSExpression, isSettingField } from '@alilc/lowcode-utils'; import { uniqueId, isJSExpression, isSettingField } from '@alilc/lowcode-utils';
import { SettingEntry } from './setting-entry'; import { Setters } from '@alilc/lowcode-shell';
import { ISettingEntry } from './setting-entry';
import { INode } from '../../document'; import { INode } from '../../document';
import { IComponentMeta } from '../../component-meta'; import { IComponentMeta } from '../../component-meta';
import { Designer } from '../designer'; import { Designer } from '../designer';
import { Setters } from '@alilc/lowcode-shell'; import { ISettingField } from './setting-field';
export class SettingPropEntry implements SettingEntry { export class SettingPropEntry implements ISettingEntry {
// === static properties === // === static properties ===
readonly editor: IPublicModelEditor; readonly editor: IPublicModelEditor;
@ -25,7 +26,7 @@ export class SettingPropEntry implements SettingEntry {
readonly designer: Designer; readonly designer: Designer;
readonly top: SettingEntry; readonly top: ISettingEntry;
readonly isGroup: boolean; readonly isGroup: boolean;
@ -52,7 +53,7 @@ export class SettingPropEntry implements SettingEntry {
extraProps: any = {}; extraProps: any = {};
constructor(readonly parent: SettingEntry, name: string | number, type?: 'field' | 'group') { constructor(readonly parent: ISettingEntry | ISettingField, name: string | number, type?: 'field' | 'group') {
makeObservable(this); makeObservable(this);
if (type == null) { if (type == null) {
const c = typeof name === 'string' ? name.slice(0, 1) : ''; const c = typeof name === 'string' ? name.slice(0, 1) : '';

View File

@ -1,22 +1,26 @@
import { IPublicTypeCustomView, IPublicModelEditor } from '@alilc/lowcode-types'; import { IPublicTypeCustomView, IPublicModelEditor } from '@alilc/lowcode-types';
import { isCustomView } from '@alilc/lowcode-utils'; import { isCustomView } from '@alilc/lowcode-utils';
import { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; 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 { SettingField } from './setting-field';
import { SettingPropEntry } from './setting-prop-entry'; import { SettingPropEntry } from './setting-prop-entry';
import { Node } from '../../document'; import { INode } from '../../document';
import { ComponentMeta } from '../../component-meta'; import { ComponentMeta } from '../../component-meta';
import { Designer } from '../designer'; import { IDesigner } from '../designer';
import { Setters } from '@alilc/lowcode-shell'; import { Setters } from '@alilc/lowcode-shell';
function generateSessionId(nodes: Node[]) { function generateSessionId(nodes: INode[]) {
return nodes return nodes
.map((node) => node.id) .map((node) => node.id)
.sort() .sort()
.join(','); .join(',');
} }
export class SettingTopEntry implements SettingEntry { export interface ISettingTopEntry extends ISettingEntry {
purge(): void;
}
export class SettingTopEntry implements ISettingTopEntry {
private emitter: IEventBus = createModuleEventBus('SettingTopEntry'); private emitter: IEventBus = createModuleEventBus('SettingTopEntry');
private _items: Array<SettingField | IPublicTypeCustomView> = []; private _items: Array<SettingField | IPublicTypeCustomView> = [];
@ -68,21 +72,21 @@ export class SettingTopEntry implements SettingEntry {
readonly id: string; readonly id: string;
readonly first: Node; readonly first: INode;
readonly designer: Designer; readonly designer: IDesigner | undefined;
readonly setters: Setters; readonly setters: Setters;
disposeFunctions: any[] = []; disposeFunctions: any[] = [];
constructor(readonly editor: IPublicModelEditor, readonly nodes: Node[]) { constructor(readonly editor: IPublicModelEditor, readonly nodes: INode[]) {
if (!Array.isArray(nodes) || nodes.length < 1) { if (!Array.isArray(nodes) || nodes.length < 1) {
throw new ReferenceError('nodes should not be empty'); throw new ReferenceError('nodes should not be empty');
} }
this.id = generateSessionId(nodes); this.id = generateSessionId(nodes);
this.first = nodes[0]; this.first = nodes[0];
this.designer = this.first.document.designer; this.designer = this.first.document?.designer;
this.setters = editor.get('setters') as Setters; this.setters = editor.get('setters') as Setters;
// setups // setups
@ -229,7 +233,6 @@ export class SettingTopEntry implements SettingEntry {
this.disposeFunctions = []; this.disposeFunctions = [];
} }
getProp(propName: string | number) { getProp(propName: string | number) {
return this.get(propName); return this.get(propName);
} }

View File

@ -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 { import {
IPublicTypeNodeData, IPublicTypeNodeData,
IPublicTypeNodeSchema, IPublicTypeNodeSchema,
@ -8,20 +17,32 @@ import {
IPublicTypeDragNodeObject, IPublicTypeDragNodeObject,
IPublicTypeDragNodeDataObject, IPublicTypeDragNodeDataObject,
IPublicModelDocumentModel, IPublicModelDocumentModel,
IPublicModelHistory,
IPublicModelNode,
IPublicEnumTransformStage, IPublicEnumTransformStage,
IPublicTypeOnChangeOptions, IPublicTypeOnChangeOptions,
IPublicTypeDisposable,
} from '@alilc/lowcode-types'; } 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 { IProject, Project } from '../project';
import { ISimulatorHost } from '../simulator'; import { ISimulatorHost } from '../simulator';
import { ComponentMeta } from '../component-meta'; import { IComponentMeta } from '../component-meta';
import { IDropLocation, Designer, IHistory } from '../designer'; import { IDesigner, IHistory } from '../designer';
import { Node, insertChildren, insertChild, RootNode, INode } from './node/node'; import { insertChildren, insertChild, RootNode, INode } from './node/node';
import { Selection, ISelection } from './selection'; import { Selection, ISelection } from './selection';
import { History } from './history'; import { History } from './history';
import { IModalNodesManager, ModalNodesManager } from './node'; import { IModalNodesManager, ModalNodesManager, Node } from './node';
import { uniqueId, isPlainObject, compatStage, isJSExpression, isDOMText, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isNode } from '@alilc/lowcode-utils';
import { EDITOR_EVENT } from '../types'; import { EDITOR_EVENT } from '../types';
export type GetDataType<T, NodeType> = T extends undefined export type GetDataType<T, NodeType> = T extends undefined
@ -32,21 +53,41 @@ export type GetDataType<T, NodeType> = T extends undefined
: any : any
: T; : 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;
/** get rootNode(): INode | null;
*
*/
readonly selection: ISelection;
readonly project: IProject; get simulator(): ISimulatorHost | null;
/** get active(): boolean;
*
*/ get nodesMap(): Map<string, INode>;
readonly modalNodesManager: IModalNodesManager;
/** /**
* id * id
@ -55,16 +96,32 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'select
getHistory(): IHistory; getHistory(): IHistory;
get focusNode(): INode | null;
get rootNode(): INode | null;
checkNesting( checkNesting(
dropTarget: INode, dropTarget: INode,
dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject, dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject,
): boolean; ): boolean;
getNodeCount(): number; 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;
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 { export class DocumentModel implements IDocumentModel {
@ -86,20 +143,20 @@ export class DocumentModel implements IDocumentModel {
/** /**
* *
*/ */
readonly history: IPublicModelHistory; readonly history: IHistory;
/** /**
* *
*/ */
readonly modalNodesManager: IModalNodesManager; modalNodesManager: IModalNodesManager;
private _nodesMap = new Map<string, IPublicModelNode>(); private _nodesMap = new Map<string, INode>();
readonly project: IProject; readonly project: IProject;
readonly designer: Designer; readonly designer: IDesigner;
@obx.shallow private nodes = new Set<IPublicModelNode>(); @obx.shallow private nodes = new Set<INode>();
private seqId = 0; private seqId = 0;
@ -119,7 +176,7 @@ export class DocumentModel implements IDocumentModel {
return this.project.simulator; return this.project.simulator;
} }
get nodesMap(): Map<string, Node> { get nodesMap(): Map<string, INode> {
return this._nodesMap; return this._nodesMap;
} }
@ -131,7 +188,7 @@ export class DocumentModel implements IDocumentModel {
this.rootNode?.getExtraProp('fileName', true)?.setValue(fileName); this.rootNode?.getExtraProp('fileName', true)?.setValue(fileName);
} }
get focusNode(): INode { get focusNode(): INode | null {
if (this._drillDownNode) { if (this._drillDownNode) {
return this._drillDownNode; return this._drillDownNode;
} }
@ -142,7 +199,7 @@ export class DocumentModel implements IDocumentModel {
return this.rootNode; return this.rootNode;
} }
@obx.ref private _drillDownNode: Node | null = null; @obx.ref private _drillDownNode: INode | null = null;
private _modalNode?: INode; private _modalNode?: INode;
@ -150,7 +207,7 @@ export class DocumentModel implements IDocumentModel {
private inited = false; private inited = false;
@obx.shallow private willPurgeSpace: Node[] = []; @obx.shallow private willPurgeSpace: INode[] = [];
get modalNode() { get modalNode() {
return this._modalNode; return this._modalNode;
@ -160,7 +217,7 @@ export class DocumentModel implements IDocumentModel {
return this.modalNode || this.focusNode; return this.modalNode || this.focusNode;
} }
@obx.shallow private activeNodes?: Node[]; @obx.shallow private activeNodes?: INode[];
@obx.ref private _dropLocation: IDropLocation | null = null; @obx.ref private _dropLocation: IDropLocation | null = null;
@ -236,7 +293,7 @@ export class DocumentModel implements IDocumentModel {
// 兼容 vision // 兼容 vision
this.id = project.getSchema()?.id || this.id; this.id = project.getSchema()?.id || this.id;
this.rootNode = this.createNode<RootNode>( this.rootNode = this.createNode(
schema || { schema || {
componentName: 'Page', componentName: 'Page',
id: 'root', id: 'root',
@ -257,11 +314,11 @@ export class DocumentModel implements IDocumentModel {
this.inited = true; this.inited = true;
} }
drillDown(node: Node | null) { drillDown(node: INode | null) {
this._drillDownNode = node; 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); this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_CHILDREN_CHANGE, fn);
return () => { return () => {
@ -269,7 +326,7 @@ export class DocumentModel implements IDocumentModel {
}; };
} }
onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): () => void { onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions<INode>) => void): IPublicTypeDisposable {
this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_VISIBLE_CHANGE, fn); this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_VISIBLE_CHANGE, fn);
return () => { return () => {
@ -277,11 +334,11 @@ export class DocumentModel implements IDocumentModel {
}; };
} }
addWillPurge(node: Node) { addWillPurge(node: INode) {
this.willPurgeSpace.push(node); this.willPurgeSpace.push(node);
} }
removeWillPurge(node: Node) { removeWillPurge(node: INode) {
const i = this.willPurgeSpace.indexOf(node); const i = this.willPurgeSpace.indexOf(node);
if (i > -1) { if (i > -1) {
this.willPurgeSpace.splice(i, 1); this.willPurgeSpace.splice(i, 1);
@ -295,7 +352,7 @@ export class DocumentModel implements IDocumentModel {
/** /**
* id * id
*/ */
nextId(possibleId: string | undefined) { nextId(possibleId: string | undefined): string {
let id = possibleId; let id = possibleId;
while (!id || this.nodesMap.get(id)) { while (!id || this.nodesMap.get(id)) {
id = `node_${(String(this.id).slice(-10) + (++this.seqId).toString(36)).toLocaleLowerCase()}`; id = `node_${(String(this.id).slice(-10) + (++this.seqId).toString(36)).toLocaleLowerCase()}`;
@ -330,7 +387,7 @@ export class DocumentModel implements IDocumentModel {
* schema * schema
*/ */
@action @action
createNode<T extends Node = Node, C = undefined>(data: GetDataType<C, T>, checkId: boolean = true): T { createNode<T extends INode = INode, C = undefined>(data: GetDataType<C, T>): T {
let schema: any; let schema: any;
if (isDOMText(data) || isJSExpression(data)) { if (isDOMText(data) || isJSExpression(data)) {
schema = { schema = {
@ -341,7 +398,7 @@ export class DocumentModel implements IDocumentModel {
schema = data; schema = data;
} }
let node: Node | null = null; let node: INode | null = null;
if (this.hasNode(schema?.id)) { if (this.hasNode(schema?.id)) {
schema.id = null; schema.id = null;
} }
@ -361,7 +418,7 @@ export class DocumentModel implements IDocumentModel {
} }
} }
if (!node) { if (!node) {
node = new Node(this, schema, { checkId }); node = new Node(this, schema);
// will add // will add
// todo: this.activeNodes?.push(node); // todo: this.activeNodes?.push(node);
} }
@ -373,30 +430,30 @@ export class DocumentModel implements IDocumentModel {
return node as any; return node as any;
} }
public destroyNode(node: Node) { public destroyNode(node: INode) {
this.emitter.emit('nodedestroy', node); 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 | null {
return insertChild(parent, thing, at, copy); 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); return insertChildren(parent, thing, at, copy);
} }
/** /**
* *
*/ */
removeNode(idOrNode: string | Node) { removeNode(idOrNode: string | INode) {
let id: string; let id: string;
let node: Node | null; let node: INode | null = null;
if (typeof idOrNode === 'string') { if (typeof idOrNode === 'string') {
id = idOrNode; id = idOrNode;
node = this.getNode(id); node = this.getNode(id);
@ -413,14 +470,14 @@ export class DocumentModel implements IDocumentModel {
/** /**
* *
*/ */
internalRemoveAndPurgeNode(node: Node, useMutator = false) { internalRemoveAndPurgeNode(node: INode, useMutator = false) {
if (!this.nodes.has(node)) { if (!this.nodes.has(node)) {
return; return;
} }
node.remove(useMutator); node.remove(useMutator);
} }
unlinkNode(node: Node) { unlinkNode(node: INode) {
this.nodes.delete(node); this.nodes.delete(node);
this._nodesMap.delete(node.id); this._nodesMap.delete(node.id);
} }
@ -428,7 +485,7 @@ export class DocumentModel implements IDocumentModel {
/** /**
* *
*/ */
wrapWith(schema: IPublicTypeNodeSchema): Node | null { wrapWith(schema: IPublicTypeNodeSchema): INode | null {
const nodes = this.selection.getTopNodes(); const nodes = this.selection.getTopNodes();
if (nodes.length < 1) { if (nodes.length < 1) {
return null; return null;
@ -465,17 +522,17 @@ export class DocumentModel implements IDocumentModel {
}); });
} }
export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Serilize) { export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Serilize): IPublicTypeRootSchema | undefined {
stage = compatStage(stage); stage = compatStage(stage);
// 置顶只作用于 Page 的第一级子节点,目前还用不到里层的置顶;如果后面有需要可以考虑将这段写到 node-children 中的 export // 置顶只作用于 Page 的第一级子节点,目前还用不到里层的置顶;如果后面有需要可以考虑将这段写到 node-children 中的 export
const currentSchema = this.rootNode?.export(stage); const currentSchema = this.rootNode?.export<IPublicTypeRootSchema>(stage);
if (Array.isArray(currentSchema?.children) && currentSchema?.children.length > 0) { if (Array.isArray(currentSchema?.children) && currentSchema?.children?.length && currentSchema?.children?.length > 0) {
const FixedTopNodeIndex = currentSchema.children const FixedTopNodeIndex = currentSchema?.children
.filter(i => isPlainObject(i)) .filter(i => isPlainObject(i))
.findIndex((i => (i as IPublicTypeNodeSchema).props?.__isTopFixed__)); .findIndex((i => (i as IPublicTypeNodeSchema).props?.__isTopFixed__));
if (FixedTopNodeIndex > 0) { if (FixedTopNodeIndex > 0) {
const FixedTopNode = currentSchema.children.splice(FixedTopNodeIndex, 1); const FixedTopNode = currentSchema?.children.splice(FixedTopNodeIndex, 1);
currentSchema.children.unshift(FixedTopNode[0]); currentSchema?.children.unshift(FixedTopNode[0]);
} }
} }
return currentSchema; return currentSchema;
@ -504,7 +561,7 @@ export class DocumentModel implements IDocumentModel {
return this.simulator!.getComponent(componentName); return this.simulator!.getComponent(componentName);
} }
getComponentMeta(componentName: string): ComponentMeta { getComponentMeta(componentName: string): IComponentMeta {
return this.designer.getComponentMeta( return this.designer.getComponentMeta(
componentName, componentName,
() => this.simulator?.generateComponentMetadata(componentName) || null, () => this.simulator?.generateComponentMetadata(componentName) || null,
@ -579,10 +636,10 @@ export class DocumentModel implements IDocumentModel {
dropTarget: INode, dropTarget: INode,
dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject, dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject,
): boolean { ): boolean {
let items: Array<Node | IPublicTypeNodeSchema>; let items: Array<INode | IPublicTypeNodeSchema>;
if (isDragNodeDataObject(dragObject)) { if (isDragNodeDataObject(dragObject)) {
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data]; items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
} else if (isDragNodeObject(dragObject)) { } else if (isDragNodeObject<INode>(dragObject)) {
items = dragObject.nodes; items = dragObject.nodes;
} else if (isNode(dragObject) || isNodeSchema(dragObject)) { } else if (isNode(dragObject) || isNodeSchema(dragObject)) {
items = [dragObject]; items = [dragObject];
@ -599,11 +656,13 @@ export class DocumentModel implements IDocumentModel {
* Use checkNesting method instead. * Use checkNesting method instead.
*/ */
checkDropTarget(dropTarget: INode, dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject): boolean { checkDropTarget(dropTarget: INode, dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject): boolean {
let items: Array<Node | IPublicTypeNodeSchema>; let items: Array<INode | IPublicTypeNodeSchema>;
if (isDragNodeDataObject(dragObject)) { if (isDragNodeDataObject(dragObject)) {
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data]; items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
} else { } else if (isDragNodeObject<INode>(dragObject)) {
items = dragObject.nodes; items = dragObject.nodes;
} else {
return false;
} }
return items.every((item) => this.checkNestingUp(dropTarget, item)); return items.every((item) => this.checkNestingUp(dropTarget, item));
} }
@ -611,7 +670,7 @@ export class DocumentModel implements IDocumentModel {
/** /**
* parentWhitelist * parentWhitelist
*/ */
checkNestingUp(parent: INode, obj: IPublicTypeNodeSchema | Node): boolean { checkNestingUp(parent: INode, obj: IPublicTypeNodeSchema | INode): boolean {
if (isNode(obj) || isNodeSchema(obj)) { if (isNode(obj) || isNodeSchema(obj)) {
const config = isNode(obj) ? obj.componentMeta : this.getComponentMeta(obj.componentName); const config = isNode(obj) ? obj.componentMeta : this.getComponentMeta(obj.componentName);
if (config) { if (config) {
@ -625,7 +684,7 @@ export class DocumentModel implements IDocumentModel {
/** /**
* childWhitelist * childWhitelist
*/ */
checkNestingDown(parent: INode, obj: IPublicTypeNodeSchema | Node): boolean { checkNestingDown(parent: INode, obj: IPublicTypeNodeSchema | INode): boolean {
const config = parent.componentMeta; const config = parent.componentMeta;
return config.checkNestingDown(parent, obj); return config.checkNestingDown(parent, obj);
} }
@ -666,7 +725,9 @@ export class DocumentModel implements IDocumentModel {
*/ */
/* istanbul ignore next */ /* istanbul ignore next */
exportAddonData() { exportAddonData() {
const addons = {}; const addons: {
[key: string]: any;
} = {};
this._addons.forEach((addon) => { this._addons.forEach((addon) => {
const data = addon.exportData(); const data = addon.exportData();
if (data === null) { if (data === null) {
@ -806,7 +867,7 @@ export class DocumentModel implements IDocumentModel {
onReady(fn: Function) { onReady(fn: Function) {
this.designer.editor.eventBus.on('document-open', fn); this.designer.editor.eventBus.on('document-open', fn);
return () => { return () => {
this.designer.editor.removeListener('document-open', fn); this.designer.editor.eventBus.off('document-open', fn);
}; };
} }

View File

@ -1,18 +1,30 @@
import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core'; import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core';
import { uniqueId } from '@alilc/lowcode-utils'; import { uniqueId } from '@alilc/lowcode-utils';
import { IPublicTypeTitleContent, IPublicModelExclusiveGroup } from '@alilc/lowcode-types'; import { IPublicTypeTitleContent, IPublicModelExclusiveGroup } from '@alilc/lowcode-types';
import { Node } from './node'; import { INode } from './node';
import { intl } from '../../locale'; import { intl } from '../../locale';
export interface IExclusiveGroup extends IPublicModelExclusiveGroup<INode> {
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 // 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, // if-else-if assoc conditionGroup value, should be the same level,
// and siblings, need renderEngine support // and siblings, need renderEngine support
export class ExclusiveGroup implements IPublicModelExclusiveGroup { export class ExclusiveGroup implements IExclusiveGroup {
readonly isExclusiveGroup = true; readonly isExclusiveGroup = true;
readonly id = uniqueId('exclusive'); readonly id = uniqueId('exclusive');
@obx.shallow readonly children: Node[] = []; readonly title: IPublicTypeTitleContent;
@obx.shallow readonly children: INode[] = [];
@obx private visibleIndex = 0; @obx private visibleIndex = 0;
@ -28,11 +40,11 @@ export class ExclusiveGroup implements IPublicModelExclusiveGroup {
return this.children.length; return this.children.length;
} }
@computed get visibleNode(): Node { @computed get visibleNode(): INode {
return this.children[this.visibleIndex]; return this.children[this.visibleIndex];
} }
@computed get firstNode(): Node { @computed get firstNode(): INode {
return this.children[0]!; return this.children[0]!;
} }
@ -40,8 +52,16 @@ export class ExclusiveGroup implements IPublicModelExclusiveGroup {
return this.firstNode.index; return this.firstNode.index;
} }
add(node: Node) { constructor(readonly name: string, title?: IPublicTypeTitleContent) {
if (node.nextSibling && node.nextSibling.conditionGroup === this) { 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); const i = this.children.indexOf(node.nextSibling);
this.children.splice(i, 0, node); this.children.splice(i, 0, node);
} else { } else {
@ -49,7 +69,7 @@ export class ExclusiveGroup implements IPublicModelExclusiveGroup {
} }
} }
remove(node: Node) { remove(node: INode) {
const i = this.children.indexOf(node); const i = this.children.indexOf(node);
if (i > -1) { if (i > -1) {
this.children.splice(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); const i = this.children.indexOf(node);
if (i > -1) { if (i > -1) {
this.visibleIndex = i; this.visibleIndex = i;
} }
} }
isVisible(node: Node) { isVisible(node: INode) {
const i = this.children.indexOf(node); const i = this.children.indexOf(node);
return i === this.visibleIndex; 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 { export function isExclusiveGroup(obj: any): obj is ExclusiveGroup {

View File

@ -1,9 +1,9 @@
import { INode, Node } from './node'; import { INode } from './node';
import { DocumentModel } from '../document-model'; import { DocumentModel } from '../document-model';
import { IPublicModelModalNodesManager } from '@alilc/lowcode-types'; import { IPublicModelModalNodesManager } from '@alilc/lowcode-types';
import { createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core'; import { createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
export function getModalNodes(node: INode | Node) { export function getModalNodes(node: INode) {
if (!node) return []; if (!node) return [];
let nodes: any = []; let nodes: any = [];
if (node.componentMeta.isModal) { if (node.componentMeta.isModal) {
@ -18,11 +18,7 @@ export function getModalNodes(node: INode | Node) {
return nodes; return nodes;
} }
export interface IModalNodesManager extends IPublicModelModalNodesManager { export interface IModalNodesManager extends IPublicModelModalNodesManager<INode> {
getModalNodes(): INode[];
getVisibleModalNode(): INode | null;
} }
export class ModalNodesManager implements IModalNodesManager { export class ModalNodesManager implements IModalNodesManager {
@ -87,7 +83,7 @@ export class ModalNodesManager implements IModalNodesManager {
} }
private addNode(node: INode) { private addNode(node: INode) {
if (node.componentMeta.isModal) { if (node?.componentMeta.isModal) {
this.hideModalNodes(); this.hideModalNodes();
this.modalNodes.push(node); this.modalNodes.push(node);
this.addNodeEvent(node); this.addNodeEvent(node);

View File

@ -1,6 +1,6 @@
import { obx, computed, globalContext, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { obx, computed, globalContext, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
import { Node, INode } from './node'; 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 { shallowEqual, compatStage, isNodeSchema } from '@alilc/lowcode-utils';
import { foreachReverse } from '../../utils/tree'; import { foreachReverse } from '../../utils/tree';
import { NodeRemoveOptions } from '../../types'; import { NodeRemoveOptions } from '../../types';
@ -10,9 +10,16 @@ export interface IOnChangeOptions {
node: Node; node: Node;
} }
export interface INodeChildren extends Omit<IPublicModelNodeChildren, 'forEach' | 'map' | 'every' | 'some' | 'filter' | 'find' | 'reduce' | 'mergeChildren' > { export interface INodeChildren extends Omit<IPublicModelNodeChildren<INode>,
'importSchema' |
'exportSchema' |
'isEmpty' |
'notEmpty'
> {
get owner(): INode; get owner(): INode;
get length(): number;
unlinkChild(node: INode): void; unlinkChild(node: INode): void;
/** /**
@ -42,29 +49,19 @@ export interface INodeChildren extends Omit<IPublicModelNodeChildren, 'forEach'
forEach(fn: (item: INode, index: number) => void): void; forEach(fn: (item: INode, index: number) => void): void;
map<T>(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;
mergeChildren(
remover: (node: INode, idx: number) => boolean,
adder: (children: INode[]) => IPublicTypeNodeData[] | null,
sorter: (firstNode: INode, secondNode: INode) => number,
): any;
/** /**
* *
*/ */
get(index: number): INode | null; get(index: number): INode | null;
isEmpty(): boolean;
notEmpty(): boolean;
internalInitParent(): void;
onChange(fn: (info?: IOnChangeOptions) => void): IPublicTypeDisposable;
/** overriding methods end */ /** overriding methods end */
} }
export class NodeChildren implements INodeChildren { export class NodeChildren implements INodeChildren {
@ -138,12 +135,12 @@ export class NodeChildren implements INodeChildren {
const child = originChildren[i]; const child = originChildren[i];
const item = data[i]; const item = data[i];
let node: Node | undefined; let node: INode | undefined | null;
if (isNodeSchema(item) && !checkId && child && child.componentName === item.componentName) { if (isNodeSchema(item) && !checkId && child && child.componentName === item.componentName) {
node = child; node = child;
node.import(item); node.import(item);
} else { } else {
node = this.owner.document.createNode(item, checkId); node = this.owner.document?.createNode(item, checkId);
} }
children[i] = node; children[i] = node;
} }
@ -434,7 +431,7 @@ export class NodeChildren implements INodeChildren {
return this.children.filter(fn); 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); return this.children.find(fn);
} }
@ -442,6 +439,10 @@ export class NodeChildren implements INodeChildren {
return this.children.reduce(fn, initialValue); return this.children.reduce(fn, initialValue);
} }
reverse() {
return this.children.reverse();
}
mergeChildren( mergeChildren(
remover: (node: INode, idx: number) => boolean, remover: (node: INode, idx: number) => boolean,
adder: (children: INode[]) => IPublicTypeNodeData[] | null, adder: (children: INode[]) => IPublicTypeNodeData[] | null,
@ -465,7 +466,7 @@ export class NodeChildren implements INodeChildren {
const items = adder(this.children); const items = adder(this.children);
if (items && items.length > 0) { if (items && items.length > 0) {
items.forEach((child: IPublicTypeNodeData) => { items.forEach((child: IPublicTypeNodeData) => {
const node = this.owner.document?.createNode(child); const node: INode = this.owner.document?.createNode(child);
this.children.push(node); this.children.push(node);
node.internalSetParent(this.owner); node.internalSetParent(this.owner);
}); });
@ -481,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); this.emitter.on('change', fn);
return () => { return () => {
this.emitter.removeListener('change', fn); this.emitter.removeListener('change', fn);

View File

@ -16,15 +16,16 @@ import {
IPublicModelExclusiveGroup, IPublicModelExclusiveGroup,
IPublicEnumTransformStage, IPublicEnumTransformStage,
IPublicTypeDisposable, IPublicTypeDisposable,
IBaseModelNode,
} from '@alilc/lowcode-types'; } from '@alilc/lowcode-types';
import { compatStage, isDOMText, isJSExpression, isNode } from '@alilc/lowcode-utils'; import { compatStage, isDOMText, isJSExpression, isNode, isNodeSchema } from '@alilc/lowcode-utils';
import { SettingTopEntry } from '@alilc/lowcode-designer'; import { ISettingTopEntry } from '@alilc/lowcode-designer';
import { Props, getConvertedExtraKey, IProps } from './props/props'; 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 { NodeChildren, INodeChildren } from './node-children';
import { IProp, Prop } from './props/prop'; import { IProp, Prop } from './props/prop';
import { ComponentMeta, IComponentMeta } from '../../component-meta'; import { IComponentMeta } from '../../component-meta';
import { ExclusiveGroup, isExclusiveGroup } from './exclusive-group'; import { ExclusiveGroup, IExclusiveGroup, isExclusiveGroup } from './exclusive-group';
import { includeSlot, removeSlot } from '../../utils/slot'; import { includeSlot, removeSlot } from '../../utils/slot';
import { foreachReverse } from '../../utils/tree'; import { foreachReverse } from '../../utils/tree';
import { NodeRemoveOptions, EDITOR_EVENT } from '../../types'; import { NodeRemoveOptions, EDITOR_EVENT } from '../../types';
@ -36,50 +37,51 @@ export interface NodeStatus {
inPlaceEditing: boolean; inPlaceEditing: boolean;
} }
export interface INode extends IPublicModelNode { export interface INode extends Omit<IBaseModelNode<
IDocumentModel,
/** INode,
* INodeChildren,
*/ IComponentMeta,
get children(): INodeChildren | null; ISettingTopEntry,
IProps,
/** IProp,
* IExclusiveGroup
*/ >,
get prevSibling(): INode | null; 'isRoot' |
'isPage' |
/** 'isComponent' |
* 'isModal' |
*/ 'isSlot' |
get nextSibling(): INode | null; 'isParental' |
'isLeaf' |
/** 'settingEntry' |
* // 在内部的 node 模型中不存在
*/ 'getExtraPropValue' |
get parent(): INode | null; 'setExtraPropValue' |
'exportSchema' |
get slots(): INode[]; 'visible' |
'importSchema' |
/** // 内外实现有差异
* 'isContainer' |
*/ 'isEmpty'
get slotFor(): IProp | null; > {
isNode: boolean;
get props(): IProps;
get componentMeta(): IComponentMeta; get componentMeta(): IComponentMeta;
get document(): IDocumentModel; get settingEntry(): ISettingTopEntry;
setVisible(flag: boolean): void; get isPurged(): boolean;
getVisible(): boolean; get index(): number | undefined;
get isPurging(): boolean;
/** /**
* 使 * 使
* @param useMutator * @param useMutator
*/ */
internalSetParent(parent: INode | null, useMutator: boolean): void; internalSetParent(parent: INode | null, useMutator?: boolean): void;
setConditionGroup(grp: IPublicModelExclusiveGroup | string | null): void; setConditionGroup(grp: IPublicModelExclusiveGroup | string | null): void;
@ -87,14 +89,12 @@ export interface INode extends IPublicModelNode {
internalPurgeStart(): void; internalPurgeStart(): void;
unlinkSlot(slotNode: Node): void; unlinkSlot(slotNode: INode): void;
didDropOut(dragment: Node): void;
/** /**
* schema * schema
*/ */
export(stage: IPublicEnumTransformStage, options?: any): IPublicTypeNodeSchema; export<T = IPublicTypeNodeSchema>(stage: IPublicEnumTransformStage, options?: any): T;
emitPropChange(val: IPublicTypePropChangeOptions): void; emitPropChange(val: IPublicTypePropChangeOptions): void;
@ -106,17 +106,47 @@ export interface INode extends IPublicModelNode {
onVisibleChange(func: (flag: boolean) => any): () => void; onVisibleChange(func: (flag: boolean) => any): () => void;
getProp(path: string, createIfNone?: boolean): IProp | null;
getExtraProp(key: string, createIfNone?: boolean): IProp | null;
replaceChild(node: INode, data: any): INode;
getSuitablePlace(node: INode, ref: any): any; 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; 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: INode): void;
didDropOut(dragment: INode): void;
purge(): void;
removeSlot(slotNode: INode): boolean;
setVisible(flag: boolean): void;
getVisible(): boolean;
} }
/** /**
@ -251,9 +281,9 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
isInited = false; isInited = false;
_settingEntry: SettingTopEntry; _settingEntry: ISettingTopEntry;
get settingEntry(): SettingTopEntry { get settingEntry(): ISettingTopEntry {
if (this._settingEntry) return this._settingEntry; if (this._settingEntry) return this._settingEntry;
this._settingEntry = this.document.designer.createSettingEntry([this]); this._settingEntry = this.document.designer.createSettingEntry([this]);
return this._settingEntry; return this._settingEntry;
@ -279,7 +309,11 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
return !!this._isRGLContainer; return !!this._isRGLContainer;
} }
private _slotFor?: IProp | null = null; get isEmptyNode() {
return this.isEmpty();
}
private _slotFor?: IProp | null | undefined = null;
@obx.shallow _slots: INode[] = []; @obx.shallow _slots: INode[] = [];
@ -288,10 +322,10 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
} }
/* istanbul ignore next */ /* istanbul ignore next */
@obx.ref private _conditionGroup: IPublicModelExclusiveGroup | null = null; @obx.ref private _conditionGroup: IExclusiveGroup | null = null;
/* istanbul ignore next */ /* istanbul ignore next */
get conditionGroup(): IPublicModelExclusiveGroup | null { get conditionGroup(): IExclusiveGroup | null {
return this._conditionGroup; return this._conditionGroup;
} }
@ -319,7 +353,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
pseudo: false, pseudo: false,
}; };
constructor(readonly document: IDocumentModel, nodeSchema: Schema, options: any = {}) { constructor(readonly document: IDocumentModel, nodeSchema: Schema) {
makeObservable(this); makeObservable(this);
const { componentName, id, children, props, ...extras } = nodeSchema; const { componentName, id, children, props, ...extras } = nodeSchema;
this.id = document.nextId(id); this.id = document.nextId(id);
@ -347,7 +381,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
this.onVisibleChange((visible: boolean) => { this.onVisibleChange((visible: boolean) => {
editor?.eventBus.emit(EDITOR_EVENT.NODE_VISIBLE_CHANGE, this, visible); 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); editor?.eventBus.emit(EDITOR_EVENT.NODE_VISIBLE_CHANGE, info);
}); });
} }
@ -475,7 +509,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
this.document.addWillPurge(this); this.document.addWillPurge(this);
} }
private didDropIn(dragment: Node) { didDropIn(dragment: INode) {
const { callbacks } = this.componentMeta.advanced; const { callbacks } = this.componentMeta.advanced;
if (callbacks?.onNodeAdd) { if (callbacks?.onNodeAdd) {
const cbThis = this.internalToShellNode(); const cbThis = this.internalToShellNode();
@ -486,7 +520,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
} }
} }
private didDropOut(dragment: Node) { didDropOut(dragment: INode) {
const { callbacks } = this.componentMeta.advanced; const { callbacks } = this.componentMeta.advanced;
if (callbacks?.onNodeRemove) { if (callbacks?.onNodeRemove) {
const cbThis = this.internalToShellNode(); const cbThis = this.internalToShellNode();
@ -547,7 +581,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
/** /**
* *
*/ */
get slotFor(): IProp | null { get slotFor(): IProp | null | undefined {
return this._slotFor; return this._slotFor;
} }
@ -567,10 +601,10 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
}); });
} }
if (this.isSlot()) { if (this.isSlot()) {
this.parent.removeSlot(this, purge); this.parent.removeSlot(this);
this.parent.children.internalDelete(this, purge, useMutator, { suppressRemoveEvent: true }); this.parent.children?.internalDelete(this, purge, useMutator, { suppressRemoveEvent: true });
} else { } else {
this.parent.children.internalDelete(this, purge, useMutator, { suppressRemoveEvent: true }); this.parent.children?.internalDelete(this, purge, useMutator, { suppressRemoveEvent: true });
} }
} }
} }
@ -610,7 +644,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
/** /**
* *
*/ */
@computed get componentMeta(): ComponentMeta { @computed get componentMeta(): IComponentMeta {
return this.document.getComponentMeta(this.componentName); return this.document.getComponentMeta(this.componentName);
} }
@ -627,6 +661,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
/* istanbul ignore next */ /* istanbul ignore next */
setConditionGroup(grp: IPublicModelExclusiveGroup | string | null) { setConditionGroup(grp: IPublicModelExclusiveGroup | string | null) {
let _grp: IExclusiveGroup | null = null;
if (!grp) { if (!grp) {
this.getExtraProp('conditionGroup', false)?.remove(); this.getExtraProp('conditionGroup', false)?.remove();
if (this._conditionGroup) { if (this._conditionGroup) {
@ -637,20 +672,20 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
} }
if (!isExclusiveGroup(grp)) { if (!isExclusiveGroup(grp)) {
if (this.prevSibling?.conditionGroup?.name === grp) { if (this.prevSibling?.conditionGroup?.name === grp) {
grp = this.prevSibling.conditionGroup; _grp = this.prevSibling.conditionGroup;
} else if (this.nextSibling?.conditionGroup?.name === grp) { } else if (this.nextSibling?.conditionGroup?.name === grp) {
grp = this.nextSibling.conditionGroup; _grp = this.nextSibling.conditionGroup;
} else { } else if (typeof grp === 'string') {
grp = new ExclusiveGroup(grp); _grp = new ExclusiveGroup(grp);
} }
} }
if (this._conditionGroup !== grp) { if (_grp && this._conditionGroup !== _grp) {
this.getExtraProp('conditionGroup', true)?.setValue(grp.name); this.getExtraProp('conditionGroup', true)?.setValue(_grp.name);
if (this._conditionGroup) { if (this._conditionGroup) {
this._conditionGroup.remove(this); this._conditionGroup.remove(this);
} }
this._conditionGroup = grp; this._conditionGroup = _grp;
grp.add(this); _grp?.add(this);
} }
} }
@ -706,13 +741,17 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
* @param {INode} node * @param {INode} node
* @param {object} data * @param {object} data
*/ */
replaceChild(node: INode, data: any): INode { replaceChild(node: INode, data: any): INode | null {
if (this.children?.has(node)) { if (this.children?.has(node)) {
const selected = this.document.selection.has(node.id); const selected = this.document.selection.has(node.id);
delete data.id; delete data.id;
const newNode = this.document.createNode(data); const newNode = this.document.createNode(data);
if (!isNode(newNode)) {
return null;
}
this.insertBefore(newNode, node, false); this.insertBefore(newNode, node, false);
node.remove(false); node.remove(false);
@ -795,39 +834,45 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
/** /**
* *
*/ */
@computed get index(): number { @computed get index(): number | undefined {
if (!this.parent) { if (!this.parent) {
return -1; 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) { if (!this.parent) {
return null; return null;
} }
const { index } = this; const { index } = this;
if (typeof index !== 'number') {
return null;
}
if (index < 0) { if (index < 0) {
return null; 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) { if (!this.parent) {
return null; return null;
} }
const { index } = this; const { index } = this;
if (typeof index !== 'number') {
return null;
}
if (index < 1) { if (index < 1) {
return null; return null;
} }
return this.parent.children.get(index - 1); return this.parent.children?.get(index - 1);
} }
/** /**
@ -846,7 +891,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
if (this.isSlot()) { if (this.isSlot()) {
foreachReverse( foreachReverse(
this.children!, this.children!,
(subNode: Node) => { (subNode: INode) => {
subNode.remove(true, true); subNode.remove(true, true);
}, },
(iterable, idx) => (iterable as NodeChildren).get(idx), (iterable, idx) => (iterable as NodeChildren).get(idx),
@ -869,7 +914,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
/** /**
* schema * schema
*/ */
export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save, options: any = {}): Schema { export<T = IPublicTypeNodeSchema>(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save, options: any = {}): T {
stage = compatStage(stage); stage = compatStage(stage);
const baseSchema: any = { const baseSchema: any = {
componentName: this.componentName, componentName: this.componentName,
@ -911,7 +956,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
...this.document.designer.transformProps(_extras_, this, stage), ...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); schema.children = this.children.export(stage);
} }
@ -928,7 +973,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
/** /**
* *
*/ */
getZLevelTop(zLevel: number): Node | null { getZLevelTop(zLevel: number): INode | null {
return getZLevelTop(this, zLevel); return getZLevelTop(this, zLevel);
} }
@ -940,11 +985,11 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
* 2 thisNode before or after otherNode * 2 thisNode before or after otherNode
* 0 thisNode same as otherNode * 0 thisNode same as otherNode
*/ */
comparePosition(otherNode: Node): PositionNO { comparePosition(otherNode: INode): PositionNO {
return comparePosition(this, otherNode); return comparePosition(this, otherNode);
} }
unlinkSlot(slotNode: Node) { unlinkSlot(slotNode: INode) {
const i = this._slots.indexOf(slotNode); const i = this._slots.indexOf(slotNode);
if (i < 0) { if (i < 0) {
return false; return false;
@ -955,7 +1000,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
/** /**
* Slot节点 * Slot节点
*/ */
removeSlot(slotNode: Node, purge = false): boolean { removeSlot(slotNode: INode): boolean {
// if (purge) { // if (purge) {
// // should set parent null // // should set parent null
// slotNode?.internalSetParent(null, false); // slotNode?.internalSetParent(null, false);
@ -996,7 +1041,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
* *
* @param node * @param node
*/ */
removeChild(node: Node) { removeChild(node: INode) {
this.children?.delete(node); this.children?.delete(node);
} }
@ -1047,18 +1092,18 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
return this.componentName; return this.componentName;
} }
insert(node: Node, ref?: Node, useMutator = true) { insert(node: INode, ref?: INode, useMutator = true) {
this.insertAfter(node, ref, useMutator); 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); const nodeInstance = ensureNode(node, this.document);
this.children?.internalInsert(nodeInstance, ref ? ref.index : null, useMutator); 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); 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() { getParent() {
@ -1085,15 +1130,15 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
return this.props; return this.props;
} }
onChildrenChange(fn: (param?: { type: string; node: Node }) => void): IPublicTypeDisposable { onChildrenChange(fn: (param?: { type: string; node: INode }) => void): IPublicTypeDisposable | undefined {
const wrappedFunc = wrapWithEventSwitch(fn); const wrappedFunc = wrapWithEventSwitch(fn);
return this.children?.onChange(wrappedFunc); return this.children?.onChange(wrappedFunc);
} }
mergeChildren( mergeChildren(
remover: () => any, remover: (node: INode, idx: number) => any,
adder: (children: Node[]) => IPublicTypeNodeData[] | null, adder: (children: INode[]) => IPublicTypeNodeData[] | null,
sorter: () => any, sorter: (firstNode: INode, secondNode: INode) => any,
) { ) {
this.children?.mergeChildren(remover, adder, sorter); this.children?.mergeChildren(remover, adder, sorter);
} }
@ -1287,7 +1332,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
} }
} }
function ensureNode(node: any, document: DocumentModel): Node { function ensureNode(node: any, document: IDocumentModel): INode {
let nodeInstance = node; let nodeInstance = node;
if (!isNode(node)) { if (!isNode(node)) {
if (node.getComponentName) { if (node.getComponentName) {
@ -1400,20 +1445,24 @@ export function insertChild(
thing: INode | IPublicTypeNodeData, thing: INode | IPublicTypeNodeData,
at?: number | null, at?: number | null,
copy?: boolean, copy?: boolean,
): INode { ): INode | null {
let node: INode; let node: INode | null | RootNode | undefined;
if (isNode(thing) && (copy || thing.isSlot())) { let nodeSchema: IPublicTypeNodeSchema;
thing = thing.export(IPublicEnumTransformStage.Clone); if (isNode<INode>(thing) && (copy || thing.isSlot())) {
} nodeSchema = thing.export(IPublicEnumTransformStage.Clone);
if (isNode(thing)) { node = container.document?.createNode(nodeSchema);
} else if (isNode<INode>(thing)) {
node = thing; node = thing;
} else { } else if (isNodeSchema(thing)) {
node = container.document.createNode(thing); node = container.document?.createNode(thing);
} }
container.children.insert(node, at); if (isNode<INode>(node)) {
container.children?.insert(node, at);
return node;
}
return node; return null;
} }
export function insertChildren( export function insertChildren(

View File

@ -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 { IPublicTypeCompositeValue, GlobalEvent, IPublicTypeJSSlot, IPublicTypeSlotSchema, IPublicEnumTransformStage, IPublicModelProp } from '@alilc/lowcode-types';
import { uniqueId, isPlainObject, hasOwnProperty, compatStage, isJSExpression, isJSSlot } from '@alilc/lowcode-utils'; import { uniqueId, isPlainObject, hasOwnProperty, compatStage, isJSExpression, isJSSlot } from '@alilc/lowcode-utils';
import { valueToSource } from './value-to-source'; import { valueToSource } from './value-to-source';
import { Props, IProps, IPropParent } from './props'; import { IProps, IPropParent } from './props';
import { SlotNode, INode } from '../node'; import { SlotNode, INode } from '../node';
// import { TransformStage } from '../transform-stage'; // import { TransformStage } from '../transform-stage';
@ -11,19 +11,25 @@ export const UNSET = Symbol.for('unset');
// eslint-disable-next-line no-redeclare // eslint-disable-next-line no-redeclare
export type UNSET = typeof UNSET; export type UNSET = typeof UNSET;
export interface IProp extends Omit<IPublicModelProp, 'exportSchema' | 'node' | 'slotNode' > { export interface IProp extends Omit<IPublicModelProp<
INode
>, 'exportSchema' | 'node' > {
readonly props: Props; readonly props: IProps;
readonly owner: INode; readonly owner: INode;
get slotNode(): INode | null;
delete(prop: Prop): void; delete(prop: Prop): void;
export(stage: IPublicEnumTransformStage): IPublicTypeCompositeValue; export(stage: IPublicEnumTransformStage): IPublicTypeCompositeValue;
getNode(): INode; getNode(): INode;
getAsString(): string;
unset(): void;
get value(): IPublicTypeCompositeValue | UNSET;
} }
export type ValueTypes = 'unset' | 'literal' | 'map' | 'list' | 'expression' | 'slot'; export type ValueTypes = 'unset' | 'literal' | 'map' | 'list' | 'expression' | 'slot';
@ -43,7 +49,7 @@ export class Prop implements IProp, IPropParent {
*/ */
@obx spread: boolean; @obx spread: boolean;
readonly props: Props; readonly props: IProps;
readonly options: any; readonly options: any;
@ -303,7 +309,7 @@ export class Prop implements IProp, IPropParent {
return this._value; return this._value;
} }
const values = this.items!.map((prop) => { const values = this.items!.map((prop) => {
return prop.export(stage); return prop?.export(stage);
}); });
if (values.every((val) => val === undefined)) { if (values.every((val) => val === undefined)) {
return undefined; return undefined;
@ -401,7 +407,7 @@ export class Prop implements IProp, IPropParent {
slotSchema = { slotSchema = {
componentName: 'Slot', componentName: 'Slot',
title: value.title || value.props?.slotTitle, title: value.title || value.props?.slotTitle,
id: data.id, id: value.id,
name: value.name || value.props?.slotName, name: value.name || value.props?.slotName,
params: value.params || value.props?.slotParams, params: value.params || value.props?.slotParams,
children: value.children, children: value.children,

View File

@ -1,8 +1,8 @@
import { computed, makeObservable, obx, action } from '@alilc/lowcode-editor-core'; import { computed, makeObservable, obx, action } from '@alilc/lowcode-editor-core';
import { IPublicTypePropsMap, IPublicTypePropsList, IPublicTypeCompositeValue, IPublicEnumTransformStage, IPublicModelProps } from '@alilc/lowcode-types'; import { IPublicTypePropsMap, IPublicTypePropsList, IPublicTypeCompositeValue, IPublicEnumTransformStage, IBaseModelProps } from '@alilc/lowcode-types';
import { uniqueId, compatStage } from '@alilc/lowcode-utils'; import { uniqueId, compatStage } from '@alilc/lowcode-utils';
import { Prop, IProp, UNSET } from './prop'; import { Prop, IProp, UNSET } from './prop';
import { INode, Node } from '../node'; import { INode } from '../node';
// import { TransformStage } from '../transform-stage'; // import { TransformStage } from '../transform-stage';
interface ExtrasObject { interface ExtrasObject {
@ -33,19 +33,29 @@ export interface IPropParent {
get path(): string[]; get path(): string[];
delete(prop: Prop): void; delete(prop: Prop): void;
} }
export interface IProps extends Omit<IPublicModelProps, 'getProp' | 'getExtraProp' | 'getExtraPropValue' | 'setExtraPropValue' | 'node'> { export interface IProps extends Omit<IBaseModelProps<IProp>, | 'getExtraProp' | 'getExtraPropValue' | 'setExtraPropValue' | 'node'> {
/** /**
* props node * props node
*/ */
getNode(): INode; 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;
purge(): void;
query(path: string, createIfNone: boolean): Prop | null;
import(value?: IPublicTypePropsMap | IPublicTypePropsList | null, extras?: ExtrasObject): void;
} }
export class Props implements IProps, IPropParent { export class Props implements IProps, IPropParent {

View File

@ -1,20 +1,10 @@
import { obx, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; 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 { DocumentModel } from './document-model';
import { IPublicModelSelection } from '@alilc/lowcode-types'; import { IPublicModelSelection } from '@alilc/lowcode-types';
export interface ISelection extends Omit< IPublicModelSelection, 'getNodes' | 'getTopNodes' > { export interface ISelection extends Omit<IPublicModelSelection<INode>, 'node'> {
/**
*
* @returns
*/
getNodes(): INode[];
/**
*
*/
getTopNodes(includeRoot?: boolean): INode[];
} }
export class Selection implements ISelection { 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) { for (const id of this._selected) {
const parent = this.doc.getNode(id); const parent = this.doc.getNode(id);
if (excludeRoot && parent?.contains(this.doc.focusNode)) { if (excludeRoot && parent?.contains(this.doc.focusNode)) {
@ -131,8 +121,8 @@ export class Selection implements ISelection {
/** /**
* *
*/ */
getNodes(): Node[] { getNodes(): INode[] {
const nodes = []; const nodes: INode[] = [];
for (const id of this._selected) { for (const id of this._selected) {
const node = this.doc.getNode(id); const node = this.doc.getNode(id);
if (node) { if (node) {

View File

@ -16,6 +16,7 @@ import {
IPublicApiPlugins, IPublicApiPlugins,
IPublicTypePluginDeclaration, IPublicTypePluginDeclaration,
IPublicApiCanvas, IPublicApiCanvas,
IPublicApiWorkspace,
} from '@alilc/lowcode-types'; } from '@alilc/lowcode-types';
import { import {
IPluginContextOptions, IPluginContextOptions,
@ -24,8 +25,8 @@ import {
} from './plugin-types'; } from './plugin-types';
import { isValidPreferenceKey } from './plugin-utils'; import { isValidPreferenceKey } from './plugin-utils';
export default class PluginContext implements
export default class PluginContext implements IPublicModelPluginContext, ILowCodePluginContextPrivate { IPublicModelPluginContext, ILowCodePluginContextPrivate {
hotkey: IPublicApiHotkey; hotkey: IPublicApiHotkey;
project: IPublicApiProject; project: IPublicApiProject;
skeleton: IPublicApiSkeleton; skeleton: IPublicApiSkeleton;
@ -39,6 +40,7 @@ export default class PluginContext implements IPublicModelPluginContext, ILowCod
preference: IPluginPreferenceMananger; preference: IPluginPreferenceMananger;
pluginEvent: IPublicApiEvent; pluginEvent: IPublicApiEvent;
canvas: IPublicApiCanvas; canvas: IPublicApiCanvas;
workspace: IPublicApiWorkspace;
constructor( constructor(
options: IPluginContextOptions, options: IPluginContextOptions,

View File

@ -12,13 +12,31 @@ import {
import { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils'; import { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils';
import { ISimulatorHost } from '../simulator'; 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 designer(): IDesigner;
get simulator(): ISimulatorHost | null; get simulator(): ISimulatorHost | null;
get currentDocument(): IDocumentModel | null; get currentDocument(): IDocumentModel | null | undefined;
get documents(): IDocumentModel[]; get documents(): IDocumentModel[];
@ -60,6 +78,8 @@ export interface IProject extends Omit< IPublicApiProject, 'simulatorHost' | 'im
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
value: any, value: any,
): void; ): void;
checkExclusive(activeDoc: DocumentModel): void;
} }
export class Project implements IProject { export class Project implements IProject {
@ -85,7 +105,7 @@ export class Project implements IProject {
return this._simulator || null; return this._simulator || null;
} }
@computed get currentDocument(): IDocumentModel | null { @computed get currentDocument(): IDocumentModel | null | undefined {
return this.documents.find((doc) => doc.active); return this.documents.find((doc) => doc.active);
} }

View File

@ -2,7 +2,7 @@ import { ComponentType } from 'react';
import { IPublicTypeComponentMetadata, IPublicTypeNodeSchema, IPublicTypeScrollable, IPublicTypeComponentInstance, IPublicModelSensor, IPublicTypeNodeInstance } from '@alilc/lowcode-types'; import { IPublicTypeComponentMetadata, IPublicTypeNodeSchema, IPublicTypeScrollable, IPublicTypeComponentInstance, IPublicModelSensor, IPublicTypeNodeInstance } from '@alilc/lowcode-types';
import { Point, ScrollTarget, ILocateEvent } from './designer'; import { Point, ScrollTarget, ILocateEvent } from './designer';
import { BuiltinSimulatorRenderer } from './builtin-simulator/renderer'; import { BuiltinSimulatorRenderer } from './builtin-simulator/renderer';
import { Node, INode } from './document'; import { INode } from './document';
export type AutoFit = '100%'; export type AutoFit = '100%';
// eslint-disable-next-line no-redeclare // eslint-disable-next-line no-redeclare
@ -132,7 +132,7 @@ export interface ISimulatorHost<P = object> extends IPublicModelSensor {
/** /**
* *
*/ */
scrollToNode(node: Node, detail?: any): void; scrollToNode(node: INode, detail?: any): void;
/** /**
* *
@ -147,7 +147,7 @@ export interface ISimulatorHost<P = object> extends IPublicModelSensor {
/** /**
* *
*/ */
getComponentInstances(node: Node): IPublicTypeComponentInstance[] | null; getComponentInstances(node: INode): IPublicTypeComponentInstance[] | null;
/** /**
* schema * schema
@ -157,11 +157,11 @@ export interface ISimulatorHost<P = object> extends IPublicModelSensor {
/** /**
* *
*/ */
getComponentContext(node: Node): object | null; getComponentContext(node: INode): object | null;
getClosestNodeInstance(from: IPublicTypeComponentInstance, specId?: string): IPublicTypeNodeInstance | 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; computeComponentInstanceRect(instance: IPublicTypeComponentInstance, selector?: string): DOMRect | null;
@ -189,6 +189,6 @@ export function isSimulatorHost(obj: any): obj is ISimulatorHost {
export type Component = ComponentType<any> | object; export type Component = ComponentType<any> | object;
export interface INodeSelector { export interface INodeSelector {
node: Node; node: INode;
instance?: IPublicTypeComponentInstance; instance?: IPublicTypeComponentInstance;
} }

View File

@ -23,7 +23,7 @@ describe('document-model 测试', () => {
it('empty schema', () => { it('empty schema', () => {
const doc = new DocumentModel(project); 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.currentRoot).toBe(doc.rootNode);
expect(doc.root).toBe(doc.rootNode); expect(doc.root).toBe(doc.rootNode);
expect(doc.modalNode).toBeUndefined(); expect(doc.modalNode).toBeUndefined();

View File

@ -1,8 +1,8 @@
import set from 'lodash/set'; import set from 'lodash/set';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
import '../../fixtures/window'; import '../../fixtures/window';
import { Project } from '../../../src/project/project'; import { Project, IProject } from '../../../src/project/project';
import { Node } from '../../../src/document/node/node'; import { Node, INode } from '../../../src/document/node/node';
import { Designer } from '../../../src/designer/designer'; import { Designer } from '../../../src/designer/designer';
import formSchema from '../../fixtures/schema/form'; import formSchema from '../../fixtures/schema/form';
import { getIdsFromSchema, getNodeFromSchemaById } from '../../utils'; import { getIdsFromSchema, getNodeFromSchemaById } from '../../utils';
@ -37,7 +37,7 @@ beforeAll(() => {
describe('schema 生成节点模型测试', () => { describe('schema 生成节点模型测试', () => {
describe('block ❌ | component ❌ | slot ❌', () => { describe('block ❌ | component ❌ | slot ❌', () => {
let project: Project; let project: IProject;
beforeEach(() => { beforeEach(() => {
project = new Project(designer, { project = new Project(designer, {
componentsTree: [ componentsTree: [
@ -52,12 +52,12 @@ describe('schema 生成节点模型测试', () => {
it('基本的节点模型初始化,模型导出', () => { it('基本的节点模型初始化,模型导出', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const nodesMap = currentDocument?.nodesMap;
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
const expectedNodeCnt = ids.length; const expectedNodeCnt = ids.length;
expect(nodesMap.size).toBe(expectedNodeCnt); expect(nodesMap?.size).toBe(expectedNodeCnt);
ids.forEach(id => { 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'); const pageNode = currentDocument?.getNode('page');
@ -76,18 +76,18 @@ describe('schema 生成节点模型测试', () => {
it('基本的节点模型初始化,节点深度', () => { it('基本的节点模型初始化,节点深度', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const { currentDocument } = project; const { currentDocument } = project;
const getNode = currentDocument.getNode.bind(currentDocument); const getNode = currentDocument?.getNode.bind(currentDocument);
const pageNode = getNode('page'); const pageNode = getNode?.('page');
const rootHeaderNode = getNode('node_k1ow3cba'); const rootHeaderNode = getNode?.('node_k1ow3cba');
const rootContentNode = getNode('node_k1ow3cbb'); const rootContentNode = getNode?.('node_k1ow3cbb');
const rootFooterNode = getNode('node_k1ow3cbc'); const rootFooterNode = getNode?.('node_k1ow3cbc');
const formNode = getNode('form'); const formNode = getNode?.('form');
const cardNode = getNode('node_k1ow3cbj'); const cardNode = getNode?.('node_k1ow3cbj');
const cardContentNode = getNode('node_k1ow3cbk'); const cardContentNode = getNode?.('node_k1ow3cbk');
const columnsLayoutNode = getNode('node_k1ow3cbw'); const columnsLayoutNode = getNode?.('node_k1ow3cbw');
const columnNode = getNode('node_k1ow3cbx'); const columnNode = getNode?.('node_k1ow3cbx');
const textFieldNode = getNode('node_k1ow3cbz'); const textFieldNode = getNode?.('node_k1ow3cbz');
expect(pageNode?.zLevel).toBe(0); expect(pageNode?.zLevel).toBe(0);
expect(rootHeaderNode?.zLevel).toBe(1); expect(rootHeaderNode?.zLevel).toBe(1);
@ -131,7 +131,7 @@ describe('schema 生成节点模型测试', () => {
const textFieldNode = getNode('node_k1ow3cbz'); const textFieldNode = getNode('node_k1ow3cbz');
expect(pageNode?.index).toBe(-1); 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?.children?.get(1)).toBe(rootContentNode);
expect(pageNode?.getChildren()?.get(1)).toBe(rootContentNode); expect(pageNode?.getChildren()?.get(1)).toBe(rootContentNode);
expect(pageNode?.getNode()).toBe(pageNode); expect(pageNode?.getNode()).toBe(pageNode);
@ -162,20 +162,20 @@ describe('schema 生成节点模型测试', () => {
it('基本的节点模型初始化,节点新建、删除等事件', () => { it('基本的节点模型初始化,节点新建、删除等事件', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const { currentDocument } = project; const { currentDocument } = project;
const getNode = currentDocument.getNode.bind(currentDocument); const getNode = currentDocument?.getNode.bind(currentDocument);
const createNode = currentDocument.createNode.bind(currentDocument); const createNode = currentDocument?.createNode.bind(currentDocument);
const pageNode = getNode('page'); const pageNode = getNode?.('page');
const nodeCreateHandler = jest.fn(); const nodeCreateHandler = jest.fn();
const offCreate = currentDocument?.onNodeCreate(nodeCreateHandler); const offCreate = currentDocument?.onNodeCreate(nodeCreateHandler);
const node = createNode({ const node = createNode?.({
componentName: 'TextInput', componentName: 'TextInput',
props: { props: {
propA: 'haha', propA: 'haha',
}, },
}); });
currentDocument?.insertNode(pageNode, node); pageNode && node && currentDocument?.insertNode(pageNode, node);
expect(nodeCreateHandler).toHaveBeenCalledTimes(1); expect(nodeCreateHandler).toHaveBeenCalledTimes(1);
expect(nodeCreateHandler.mock.calls[0][0]).toBe(node); expect(nodeCreateHandler.mock.calls[0][0]).toBe(node);
@ -184,7 +184,7 @@ describe('schema 生成节点模型测试', () => {
const nodeDestroyHandler = jest.fn(); const nodeDestroyHandler = jest.fn();
const offDestroy = currentDocument?.onNodeDestroy(nodeDestroyHandler); const offDestroy = currentDocument?.onNodeDestroy(nodeDestroyHandler);
node.remove(); node?.remove();
expect(nodeDestroyHandler).toHaveBeenCalledTimes(1); expect(nodeDestroyHandler).toHaveBeenCalledTimes(1);
expect(nodeDestroyHandler.mock.calls[0][0]).toBe(node); expect(nodeDestroyHandler.mock.calls[0][0]).toBe(node);
expect(nodeDestroyHandler.mock.calls[0][0].componentName).toBe('TextInput'); expect(nodeDestroyHandler.mock.calls[0][0].componentName).toBe('TextInput');
@ -290,9 +290,9 @@ describe('schema 生成节点模型测试', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap.get('form'); const formNode = nodesMap?.get('form');
currentDocument?.insertNode(formNode, { formNode && currentDocument?.insertNode(formNode, {
componentName: 'TextInput', componentName: 'TextInput',
id: 'nodeschema-id1', id: 'nodeschema-id1',
props: { props: {
@ -300,11 +300,11 @@ describe('schema 生成节点模型测试', () => {
propB: 3, propB: 3,
}, },
}, 0); }, 0);
expect(nodesMap.size).toBe(ids.length + 1); expect(nodesMap?.size).toBe(ids.length + 1);
expect(formNode.children.length).toBe(4); expect(formNode?.children?.length).toBe(4);
const insertedNode = formNode.children.get(0); const insertedNode = formNode?.children?.get(0);
expect(insertedNode.componentName).toBe('TextInput'); expect(insertedNode?.componentName).toBe('TextInput');
expect(insertedNode.propsData).toEqual({ expect(insertedNode?.propsData).toEqual({
propA: 'haha', propA: 'haha',
propB: 3, propB: 3,
}); });
@ -316,9 +316,9 @@ describe('schema 生成节点模型测试', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap.get('form'); const formNode = nodesMap?.get('form');
currentDocument?.insertNode(formNode, { formNode && currentDocument?.insertNode(formNode, {
componentName: 'TextInput', componentName: 'TextInput',
id: 'nodeschema-id1', id: 'nodeschema-id1',
props: { props: {
@ -326,11 +326,11 @@ describe('schema 生成节点模型测试', () => {
propB: 3, propB: 3,
}, },
}, 1); }, 1);
expect(nodesMap.size).toBe(ids.length + 1); expect(nodesMap?.size).toBe(ids.length + 1);
expect(formNode.children.length).toBe(4); expect(formNode?.children?.length).toBe(4);
const insertedNode = formNode.children.get(1); const insertedNode = formNode?.children?.get(1);
expect(insertedNode.componentName).toBe('TextInput'); expect(insertedNode?.componentName).toBe('TextInput');
expect(insertedNode.propsData).toEqual({ expect(insertedNode?.propsData).toEqual({
propA: 'haha', propA: 'haha',
propB: 3, propB: 3,
}); });
@ -342,8 +342,8 @@ describe('schema 生成节点模型测试', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap.get('form') as Node; const formNode = nodesMap?.get('form') as INode;
currentDocument?.insertNode(formNode, { currentDocument?.insertNode(formNode, {
componentName: 'ParentNode', componentName: 'ParentNode',
props: { props: {
@ -367,8 +367,8 @@ describe('schema 生成节点模型测试', () => {
}, },
], ],
}); });
expect(nodesMap.size).toBe(ids.length + 3); expect(nodesMap?.size).toBe(ids.length + 3);
expect(formNode.children.length).toBe(4); expect(formNode.children?.length).toBe(4);
expect(formNode.children?.get(3)?.componentName).toBe('ParentNode'); 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(0)?.componentName).toBe('SubNode');
expect(formNode.children?.get(3)?.children?.get(1)?.componentName).toBe('SubNode2'); expect(formNode.children?.get(3)?.children?.get(1)?.componentName).toBe('SubNode2');
@ -378,9 +378,9 @@ describe('schema 生成节点模型测试', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap.get('form'); const formNode = nodesMap?.get('form');
currentDocument?.insertNode(formNode, { formNode && currentDocument?.insertNode(formNode, {
componentName: 'TextInput', componentName: 'TextInput',
id: 'nodeschema-id1', id: 'nodeschema-id1',
props: { props: {
@ -388,17 +388,17 @@ describe('schema 生成节点模型测试', () => {
propB: 3, propB: 3,
}, },
}); });
expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput'); expect(nodesMap?.get('nodeschema-id1')?.componentName).toBe('TextInput');
expect(nodesMap.size).toBe(ids.length + 1); expect(nodesMap?.size).toBe(ids.length + 1);
}); });
it.skip('场景一:插入 NodeSchemaid 与现有 schema 里的 id 重复,但关闭了 id 检测器', () => { it.skip('场景一:插入 NodeSchemaid 与现有 schema 里的 id 重复,但关闭了 id 检测器', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap.get('form'); const formNode = nodesMap?.get('form');
currentDocument?.insertNode(formNode, { formNode && currentDocument?.insertNode(formNode, {
componentName: 'TextInput', componentName: 'TextInput',
id: 'nodeschema-id1', id: 'nodeschema-id1',
props: { props: {
@ -406,16 +406,16 @@ describe('schema 生成节点模型测试', () => {
propB: 3, propB: 3,
}, },
}); });
expect(nodesMap.get('nodeschema-id1').componentName).toBe('TextInput'); expect(nodesMap?.get('nodeschema-id1')?.componentName).toBe('TextInput');
expect(nodesMap.size).toBe(ids.length + 1); expect(nodesMap?.size).toBe(ids.length + 1);
}); });
it('场景二:插入 Node 实例', () => { it('场景二:插入 Node 实例', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap.get('form'); const formNode = nodesMap?.get('form');
const inputNode = currentDocument?.createNode({ const inputNode = currentDocument?.createNode({
componentName: 'TextInput', componentName: 'TextInput',
id: 'nodeschema-id2', id: 'nodeschema-id2',
@ -424,22 +424,22 @@ describe('schema 生成节点模型测试', () => {
propB: 3, propB: 3,
}, },
}); });
currentDocument?.insertNode(formNode, inputNode); formNode && currentDocument?.insertNode(formNode, inputNode);
expect(formNode.children?.get(3)?.componentName).toBe('TextInput'); expect(formNode?.children?.get(3)?.componentName).toBe('TextInput');
expect(nodesMap.size).toBe(ids.length + 1); expect(nodesMap?.size).toBe(ids.length + 1);
}); });
it('场景三:插入 JSExpression', () => { it('场景三:插入 JSExpression', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap.get('form') as Node; const formNode = nodesMap?.get('form') as Node;
currentDocument?.insertNode(formNode, { currentDocument?.insertNode(formNode, {
type: 'JSExpression', type: 'JSExpression',
value: 'just a expression', 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)?.componentName).toBe('Leaf');
// expect(formNode.children?.get(3)?.children).toEqual({ // expect(formNode.children?.get(3)?.children).toEqual({
// type: 'JSExpression', // type: 'JSExpression',
@ -450,10 +450,10 @@ describe('schema 生成节点模型测试', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap.get('form') as Node; const formNode = nodesMap?.get('form') as Node;
currentDocument?.insertNode(formNode, 'just a string'); 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)?.componentName).toBe('Leaf');
// expect(formNode.children?.get(3)?.children).toBe('just a string'); // expect(formNode.children?.get(3)?.children).toBe('just a string');
}); });
@ -473,8 +473,8 @@ describe('schema 生成节点模型测试', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap.get('form') as Node; const formNode = nodesMap?.get('form') as Node;
const formNode2 = currentDocument?.getNode('form'); const formNode2 = currentDocument?.getNode('form');
expect(formNode).toEqual(formNode2); expect(formNode).toEqual(formNode2);
currentDocument?.insertNodes(formNode, [ currentDocument?.insertNodes(formNode, [
@ -493,17 +493,17 @@ describe('schema 生成节点模型测试', () => {
}, },
}, },
], 1); ], 1);
expect(nodesMap.size).toBe(ids.length + 2); expect(nodesMap?.size).toBe(ids.length + 2);
expect(formNode.children?.length).toBe(5); expect(formNode.children?.length).toBe(5);
const insertedNode1 = formNode.children.get(1); const insertedNode1 = formNode.children?.get(1);
const insertedNode2 = formNode.children.get(2); const insertedNode2 = formNode.children?.get(2);
expect(insertedNode1.componentName).toBe('TextInput'); expect(insertedNode1?.componentName).toBe('TextInput');
expect(insertedNode1.propsData).toEqual({ expect(insertedNode1?.propsData).toEqual({
propA: 'haha2', propA: 'haha2',
propB: 3, propB: 3,
}); });
expect(insertedNode2.componentName).toBe('TextInput2'); expect(insertedNode2?.componentName).toBe('TextInput2');
expect(insertedNode2.propsData).toEqual({ expect(insertedNode2?.propsData).toEqual({
propA: 'haha', propA: 'haha',
propB: 3, propB: 3,
}); });
@ -513,8 +513,8 @@ describe('schema 生成节点模型测试', () => {
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap.get('form') as Node; const formNode = nodesMap?.get('form') as INode;
const formNode2 = currentDocument?.getNode('form'); const formNode2 = currentDocument?.getNode('form');
expect(formNode).toEqual(formNode2); expect(formNode).toEqual(formNode2);
const createdNode1 = currentDocument?.createNode({ const createdNode1 = currentDocument?.createNode({
@ -532,17 +532,17 @@ describe('schema 生成节点模型测试', () => {
}, },
}); });
currentDocument?.insertNodes(formNode, [createdNode1, createdNode2], 1); 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); expect(formNode.children?.length).toBe(5);
const insertedNode1 = formNode.children.get(1); const insertedNode1 = formNode.children?.get(1);
const insertedNode2 = formNode.children.get(2); const insertedNode2 = formNode.children?.get(2);
expect(insertedNode1.componentName).toBe('TextInput'); expect(insertedNode1?.componentName).toBe('TextInput');
expect(insertedNode1.propsData).toEqual({ expect(insertedNode1?.propsData).toEqual({
propA: 'haha2', propA: 'haha2',
propB: 3, propB: 3,
}); });
expect(insertedNode2.componentName).toBe('TextInput2'); expect(insertedNode2?.componentName).toBe('TextInput2');
expect(insertedNode2.propsData).toEqual({ expect(insertedNode2?.propsData).toEqual({
propA: 'haha', propA: 'haha',
propB: 3, propB: 3,
}); });
@ -561,13 +561,13 @@ describe('schema 生成节点模型测试', () => {
project.open(); project.open();
expect(project).toBeTruthy(); expect(project).toBeTruthy();
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const nodesMap = currentDocument?.nodesMap;
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
// 目前每个 slot 会新增1 + children.length个节点 // 目前每个 slot 会新增1 + children.length个节点
const expectedNodeCnt = ids.length + 2; const expectedNodeCnt = ids.length + 2;
expect(nodesMap.size).toBe(expectedNodeCnt); expect(nodesMap?.size).toBe(expectedNodeCnt);
// PageHeader // PageHeader
expect(nodesMap.get('node_k1ow3cbd').slots).toHaveLength(1); expect(nodesMap?.get('node_k1ow3cbd')?.slots).toHaveLength(1);
}); });
}); });
}); });

View File

@ -499,6 +499,59 @@ describe('Prop 类测试', () => {
expect(slotProp.purged).toBeTruthy(); expect(slotProp.purged).toBeTruthy();
slotProp.dispose(); 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',
id: 'node_oclei5rv2e2',
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');
expect(slotProp.slotNode?.export()?.id).toBe('node_oclei5rv2e2');
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('其他导出函数', () => { describe('其他导出函数', () => {

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-editor-core", "name": "@alilc/lowcode-editor-core",
"version": "1.1.2", "version": "1.1.3",
"description": "Core Api for Ali lowCode engine", "description": "Core Api for Ali lowCode engine",
"license": "MIT", "license": "MIT",
"main": "lib/index.js", "main": "lib/index.js",
@ -14,8 +14,8 @@
}, },
"dependencies": { "dependencies": {
"@alifd/next": "^1.19.16", "@alifd/next": "^1.19.16",
"@alilc/lowcode-types": "1.1.2", "@alilc/lowcode-types": "1.1.3",
"@alilc/lowcode-utils": "1.1.2", "@alilc/lowcode-utils": "1.1.3",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"debug": "^4.1.1", "debug": "^4.1.1",
"intl-messageformat": "^9.3.1", "intl-messageformat": "^9.3.1",

View File

@ -124,9 +124,7 @@ const VALID_ENGINE_OPTIONS = {
type: 'array', type: 'array',
description: '自定义 simulatorUrl 的地址', 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: { appHelper: {
type: 'object', type: 'object',
description: '定义 utils 和 constants 等对象', description: '定义 utils 和 constants 等对象',
@ -149,7 +147,6 @@ const VALID_ENGINE_OPTIONS = {
}, },
}; };
const getStrictModeValue = (engineOptions: IPublicTypeEngineOptions, defaultValue: boolean): boolean => { const getStrictModeValue = (engineOptions: IPublicTypeEngineOptions, defaultValue: boolean): boolean => {
if (!engineOptions || !isPlainObject(engineOptions)) { if (!engineOptions || !isPlainObject(engineOptions)) {
return defaultValue; return defaultValue;
@ -161,7 +158,8 @@ const getStrictModeValue = (engineOptions: IPublicTypeEngineOptions, defaultValu
return engineOptions.enableStrictPluginMode; return engineOptions.enableStrictPluginMode;
}; };
export interface IEngineConfigPrivate { export interface IEngineConfig extends IPublicModelEngineConfig {
/** /**
* if engineOptions.strictPluginMode === true, only accept propertied predefined in EngineOptions. * if engineOptions.strictPluginMode === true, only accept propertied predefined in EngineOptions.
* *
@ -176,8 +174,7 @@ export interface IEngineConfigPrivate {
delWait(key: string, fn: any): void; delWait(key: string, fn: any): void;
} }
export class EngineConfig implements IEngineConfig {
export class EngineConfig implements IPublicModelEngineConfig, IEngineConfigPrivate {
private config: { [key: string]: any } = {}; private config: { [key: string]: any } = {};
private waits = new Map< private waits = new Map<
@ -291,13 +288,11 @@ export class EngineConfig implements IPublicModelEngineConfig, IEngineConfigPriv
const val = this.config?.[key]; const val = this.config?.[key];
if (val !== undefined) { if (val !== undefined) {
fn(val); 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 { notifyGot(key: string): void {
@ -350,4 +345,4 @@ export class EngineConfig implements IPublicModelEngineConfig, IEngineConfigPriv
} }
} }
export const engineConfig = new EngineConfig(); export const engineConfig = new EngineConfig();

View File

@ -123,6 +123,7 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor
await (new AssetLoader()).load(url); await (new AssetLoader()).load(url);
function setAssetsComponent(component: any, extraNpmInfo: any = {}) { function setAssetsComponent(component: any, extraNpmInfo: any = {}) {
const components = component.components; const components = component.components;
assets.componentList = assets.componentList?.concat(component.componentList || []);
if (Array.isArray(components)) { if (Array.isArray(components)) {
components.forEach(d => { components.forEach(d => {
assets.components = assets.components.concat({ assets.components = assets.components.concat({
@ -144,7 +145,6 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor
...component.components, ...component.components,
} || []); } || []);
} }
// assets.componentList = assets.componentList.concat(component.componentList || []);
} }
function setArrayAssets(value: any[], preExportName: string = '', preSubName: string = '') { function setArrayAssets(value: any[], preExportName: string = '', preSubName: string = '') {
value.forEach((d: any, i: number) => { value.forEach((d: any, i: number) => {
@ -190,13 +190,11 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor
const x = this.context.get(keyOrType); const x = this.context.get(keyOrType);
if (x !== undefined) { if (x !== undefined) {
fn(x); 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 { 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()); export const commonEvent = new EventBus(new EventEmitter());

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-editor-skeleton", "name": "@alilc/lowcode-editor-skeleton",
"version": "1.1.2", "version": "1.1.3",
"description": "alibaba lowcode editor skeleton", "description": "alibaba lowcode editor skeleton",
"main": "lib/index.js", "main": "lib/index.js",
"module": "es/index.js", "module": "es/index.js",
@ -18,10 +18,10 @@
], ],
"dependencies": { "dependencies": {
"@alifd/next": "^1.20.12", "@alifd/next": "^1.20.12",
"@alilc/lowcode-designer": "1.1.2", "@alilc/lowcode-designer": "1.1.3",
"@alilc/lowcode-editor-core": "1.1.2", "@alilc/lowcode-editor-core": "1.1.3",
"@alilc/lowcode-types": "1.1.2", "@alilc/lowcode-types": "1.1.3",
"@alilc/lowcode-utils": "1.1.2", "@alilc/lowcode-utils": "1.1.3",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"react": "^16.8.1", "react": "^16.8.1",
"react-dom": "^16.8.1" "react-dom": "^16.8.1"

View File

@ -3,7 +3,7 @@ import { shallowIntl, observer, obx, engineConfig, runInAction, globalContext }
import { createContent, isJSSlot, isSetterConfig, isSettingField } from '@alilc/lowcode-utils'; import { createContent, isJSSlot, isSetterConfig, isSettingField } from '@alilc/lowcode-utils';
import { Skeleton } from '@alilc/lowcode-editor-skeleton'; import { Skeleton } from '@alilc/lowcode-editor-skeleton';
import { IPublicTypeCustomView } from '@alilc/lowcode-types'; 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 { createField } from '../field';
import PopupService, { PopupPipe } from '../popup'; import PopupService, { PopupPipe } from '../popup';
import { SkeletonContext } from '../../context'; import { SkeletonContext } from '../../context';
@ -58,7 +58,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
stageName = `${field.getNode().id}_${field.name.toString()}`; stageName = `${field.getNode().id}_${field.name.toString()}`;
// 清除原 stage不然 content 引用的一直是老的 field导致数据无法得到更新 // 清除原 stage不然 content 引用的一直是老的 field导致数据无法得到更新
stages.container.remove(stageName); stages.container.remove(stageName);
const stage = stages.add({ stages.add({
type: 'Widget', type: 'Widget',
name: stageName, name: stageName,
content: <Fragment>{field.items.map((item, index) => createSettingFieldView(item, field, index))}</Fragment>, content: <Fragment>{field.items.map((item, index) => createSettingFieldView(item, field, index))}</Fragment>,
@ -324,7 +324,7 @@ class SettingGroupView extends Component<SettingGroupViewProps> {
} }
} }
export function createSettingFieldView(item: SettingField | IPublicTypeCustomView, field: SettingEntry, index?: number) { export function createSettingFieldView(item: SettingField | IPublicTypeCustomView, field: ISettingEntry, index?: number) {
if (isSettingField(item)) { if (isSettingField(item)) {
if (item.isGroup) { if (item.isGroup) {
return <SettingGroupView field={item} key={item.id} />; return <SettingGroupView field={item} key={item.id} />;

View File

@ -71,7 +71,7 @@ skeleton.add({
area: 'topArea', area: 'topArea',
type: 'Widget', type: 'Widget',
name: 'logo', name: 'logo',
content: YourFantaticLogo, content: YourFantasticLogo,
contentProps: { contentProps: {
logo: logo:
'https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png', 'https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png',

View File

@ -71,7 +71,7 @@ skeleton.add({
area: 'topArea', area: 'topArea',
type: 'Widget', type: 'Widget',
name: 'logo', name: 'logo',
content: YourFantaticLogo, content: YourFantasticLogo,
contentProps: { contentProps: {
logo: logo:
'https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png', 'https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png',

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-engine", "name": "@alilc/lowcode-engine",
"version": "1.1.2", "version": "1.1.3",
"description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系",
"main": "lib/engine-core.js", "main": "lib/engine-core.js",
"module": "es/engine-core.js", "module": "es/engine-core.js",
@ -19,15 +19,15 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@alifd/next": "^1.19.12", "@alifd/next": "^1.19.12",
"@alilc/lowcode-designer": "1.1.2", "@alilc/lowcode-designer": "1.1.3",
"@alilc/lowcode-editor-core": "1.1.2", "@alilc/lowcode-editor-core": "1.1.3",
"@alilc/lowcode-editor-skeleton": "1.1.2", "@alilc/lowcode-editor-skeleton": "1.1.3",
"@alilc/lowcode-engine-ext": "^1.0.0", "@alilc/lowcode-engine-ext": "^1.0.0",
"@alilc/lowcode-plugin-designer": "1.1.2", "@alilc/lowcode-plugin-designer": "1.1.3",
"@alilc/lowcode-plugin-outline-pane": "1.1.2", "@alilc/lowcode-plugin-outline-pane": "1.1.3",
"@alilc/lowcode-shell": "1.1.2", "@alilc/lowcode-shell": "1.1.3",
"@alilc/lowcode-utils": "1.1.2", "@alilc/lowcode-utils": "1.1.3",
"@alilc/lowcode-workspace": "1.1.2", "@alilc/lowcode-workspace": "1.1.3",
"react": "^16.8.1", "react": "^16.8.1",
"react-dom": "^16.8.1" "react-dom": "^16.8.1"
}, },

View File

@ -43,6 +43,7 @@ import {
Logger, Logger,
Canvas, Canvas,
Workspace, Workspace,
Config,
} from '@alilc/lowcode-shell'; } from '@alilc/lowcode-shell';
import { isPlainObject } from '@alilc/lowcode-utils'; import { isPlainObject } from '@alilc/lowcode-utils';
import './modules/live-editing'; import './modules/live-editing';
@ -96,7 +97,7 @@ editor.set('project', project);
editor.set('setters' as any, setters); editor.set('setters' as any, setters);
editor.set('material', material); editor.set('material', material);
editor.set('innerHotkey', innerHotkey); editor.set('innerHotkey', innerHotkey);
const config = engineConfig; const config = new Config(engineConfig);
const event = new Event(commonEvent, { prefix: 'common' }); const event = new Event(commonEvent, { prefix: 'common' });
const logger = new Logger({ level: 'warn', bizName: 'common' }); const logger = new Logger({ level: 'warn', bizName: 'common' });
const common = new Common(editor, innerSkeleton); const common = new Common(editor, innerSkeleton);
@ -118,6 +119,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = {
context.canvas = canvas; context.canvas = canvas;
context.plugins = plugins; context.plugins = plugins;
context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` });
context.workspace = workspace;
}, },
}; };

View File

@ -1,5 +1,5 @@
import { import {
Node as InnerNode, INode,
SettingField as InnerSettingField, SettingField as InnerSettingField,
} from '@alilc/lowcode-designer'; } from '@alilc/lowcode-designer';
import { IShellModelFactory, IPublicModelNode, IPublicModelSettingPropEntry } from '@alilc/lowcode-types'; import { IShellModelFactory, IPublicModelNode, IPublicModelSettingPropEntry } from '@alilc/lowcode-types';
@ -8,7 +8,7 @@ import {
SettingPropEntry, SettingPropEntry,
} from '@alilc/lowcode-shell'; } from '@alilc/lowcode-shell';
class ShellModelFactory implements IShellModelFactory { class ShellModelFactory implements IShellModelFactory {
createNode(node: InnerNode | null | undefined): IPublicModelNode | null { createNode(node: INode | null | undefined): IPublicModelNode | null {
return Node.create(node); return Node.create(node);
} }
createSettingPropEntry(prop: InnerSettingField): IPublicModelSettingPropEntry { createSettingPropEntry(prop: InnerSettingField): IPublicModelSettingPropEntry {

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-ignitor", "name": "@alilc/lowcode-ignitor",
"version": "1.1.2", "version": "1.1.3",
"description": "点火器bootstrap lce project", "description": "点火器bootstrap lce project",
"main": "lib/index.js", "main": "lib/index.js",
"private": true, "private": true,

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-plugin-designer", "name": "@alilc/lowcode-plugin-designer",
"version": "1.1.2", "version": "1.1.3",
"description": "alibaba lowcode editor designer plugin", "description": "alibaba lowcode editor designer plugin",
"files": [ "files": [
"es", "es",
@ -18,9 +18,9 @@
], ],
"author": "xiayang.xy", "author": "xiayang.xy",
"dependencies": { "dependencies": {
"@alilc/lowcode-designer": "1.1.2", "@alilc/lowcode-designer": "1.1.3",
"@alilc/lowcode-editor-core": "1.1.2", "@alilc/lowcode-editor-core": "1.1.3",
"@alilc/lowcode-utils": "1.1.2", "@alilc/lowcode-utils": "1.1.3",
"react": "^16.8.1", "react": "^16.8.1",
"react-dom": "^16.8.1" "react-dom": "^16.8.1"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-plugin-outline-pane", "name": "@alilc/lowcode-plugin-outline-pane",
"version": "1.1.2", "version": "1.1.3",
"description": "Outline pane for Ali lowCode engine", "description": "Outline pane for Ali lowCode engine",
"files": [ "files": [
"es", "es",
@ -13,10 +13,10 @@
}, },
"dependencies": { "dependencies": {
"@alifd/next": "^1.19.16", "@alifd/next": "^1.19.16",
"@alilc/lowcode-designer": "1.1.2", "@alilc/lowcode-designer": "1.1.3",
"@alilc/lowcode-editor-core": "1.1.2", "@alilc/lowcode-editor-core": "1.1.3",
"@alilc/lowcode-types": "1.1.2", "@alilc/lowcode-types": "1.1.3",
"@alilc/lowcode-utils": "1.1.2", "@alilc/lowcode-utils": "1.1.3",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"react": "^16", "react": "^16",
"react-dom": "^16.7.0", "react-dom": "^16.7.0",

View File

@ -3,8 +3,10 @@ import {
IPublicTypeLocationChildrenDetail, IPublicTypeLocationChildrenDetail,
IPublicModelNode, IPublicModelNode,
IPublicModelPluginContext, IPublicModelPluginContext,
IPublicTypeDisposable,
} from '@alilc/lowcode-types'; } from '@alilc/lowcode-types';
import { isI18nData, isLocationChildrenDetail } from '@alilc/lowcode-utils'; import { isI18nData, isLocationChildrenDetail } from '@alilc/lowcode-utils';
import EventEmitter from 'events';
import { Tree } from './tree'; import { Tree } from './tree';
/** /**
@ -21,14 +23,61 @@ export interface FilterResult {
keywords: string; keywords: string;
} }
enum EVENT_NAMES {
filterResultChanged = 'filterResultChanged',
expandedChanged = 'expandedChanged',
hiddenChanged = 'hiddenChanged',
lockedChanged = 'lockedChanged',
titleLabelChanged = 'titleLabelChanged',
expandableChanged = 'expandableChanged',
}
export default class TreeNode { export default class TreeNode {
readonly pluginContext: IPublicModelPluginContext; readonly pluginContext: IPublicModelPluginContext;
onFilterResultChanged: () => void; event = new EventEmitter();
onExpandedChanged: (expanded: boolean) => void;
onHiddenChanged: (hidden: boolean) => void; onFilterResultChanged(fn: () => void): IPublicTypeDisposable {
onLockedChanged: (locked: boolean) => void; this.event.on(EVENT_NAMES.filterResultChanged, fn);
onTitleLabelChanged: (treeNode: TreeNode) => void; return () => {
onExpandableChanged: (expandable: boolean) => void; 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 { get id(): string {
return this.node.id; return this.node.id;
@ -46,7 +95,7 @@ export default class TreeNode {
* onExpandableChanged * onExpandableChanged
*/ */
notifyExpandableChanged(): void { 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) { setExpanded(value: boolean) {
this._expanded = value; this._expanded = value;
this.onExpandedChanged && this.onExpandedChanged(value); this.event.emit(EVENT_NAMES.expandedChanged, value);
} }
get detecting() { get detecting() {
@ -120,7 +169,7 @@ export default class TreeNode {
return; return;
} }
this.node.visible = !flag; this.node.visible = !flag;
this.onHiddenChanged && this.onHiddenChanged(flag); this.event.emit(EVENT_NAMES.hiddenChanged, flag);
} }
get locked(): boolean { get locked(): boolean {
@ -129,7 +178,7 @@ export default class TreeNode {
setLocked(flag: boolean) { setLocked(flag: boolean) {
this.node.lock(flag); this.node.lock(flag);
this.onLockedChanged && this.onLockedChanged(flag); this.event.emit(EVENT_NAMES.lockedChanged, flag);
} }
get selected(): boolean { get selected(): boolean {
@ -174,11 +223,11 @@ export default class TreeNode {
} else { } else {
this.node.getExtraProp('title', true)?.setValue(label); this.node.getExtraProp('title', true)?.setValue(label);
} }
this.onTitleLabelChanged && this.onTitleLabelChanged(this); this.event.emit(EVENT_NAMES.titleLabelChanged, this);
} }
get icon() { get icon() {
return this.node.componentMeta.icon; return this.node.componentMeta?.icon;
} }
get parent(): TreeNode | null { get parent(): TreeNode | null {
@ -282,8 +331,6 @@ export default class TreeNode {
setFilterReult(val: FilterResult) { setFilterReult(val: FilterResult) {
this._filterResult = val; this._filterResult = val;
if (this.onFilterResultChanged) { this.event.emit(EVENT_NAMES.filterResultChanged)
this.onFilterResultChanged();
}
} }
} }

View File

@ -2,7 +2,7 @@ import { Component } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import TreeNode from '../controllers/tree-node'; import TreeNode from '../controllers/tree-node';
import TreeNodeView from './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<{ export default class TreeBranches extends Component<{
treeNode: TreeNode; treeNode: TreeNode;
@ -25,10 +25,10 @@ export default class TreeBranches extends Component<{
componentDidMount() { componentDidMount() {
const { treeNode } = this.props; const { treeNode } = this.props;
treeNode.onFilterResultChanged = () => { treeNode.onFilterResultChanged(() => {
const { filterWorking: newFilterWorking, matchChild: newMatchChild } = treeNode.filterReult; const { filterWorking: newFilterWorking, matchChild: newMatchChild } = treeNode.filterReult;
this.setState({ filterWorking: newFilterWorking, matchChild: newMatchChild }); this.setState({ filterWorking: newFilterWorking, matchChild: newMatchChild });
}; });
} }
componentWillUnmount(): void { componentWillUnmount(): void {
@ -73,7 +73,7 @@ class TreeNodeChildren extends Component<{
keywords: null, keywords: null,
dropDetail: null, dropDetail: null,
}; };
offLocationChanged: () => void; offLocationChanged: IPublicTypeDisposable | undefined;
componentDidMount() { componentDidMount() {
const { treeNode, pluginContext } = this.props; const { treeNode, pluginContext } = this.props;
const { project } = pluginContext; const { project } = pluginContext;
@ -85,7 +85,7 @@ class TreeNodeChildren extends Component<{
keywords, keywords,
dropDetail, dropDetail,
}); });
treeNode.onFilterResultChanged = () => { treeNode.onFilterResultChanged(() => {
const { const {
filterWorking: newFilterWorking, filterWorking: newFilterWorking,
matchSelf: newMatchChild, matchSelf: newMatchChild,
@ -96,7 +96,7 @@ class TreeNodeChildren extends Component<{
matchSelf: newMatchChild, matchSelf: newMatchChild,
keywords: newKeywords, keywords: newKeywords,
}); });
}; });
this.offLocationChanged = project.currentDocument?.onDropLocationChanged( this.offLocationChanged = project.currentDocument?.onDropLocationChanged(
() => { () => {
this.setState({ dropDetail: treeNode.dropDetail }); this.setState({ dropDetail: treeNode.dropDetail });
@ -118,7 +118,7 @@ class TreeNodeChildren extends Component<{
const endGroup = () => { const endGroup = () => {
if (groupContents.length > 0) { if (groupContents.length > 0) {
children.push( children.push(
<div key={currentGrp.id} className="condition-group-container" data-id={currentGrp.firstNode.id}> <div key={currentGrp.id} className="condition-group-container" data-id={currentGrp.firstNode?.id}>
<div className="condition-group-title"> <div className="condition-group-title">
<Title <Title
title={currentGrp.title} title={currentGrp.title}

View File

@ -4,7 +4,7 @@ import TreeNode from '../controllers/tree-node';
import TreeTitle from './tree-title'; import TreeTitle from './tree-title';
import TreeBranches from './tree-branches'; import TreeBranches from './tree-branches';
import { IconEyeClose } from '../icons/eye-close'; import { IconEyeClose } from '../icons/eye-close';
import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicModelDocumentModel } from '@alilc/lowcode-types'; import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicModelDocumentModel, IPublicTypeDisposable } from '@alilc/lowcode-types';
class ModalTreeNodeView extends Component<{ class ModalTreeNodeView extends Component<{
treeNode: TreeNode; treeNode: TreeNode;
@ -78,7 +78,7 @@ export default class TreeNodeView extends Component<{
expandable: false, expandable: false,
}; };
eventOffCallbacks: Array<() => void> = []; eventOffCallbacks: Array<IPublicTypeDisposable | undefined> = [];
constructor(props: any) { constructor(props: any) {
super(props); super(props);
@ -104,18 +104,18 @@ export default class TreeNodeView extends Component<{
const doc = project.currentDocument; const doc = project.currentDocument;
treeNode.onExpandedChanged = ((expanded: boolean) => { treeNode.onExpandedChanged(((expanded: boolean) => {
this.setState({ expanded }); this.setState({ expanded });
}); }));
treeNode.onHiddenChanged = (hidden: boolean) => { treeNode.onHiddenChanged((hidden: boolean) => {
this.setState({ hidden }); this.setState({ hidden });
}; });
treeNode.onLockedChanged = (locked: boolean) => { treeNode.onLockedChanged((locked: boolean) => {
this.setState({ locked }); this.setState({ locked });
}; });
treeNode.onExpandableChanged = (expandable: boolean) => { treeNode.onExpandableChanged((expandable: boolean) => {
this.setState({ expandable }); this.setState({ expandable });
}; });
this.eventOffCallbacks.push( this.eventOffCallbacks.push(
doc?.onDropLocationChanged((document: IPublicModelDocumentModel) => { doc?.onDropLocationChanged((document: IPublicModelDocumentModel) => {
@ -135,8 +135,8 @@ export default class TreeNodeView extends Component<{
this.eventOffCallbacks.push(offDetectingChange!); this.eventOffCallbacks.push(offDetectingChange!);
} }
componentWillUnmount(): void { componentWillUnmount(): void {
this.eventOffCallbacks?.forEach((offFun: () => void) => { this.eventOffCallbacks?.forEach((offFun: IPublicTypeDisposable | undefined) => {
offFun(); offFun && offFun();
}); });
} }

View File

@ -6,7 +6,6 @@ import { IPublicModelPluginContext, IPublicApiEvent } from '@alilc/lowcode-types
import TreeNode from '../controllers/tree-node'; import TreeNode from '../controllers/tree-node';
import { IconLock, IconUnlock, IconArrowRight, IconEyeClose, IconEye, IconCond, IconLoop, IconRadioActive, IconRadio, IconSetting } from '../icons'; import { IconLock, IconUnlock, IconArrowRight, IconEyeClose, IconEye, IconCond, IconLoop, IconRadioActive, IconRadio, IconSetting } from '../icons';
function emitOutlineEvent(event: IPublicApiEvent, type: string, treeNode: TreeNode, rest?: Record<string, unknown>) { function emitOutlineEvent(event: IPublicApiEvent, type: string, treeNode: TreeNode, rest?: Record<string, unknown>) {
const node = treeNode?.node; const node = treeNode?.node;
const npm = node?.componentMeta?.npm; const npm = node?.componentMeta?.npm;
@ -35,6 +34,8 @@ export default class TreeTitle extends Component<{
title: '', title: '',
}; };
private lastInput?: HTMLInputElement;
private enableEdit = (e) => { private enableEdit = (e) => {
e.preventDefault(); e.preventDefault();
this.setState({ this.setState({
@ -66,8 +67,6 @@ export default class TreeTitle extends Component<{
} }
}; };
private lastInput?: HTMLInputElement;
private setCaret = (input: HTMLInputElement | null) => { private setCaret = (input: HTMLInputElement | null) => {
if (!input || this.lastInput === input) { if (!input || this.lastInput === input) {
return; return;
@ -84,11 +83,11 @@ export default class TreeTitle extends Component<{
editing: false, editing: false,
title: treeNode.titleLabel, title: treeNode.titleLabel,
}); });
treeNode.onTitleLabelChanged = () => { treeNode.onTitleLabelChanged(() => {
this.setState({ this.setState({
title: treeNode.titleLabel, title: treeNode.titleLabel,
}); });
}; });
} }
render() { render() {
@ -96,6 +95,8 @@ export default class TreeTitle extends Component<{
const { editing } = this.state; const { editing } = this.state;
const isCNode = !treeNode.isRoot(); const isCNode = !treeNode.isRoot();
const { node } = treeNode; const { node } = treeNode;
const { componentMeta } = node;
const availableActions = componentMeta ? componentMeta.availableActions.map((availableAction) => availableAction.name) : [];
const isNodeParent = node.isParentalNode; const isNodeParent = node.isParentalNode;
const isContainer = node.isContainerNode; const isContainer = node.isContainerNode;
let style: any; let style: any;
@ -112,8 +113,11 @@ export default class TreeTitle extends Component<{
const { intlNode, common, config } = pluginContext; const { intlNode, common, config } = pluginContext;
const Tip = common.editorCabin.Tip; const Tip = common.editorCabin.Tip;
const Title = common.editorCabin.Title; const Title = common.editorCabin.Title;
const shouldShowHideBtn = isCNode && isNodeParent && !isModal; const couldHide = availableActions.includes('hide');
const shouldShowLockBtn = config.get('enableCanvasLock', false) && isContainer && isCNode && isNodeParent; 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; const shouldEditBtn = isCNode && isNodeParent;
return ( return (
<div <div
@ -221,7 +225,6 @@ class RenameBtn extends Component<{
} }
} }
class LockBtn extends Component<{ class LockBtn extends Component<{
treeNode: TreeNode; treeNode: TreeNode;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
@ -273,7 +276,6 @@ class HideBtn extends Component<{
} }
} }
class ExpandBtn extends Component<{ class ExpandBtn extends Component<{
treeNode: TreeNode; treeNode: TreeNode;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
@ -301,4 +303,4 @@ class ExpandBtn extends Component<{
</div> </div>
); );
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-rax-renderer", "name": "@alilc/lowcode-rax-renderer",
"version": "1.1.2", "version": "1.1.3",
"description": "Rax renderer for Ali lowCode engine", "description": "Rax renderer for Ali lowCode engine",
"main": "lib/index.js", "main": "lib/index.js",
"module": "es/index.js", "module": "es/index.js",
@ -30,8 +30,8 @@
"build": "build-scripts build" "build": "build-scripts build"
}, },
"dependencies": { "dependencies": {
"@alilc/lowcode-renderer-core": "1.1.2", "@alilc/lowcode-renderer-core": "1.1.3",
"@alilc/lowcode-utils": "1.1.2", "@alilc/lowcode-utils": "1.1.3",
"rax-find-dom-node": "^1.0.1" "rax-find-dom-node": "^1.0.1"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-rax-simulator-renderer", "name": "@alilc/lowcode-rax-simulator-renderer",
"version": "1.1.2", "version": "1.1.3",
"description": "rax simulator renderer for alibaba lowcode designer", "description": "rax simulator renderer for alibaba lowcode designer",
"main": "lib/index.js", "main": "lib/index.js",
"module": "es/index.js", "module": "es/index.js",
@ -13,10 +13,10 @@
"build:umd": "build-scripts build --config build.umd.json" "build:umd": "build-scripts build --config build.umd.json"
}, },
"dependencies": { "dependencies": {
"@alilc/lowcode-designer": "1.1.2", "@alilc/lowcode-designer": "1.1.3",
"@alilc/lowcode-rax-renderer": "1.1.2", "@alilc/lowcode-rax-renderer": "1.1.3",
"@alilc/lowcode-types": "1.1.2", "@alilc/lowcode-types": "1.1.3",
"@alilc/lowcode-utils": "1.1.2", "@alilc/lowcode-utils": "1.1.3",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"driver-universal": "^3.1.3", "driver-universal": "^3.1.3",
"history": "^5.0.0", "history": "^5.0.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-react-renderer", "name": "@alilc/lowcode-react-renderer",
"version": "1.1.2", "version": "1.1.3",
"description": "react renderer for ali lowcode engine", "description": "react renderer for ali lowcode engine",
"main": "lib/index.js", "main": "lib/index.js",
"module": "es/index.js", "module": "es/index.js",
@ -22,7 +22,7 @@
], ],
"dependencies": { "dependencies": {
"@alifd/next": "^1.21.16", "@alifd/next": "^1.21.16",
"@alilc/lowcode-renderer-core": "1.1.2" "@alilc/lowcode-renderer-core": "1.1.3"
}, },
"devDependencies": { "devDependencies": {
"@alib/build-scripts": "^0.1.18", "@alib/build-scripts": "^0.1.18",

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-react-simulator-renderer", "name": "@alilc/lowcode-react-simulator-renderer",
"version": "1.1.2", "version": "1.1.3",
"description": "react simulator renderer for alibaba lowcode designer", "description": "react simulator renderer for alibaba lowcode designer",
"main": "lib/index.js", "main": "lib/index.js",
"module": "es/index.js", "module": "es/index.js",
@ -17,10 +17,10 @@
"test:cov": "build-scripts test --config build.test.json --jest-coverage" "test:cov": "build-scripts test --config build.test.json --jest-coverage"
}, },
"dependencies": { "dependencies": {
"@alilc/lowcode-designer": "1.1.2", "@alilc/lowcode-designer": "1.1.3",
"@alilc/lowcode-react-renderer": "1.1.2", "@alilc/lowcode-react-renderer": "1.1.3",
"@alilc/lowcode-types": "1.1.2", "@alilc/lowcode-types": "1.1.3",
"@alilc/lowcode-utils": "1.1.2", "@alilc/lowcode-utils": "1.1.3",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"mobx": "^6.3.0", "mobx": "^6.3.0",
"mobx-react": "^7.2.0", "mobx-react": "^7.2.0",

View File

@ -170,7 +170,9 @@ class Renderer extends Component<{
this.startTime = Date.now(); this.startTime = Date.now();
this.schemaChangedSymbol = false; this.schemaChangedSymbol = false;
if (!container.autoRender || isRendererDetached()) return null; if (!container.autoRender || isRendererDetached()) {
return null;
}
const { intl } = createIntl(locale); const { intl } = createIntl(locale);

View File

@ -39,10 +39,6 @@ export class DocumentInstance {
private disposeFunctions: Array<() => void> = []; private disposeFunctions: Array<() => void> = [];
constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) {
makeObservable(this);
}
@obx.ref private _components: any = {}; @obx.ref private _components: any = {};
@computed get components(): object { @computed get components(): object {
@ -98,6 +94,10 @@ export class DocumentInstance {
return this.document.id; return this.document.id;
} }
constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) {
makeObservable(this);
}
private unmountInstance(id: string, instance: ReactInstance) { private unmountInstance(id: string, instance: ReactInstance) {
const instances = this.instancesMap.get(id); const instances = this.instancesMap.get(id);
if (instances) { if (instances) {
@ -170,8 +170,7 @@ export class DocumentInstance {
host.setInstance(this.document.id, id, instances); host.setInstance(this.document.id, id, instances);
} }
mountContext(docId: string, id: string, ctx: object) { mountContext() {
// this.ctxMap.set(id, ctx);
} }
getNode(id: string): Node | null { getNode(id: string): Node | null {
@ -195,6 +194,60 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
return this._documentInstances; 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() { constructor() {
makeObservable(this); makeObservable(this);
this.autoRender = host.autoRender; 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() { private buildComponents() {
this._components = buildComponents( this._components = buildComponents(
this._libraryMap, this._libraryMap,
@ -330,44 +370,6 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
...this._components, ...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, appHelper: renderer.context,
rendererName: 'LowCodeRenderer', rendererName: 'LowCodeRenderer',
thisRequiredInJSE: host.thisRequiredInJSE, thisRequiredInJSE: host.thisRequiredInJSE,
faultComponent: host.faultComponent,
customCreateElement: (Comp: any, props: any, children: any) => { customCreateElement: (Comp: any, props: any, children: any) => {
const componentMeta = host.currentDocument?.getComponentMeta(Comp.displayName); const componentMeta = host.currentDocument?.getComponentMeta(Comp.displayName);
if (componentMeta?.isModal) { if (componentMeta?.isModal) {
@ -479,8 +482,6 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
return LowCodeComp; return LowCodeComp;
} }
private _running = false;
run() { run() {
if (this._running) { if (this._running) {
return; return;

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-renderer-core", "name": "@alilc/lowcode-renderer-core",
"version": "1.1.2", "version": "1.1.3",
"description": "renderer core", "description": "renderer core",
"license": "MIT", "license": "MIT",
"main": "lib/index.js", "main": "lib/index.js",
@ -16,8 +16,8 @@
}, },
"dependencies": { "dependencies": {
"@alilc/lowcode-datasource-engine": "^1.0.0", "@alilc/lowcode-datasource-engine": "^1.0.0",
"@alilc/lowcode-types": "1.1.2", "@alilc/lowcode-types": "1.1.3",
"@alilc/lowcode-utils": "1.1.2", "@alilc/lowcode-utils": "1.1.3",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"debug": "^4.1.1", "debug": "^4.1.1",
"fetch-jsonp": "^1.1.3", "fetch-jsonp": "^1.1.3",
@ -32,7 +32,7 @@
"devDependencies": { "devDependencies": {
"@alib/build-scripts": "^0.1.18", "@alib/build-scripts": "^0.1.18",
"@alifd/next": "^1.26.0", "@alifd/next": "^1.26.0",
"@alilc/lowcode-designer": "1.1.2", "@alilc/lowcode-designer": "1.1.3",
"@babel/plugin-transform-typescript": "^7.16.8", "@babel/plugin-transform-typescript": "^7.16.8",
"@testing-library/react": "^11.2.2", "@testing-library/react": "^11.2.2",
"@types/classnames": "^2.2.11", "@types/classnames": "^2.2.11",

View File

@ -45,7 +45,7 @@ export default function addonRendererFactory(): IBaseRenderComponent {
this.__initDataSource(props); this.__initDataSource(props);
this.open = this.open || (() => { }); this.open = this.open || (() => { });
this.close = this.close || (() => { }); this.close = this.close || (() => { });
this.__excuteLifeCycleMethod('constructor', [...arguments]); this.__executeLifeCycleMethod('constructor', [...arguments]);
} }
async componentWillUnmount() { async componentWillUnmount() {

View File

@ -40,7 +40,7 @@ import isUseLoop from '../utils/is-use-loop';
* execute method in schema.lifeCycles with context * execute method in schema.lifeCycles with context
* @PRIVATE * @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) { if (!context || !isSchema(schema) || !method) {
return; return;
} }
@ -183,32 +183,32 @@ export default function baseRendererFactory(): IBaseRenderComponent {
__afterInit(_props: IBaseRendererProps) { } __afterInit(_props: IBaseRendererProps) { }
static getDerivedStateFromProps(props: IBaseRendererProps, state: any) { 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[]) { async getSnapshotBeforeUpdate(...args: any[]) {
this.__excuteLifeCycleMethod('getSnapshotBeforeUpdate', args); this.__executeLifeCycleMethod('getSnapshotBeforeUpdate', args);
this.__debug(`getSnapshotBeforeUpdate - ${this.props?.__schema?.fileName}`); this.__debug(`getSnapshotBeforeUpdate - ${this.props?.__schema?.fileName}`);
} }
async componentDidMount(...args: any[]) { async componentDidMount(...args: any[]) {
this.reloadDataSource(); this.reloadDataSource();
this.__excuteLifeCycleMethod('componentDidMount', args); this.__executeLifeCycleMethod('componentDidMount', args);
this.__debug(`componentDidMount - ${this.props?.__schema?.fileName}`); this.__debug(`componentDidMount - ${this.props?.__schema?.fileName}`);
} }
async componentDidUpdate(...args: any[]) { async componentDidUpdate(...args: any[]) {
this.__excuteLifeCycleMethod('componentDidUpdate', args); this.__executeLifeCycleMethod('componentDidUpdate', args);
this.__debug(`componentDidUpdate - ${this.props.__schema.fileName}`); this.__debug(`componentDidUpdate - ${this.props.__schema.fileName}`);
} }
async componentWillUnmount(...args: any[]) { async componentWillUnmount(...args: any[]) {
this.__excuteLifeCycleMethod('componentWillUnmount', args); this.__executeLifeCycleMethod('componentWillUnmount', args);
this.__debug(`componentWillUnmount - ${this.props?.__schema?.fileName}`); this.__debug(`componentWillUnmount - ${this.props?.__schema?.fileName}`);
} }
async componentDidCatch(...args: any[]) { async componentDidCatch(...args: any[]) {
this.__excuteLifeCycleMethod('componentDidCatch', args); this.__executeLifeCycleMethod('componentDidCatch', args);
console.warn(args); console.warn(args);
} }
@ -248,8 +248,8 @@ export default function baseRendererFactory(): IBaseRenderComponent {
* execute method in schema.lifeCycles * execute method in schema.lifeCycles
* @PRIVATE * @PRIVATE
*/ */
__excuteLifeCycleMethod = (method: string, args?: any) => { __executeLifeCycleMethod = (method: string, args?: any) => {
excuteLifeCycleMethod(this, this.props.__schema, method, args, this.props.thisRequiredInJSE); executeLifeCycleMethod(this, this.props.__schema, method, args, this.props.thisRequiredInJSE);
}; };
/** /**
@ -406,7 +406,7 @@ export default function baseRendererFactory(): IBaseRenderComponent {
__render = () => { __render = () => {
const schema = this.props.__schema; const schema = this.props.__schema;
this.__excuteLifeCycleMethod('render'); this.__executeLifeCycleMethod('render');
this.__writeCss(this.props); this.__writeCss(this.props);
const { engine } = this.context; const { engine } = this.context;
@ -774,6 +774,11 @@ export default function baseRendererFactory(): IBaseRenderComponent {
{ {
...schema, ...schema,
loop: undefined, loop: undefined,
props: {
...schema.props,
// 循环下 key 不能为常量,这样会造成 key 值重复,渲染异常
key: isJSExpression(schema.props?.key) ? schema.props?.key : null,
},
}, },
loopSelf, loopSelf,
parentInfo, parentInfo,

View File

@ -13,7 +13,7 @@ export default function blockRendererFactory(): IBaseRenderComponent {
const schema = props.__schema || {}; const schema = props.__schema || {};
this.state = this.__parseData(schema.state || {}); this.state = this.__parseData(schema.state || {});
this.__initDataSource(props); this.__initDataSource(props);
this.__excuteLifeCycleMethod('constructor', [...arguments]); this.__executeLifeCycleMethod('constructor', [...arguments]);
} }
render() { render() {

View File

@ -15,7 +15,7 @@ export default function componentRendererFactory(): IBaseRenderComponent {
const schema = props.__schema || {}; const schema = props.__schema || {};
this.state = this.__parseData(schema.state || {}); this.state = this.__parseData(schema.state || {});
this.__initDataSource(props); this.__initDataSource(props);
this.__excuteLifeCycleMethod('constructor', arguments as any); this.__executeLifeCycleMethod('constructor', arguments as any);
} }
render() { render() {

View File

@ -15,7 +15,7 @@ export default function pageRendererFactory(): IBaseRenderComponent {
const schema = props.__schema || {}; const schema = props.__schema || {};
this.state = this.__parseData(schema.state || {}); this.state = this.__parseData(schema.state || {});
this.__initDataSource(props); this.__initDataSource(props);
this.__excuteLifeCycleMethod('constructor', [props, ...rest]); this.__executeLifeCycleMethod('constructor', [props, ...rest]);
} }
async componentDidUpdate(prevProps: IBaseRendererProps, _prevState: {}, snapshot: unknown) { async componentDidUpdate(prevProps: IBaseRendererProps, _prevState: {}, snapshot: unknown) {
@ -44,7 +44,6 @@ export default function pageRendererFactory(): IBaseRenderComponent {
}); });
this.__render(); this.__render();
const { Page } = __components; const { Page } = __components;
if (Page) { if (Page) {
return this.__renderComp(Page, { pageContext: this }); return this.__renderComp(Page, { pageContext: this });

View File

@ -19,10 +19,9 @@ export default function rendererFactory(): IRenderComponent {
const debug = Debug('renderer:entry'); const debug = Debug('renderer:entry');
class FaultComponent extends PureComponent<IPublicTypeNodeSchema> { class FaultComponent extends PureComponent<IPublicTypeNodeSchema | any> {
render() { render() {
// FIXME: errorlog logger.error(`%c组件渲染异常, 异常原因: ${this.props.error?.message || this.props.error || '未知'}`, 'color: #ff0000;');
console.error('render error', this.props);
return createElement(Div, { return createElement(Div, {
style: { style: {
width: '100%', width: '100%',
@ -86,8 +85,9 @@ export default function rendererFactory(): IRenderComponent {
debug(`entry.componentWillUnmount - ${this.props?.schema?.componentName}`); debug(`entry.componentWillUnmount - ${this.props?.schema?.componentName}`);
} }
async componentDidCatch(e: any) { componentDidCatch(error: Error) {
console.warn(e); this.state.engineRenderError = true;
this.state.error = error;
} }
shouldComponentUpdate(nextProps: IRendererProps) { shouldComponentUpdate(nextProps: IRendererProps) {
@ -182,6 +182,13 @@ export default function rendererFactory(): IRenderComponent {
} }
} }
if (this.state && this.state.engineRenderError) {
return createElement(this.getFaultComponent(), {
...this.props,
error: this.state.error,
});
}
if (Comp) { if (Comp) {
return createElement(AppContext.Provider, { value: { return createElement(AppContext.Provider, { value: {
appHelper, appHelper,

View File

@ -281,7 +281,7 @@ export type IBaseRendererInstance = IGeneralComponent<
__beforeInit(props: IBaseRendererProps): void; __beforeInit(props: IBaseRendererProps): void;
__init(props: IBaseRendererProps): void; __init(props: IBaseRendererProps): void;
__afterInit(props: IBaseRendererProps): void; __afterInit(props: IBaseRendererProps): void;
__excuteLifeCycleMethod(method: string, args?: any[]): void; __executeLifeCycleMethod(method: string, args?: any[]): void;
__bindCustomMethods(props: IBaseRendererProps): void; __bindCustomMethods(props: IBaseRendererProps): void;
__generateCtx(ctx: Record<string, any>): void; __generateCtx(ctx: Record<string, any>): void;
__parseData(data: any, ctx?: any): any; __parseData(data: any, ctx?: any): any;
@ -323,10 +323,10 @@ export interface IRenderComponent {
new(props: IRendererProps, context: any): IGeneralComponent<IRendererProps, IRendererState> & { new(props: IRendererProps, context: any): IGeneralComponent<IRendererProps, IRendererState> & {
[x: string]: any; [x: string]: any;
__getRef: (ref: any) => void; __getRef: (ref: any) => void;
componentDidMount(): Promise<void>; componentDidMount(): Promise<void> | void;
componentDidUpdate(): Promise<void>; componentDidUpdate(): Promise<void> | void;
componentWillUnmount(): Promise<void>; componentWillUnmount(): Promise<void> | void;
componentDidCatch(e: any): Promise<void>; componentDidCatch(e: any): Promise<void> | void;
shouldComponentUpdate(nextProps: IRendererProps): boolean; shouldComponentUpdate(nextProps: IRendererProps): boolean;
isValidComponent(SetComponent: any): any; isValidComponent(SetComponent: any): any;
patchDidCatch(SetComponent: any): void; patchDidCatch(SetComponent: any): void;

View File

@ -121,7 +121,7 @@ describe('Base Render methods', () => {
// it('should excute lifecycle.componentDidCatch when defined', () => { // it('should excute lifecycle.componentDidCatch when defined', () => {
// }); // });
// it('__excuteLifeCycleMethod should work', () => { // it('__executeLifeCycleMethod should work', () => {
// }); // });
// it('reloadDataSource should work', () => { // it('reloadDataSource should work', () => {

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-shell", "name": "@alilc/lowcode-shell",
"version": "1.1.2", "version": "1.1.3",
"description": "Shell Layer for AliLowCodeEngine", "description": "Shell Layer for AliLowCodeEngine",
"main": "lib/index.js", "main": "lib/index.js",
"module": "es/index.js", "module": "es/index.js",
@ -15,12 +15,12 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@alilc/lowcode-designer": "1.1.2", "@alilc/lowcode-designer": "1.1.3",
"@alilc/lowcode-editor-core": "1.1.2", "@alilc/lowcode-editor-core": "1.1.3",
"@alilc/lowcode-editor-skeleton": "1.1.2", "@alilc/lowcode-editor-skeleton": "1.1.3",
"@alilc/lowcode-types": "1.1.2", "@alilc/lowcode-types": "1.1.3",
"@alilc/lowcode-utils": "1.1.2", "@alilc/lowcode-utils": "1.1.3",
"@alilc/lowcode-workspace": "1.1.2", "@alilc/lowcode-workspace": "1.1.3",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"enzyme": "^3.11.0", "enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.5", "enzyme-adapter-react-16": "^1.15.5",

View File

@ -10,6 +10,7 @@ import {
SettingPropEntry, SettingPropEntry,
SettingTopEntry, SettingTopEntry,
Clipboard, Clipboard,
Config,
} from './model'; } from './model';
import { import {
Project, Project,
@ -61,4 +62,5 @@ export {
Workspace, Workspace,
Clipboard, Clipboard,
SimulatorHost, SimulatorHost,
}; Config,
};

View File

@ -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;
}
}

View File

@ -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<any> {
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();
}
}

View File

@ -21,6 +21,7 @@ import {
IPublicApiCanvas, IPublicApiCanvas,
IPublicTypeDisposable, IPublicTypeDisposable,
IPublicModelEditor, IPublicModelEditor,
IPublicTypeNodeSchema,
} from '@alilc/lowcode-types'; } from '@alilc/lowcode-types';
import { isDragNodeObject } from '@alilc/lowcode-utils'; import { isDragNodeObject } from '@alilc/lowcode-utils';
import { Node as ShellNode } from './node'; import { Node as ShellNode } from './node';
@ -195,7 +196,7 @@ export class DocumentModel implements IPublicModelDocumentModel {
* @param data * @param data
* @returns * @returns
*/ */
createNode(data: any): IPublicModelNode | null { createNode(data: IPublicTypeNodeSchema): IPublicModelNode | null {
return ShellNode.create(this[documentSymbol].createNode(data)); return ShellNode.create(this[documentSymbol].createNode(data));
} }
@ -289,7 +290,7 @@ export class DocumentModel implements IPublicModelDocumentModel {
* @param fn * @param fn
*/ */
onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): IPublicTypeDisposable { 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); fn(ShellNode.create(node)!, visible);
}); });
} }

View File

@ -18,4 +18,5 @@ export * from './resource';
export * from './active-tracker'; export * from './active-tracker';
export * from './plugin-instance'; export * from './plugin-instance';
export * from './window'; export * from './window';
export * from './clipboard'; export * from './clipboard';
export * from './config';

View File

@ -129,6 +129,15 @@ export class NodeChildren implements IPublicModelNodeChildren {
}); });
} }
/**
* reverse
*/
reverse(): IPublicModelNode[] {
return this[nodeChildrenSymbol].reverse().map(d => {
return ShellNode.create(d)!;
});
}
/** /**
* map * map
* @param fn * @param fn

View File

@ -27,6 +27,7 @@ import { ComponentMeta as ShellComponentMeta } from './component-meta';
import { SettingTopEntry as ShellSettingTopEntry } from './setting-top-entry'; import { SettingTopEntry as ShellSettingTopEntry } from './setting-top-entry';
import { documentSymbol, nodeSymbol } from '../symbols'; import { documentSymbol, nodeSymbol } from '../symbols';
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import { ConditionGroup } from './condition-group';
const shellNodeSymbol = Symbol('shellNodeSymbol'); 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); return ShellProp.create(this[nodeSymbol].slotFor);
} }
@ -349,7 +350,6 @@ export class Node implements IPublicModelNode {
/** /**
* dom * dom
* @deprecated
*/ */
getDOMNode() { getDOMNode() {
return (this[nodeSymbol] as any).getDOMNode(); return (this[nodeSymbol] as any).getDOMNode();
@ -641,7 +641,7 @@ export class Node implements IPublicModelNode {
* @since v1.1.0 * @since v1.1.0
*/ */
get conditionGroup(): IPublicModelExclusiveGroup | null { get conditionGroup(): IPublicModelExclusiveGroup | null {
return this[nodeSymbol].conditionGroup; return ConditionGroup.create(this[nodeSymbol].conditionGroup);
} }
/** /**

View File

@ -37,7 +37,7 @@ export class Resource implements IPublicModelResource {
return this[resourceSymbol].children.map((child) => new Resource(child)); return this[resourceSymbol].children.map((child) => new Resource(child));
} }
get viewType() { get viewName() {
return this[resourceSymbol].viewType; return this[resourceSymbol].viewName;
} }
} }

View File

@ -1,14 +1,14 @@
import { import {
IDocumentModel as InnerDocumentModel, IDocumentModel as InnerDocumentModel,
INode as InnerNode, INode as InnerNode,
ISelection as InnerSelection, ISelection,
} from '@alilc/lowcode-designer'; } from '@alilc/lowcode-designer';
import { Node as ShellNode } from './node'; import { Node as ShellNode } from './node';
import { selectionSymbol } from '../symbols'; import { selectionSymbol } from '../symbols';
import { IPublicModelSelection, IPublicModelNode, IPublicTypeDisposable } from '@alilc/lowcode-types'; import { IPublicModelSelection, IPublicModelNode, IPublicTypeDisposable } from '@alilc/lowcode-types';
export class Selection implements IPublicModelSelection { export class Selection implements IPublicModelSelection {
private readonly [selectionSymbol]: InnerSelection; private readonly [selectionSymbol]: ISelection;
constructor(document: InnerDocumentModel) { constructor(document: InnerDocumentModel) {
this[selectionSymbol] = document.selection; this[selectionSymbol] = document.selection;

View File

@ -1,4 +1,4 @@
import { SettingField, SettingEntry } from '@alilc/lowcode-designer'; import { SettingField, ISettingEntry } from '@alilc/lowcode-designer';
import { import {
IPublicTypeCompositeValue, IPublicTypeCompositeValue,
IPublicTypeFieldConfig, IPublicTypeFieldConfig,
@ -233,7 +233,7 @@ export class SettingPropEntry implements IPublicModelSettingPropEntry {
* @returns * @returns
*/ */
getProps(): IPublicModelSettingTopEntry { getProps(): IPublicModelSettingTopEntry {
return ShellSettingTopEntry.create(this[settingPropEntrySymbol].getProps() as SettingEntry); return ShellSettingTopEntry.create(this[settingPropEntrySymbol].getProps() as ISettingEntry);
} }
/** /**

View File

@ -1,17 +1,17 @@
import { SettingEntry } from '@alilc/lowcode-designer'; import { ISettingEntry } from '@alilc/lowcode-designer';
import { settingTopEntrySymbol } from '../symbols'; import { settingTopEntrySymbol } from '../symbols';
import { Node as ShellNode } from './node'; import { Node as ShellNode } from './node';
import { SettingPropEntry as ShellSettingPropEntry } from './setting-prop-entry'; import { SettingPropEntry as ShellSettingPropEntry } from './setting-prop-entry';
import { IPublicModelSettingTopEntry, IPublicModelNode, IPublicModelSettingPropEntry } from '@alilc/lowcode-types'; import { IPublicModelSettingTopEntry, IPublicModelNode, IPublicModelSettingPropEntry } from '@alilc/lowcode-types';
export class SettingTopEntry implements IPublicModelSettingTopEntry { export class SettingTopEntry implements IPublicModelSettingTopEntry {
private readonly [settingTopEntrySymbol]: SettingEntry; private readonly [settingTopEntrySymbol]: ISettingEntry;
constructor(prop: SettingEntry) { constructor(prop: ISettingEntry) {
this[settingTopEntrySymbol] = prop; this[settingTopEntrySymbol] = prop;
} }
static create(prop: SettingEntry): IPublicModelSettingTopEntry { static create(prop: ISettingEntry): IPublicModelSettingTopEntry {
return new SettingTopEntry(prop); return new SettingTopEntry(prop);
} }

View File

@ -31,4 +31,6 @@ export const windowSymbol = Symbol('window');
export const pluginInstanceSymbol = Symbol('plugin-instance'); export const pluginInstanceSymbol = Symbol('plugin-instance');
export const resourceTypeSymbol = Symbol('resourceType'); export const resourceTypeSymbol = Symbol('resourceType');
export const resourceSymbol = Symbol('resource'); export const resourceSymbol = Symbol('resource');
export const clipboardSymbol = Symbol('clipboard'); export const clipboardSymbol = Symbol('clipboard');
export const configSymbol = Symbol('configSymbol');
export const conditionGroupSymbol = Symbol('conditionGroup');

View File

@ -1,6 +1,6 @@
{ {
"name": "@alilc/lowcode-types", "name": "@alilc/lowcode-types",
"version": "1.1.2", "version": "1.1.3",
"description": "Types for Ali lowCode engine", "description": "Types for Ali lowCode engine",
"files": [ "files": [
"es", "es",

View File

@ -2,12 +2,14 @@ import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget,
import { IPublicTypeLocationData, IPublicTypeScrollable } from '../type'; import { IPublicTypeLocationData, IPublicTypeScrollable } from '../type';
/** /**
* canvas - API
* @since v1.1.0 * @since v1.1.0
*/ */
export interface IPublicApiCanvas { export interface IPublicApiCanvas {
/** /**
* Scroller * Scroller
*
* a Scroller is a controller that gives a view (IPublicTypeScrollable) the ability scrolling * a Scroller is a controller that gives a view (IPublicTypeScrollable) the ability scrolling
* to some cordination by api scrollTo. * to some cordination by api scrollTo.
* *
@ -20,6 +22,7 @@ export interface IPublicApiCanvas {
/** /**
* ScrollTarget Scroller createScroller * ScrollTarget Scroller createScroller
*
* this works with Scroller, refer to createScroller`s description * this works with Scroller, refer to createScroller`s description
* @since v1.1.0 * @since v1.1.0
*/ */
@ -27,6 +30,7 @@ export interface IPublicApiCanvas {
/** /**
* *
*
* create a drop location for document, drop location describes a location in document * create a drop location for document, drop location describes a location in document
* @since v1.1.0 * @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 * get dragon instance, you can use this to obtain draging related abilities and lifecycle hooks
* @since v1.1.0 * @since v1.1.0
*/ */
@ -41,6 +46,7 @@ export interface IPublicApiCanvas {
/** /**
* *
*
* get activeTracker instance, which is a singleton running in engine. * 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 * it tracks document`s current focusing node/node[], and notify it`s subscribers that when
* focusing node/node[] changed. * focusing node/node[] changed.
@ -50,6 +56,7 @@ export interface IPublicApiCanvas {
/** /**
* LiveEditing * LiveEditing
*
* check if canvas is in liveEditing state * check if canvas is in liveEditing state
* @since v1.1.0 * @since v1.1.0
*/ */
@ -57,6 +64,7 @@ export interface IPublicApiCanvas {
/** /**
* *
*
* get clipboard instance * get clipboard instance
* *
* @since v1.1.0 * @since v1.1.0

View File

@ -76,8 +76,25 @@ export interface IPublicApiMaterial {
/** /**
* action * action
*
* add an action button in canvas context menu area * add an action button in canvas context menu area
* @param action * @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; addBuiltinComponentAction(action: IPublicTypeComponentAction): void;

View File

@ -13,6 +13,11 @@ export interface IPluginPreferenceMananger {
export type PluginOptionsType = string | number | boolean | object; export type PluginOptionsType = string | number | boolean | object;
export interface IPublicApiPlugins { export interface IPublicApiPlugins {
/**
* plugin api export
*/
[key: string]: any;
register( register(
pluginModel: IPublicTypePlugin, pluginModel: IPublicTypePlugin,
options?: Record<string, PluginOptionsType>, options?: Record<string, PluginOptionsType>,
@ -21,6 +26,7 @@ export interface IPublicApiPlugins {
/** /**
* *
*
* use this to get preference config for this plugin when engine.init() called * use this to get preference config for this plugin when engine.init() called
*/ */
getPluginPreference( getPluginPreference(
@ -29,24 +35,28 @@ export interface IPublicApiPlugins {
/** /**
* *
*
* get plugin instance by name * get plugin instance by name
*/ */
get(pluginName: string): IPublicModelPluginInstance | null; get(pluginName: string): IPublicModelPluginInstance | null;
/** /**
* *
*
* get all plugin instances * get all plugin instances
*/ */
getAll(): IPublicModelPluginInstance[]; getAll(): IPublicModelPluginInstance[];
/** /**
* *
*
* check if plugin with certain name exists * check if plugin with certain name exists
*/ */
has(pluginName: string): boolean; has(pluginName: string): boolean;
/** /**
* *
*
* delete plugin instance by name * delete plugin instance by name
*/ */
delete(pluginName: string): void; delete(pluginName: string): void;

View File

@ -1,7 +1,9 @@
import { IPublicModelWindow } from '../model'; import { IPublicModelWindow } from '../model';
import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types';
export interface IPublicApiWorkspace { export interface IPublicApiWorkspace<
Plugins = IPublicApiPlugins
> {
/** 是否启用 workspace 模式 */ /** 是否启用 workspace 模式 */
isActive: boolean; isActive: boolean;
@ -9,7 +11,7 @@ export interface IPublicApiWorkspace {
/** 当前设计器窗口 */ /** 当前设计器窗口 */
window: IPublicModelWindow; window: IPublicModelWindow;
plugins: IPublicApiPlugins; plugins: Plugins;
/** 当前设计器的编辑窗口 */ /** 当前设计器的编辑窗口 */
windows: IPublicModelWindow[]; windows: IPublicModelWindow[];

View File

@ -2,7 +2,9 @@ import { IPublicTypeNodeSchema, IPublicTypeNodeData, IPublicTypeIconType, IPubli
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import { IPublicModelNode } from './node'; import { IPublicModelNode } from './node';
export interface IPublicModelComponentMeta { export interface IPublicModelComponentMeta<
Node = IPublicModelNode
> {
/** /**
* *
@ -92,7 +94,7 @@ export interface IPublicModelComponentMeta {
* @param my * @param my
* @param parent * @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 * @param parent
*/ */
checkNestingDown( checkNestingDown(
my: IPublicModelNode | IPublicTypeNodeData, my: Node | IPublicTypeNodeData,
target: IPublicTypeNodeSchema | IPublicModelNode | IPublicTypeNodeSchema[], target: IPublicTypeNodeSchema | Node | IPublicTypeNodeSchema[],
): boolean; ): boolean;
/** /**

View File

@ -1,7 +1,7 @@
import { IPublicModelNode } from './'; import { IPublicModelNode } from './';
import { IPublicTypeDisposable } from '../type'; import { IPublicTypeDisposable } from '../type';
export interface IPublicModelDetecting { export interface IPublicModelDetecting<Node = IPublicModelNode> {
/** /**
* *
@ -15,7 +15,7 @@ export interface IPublicModelDetecting {
* get current hovering node * get current hovering node
* @since v1.0.16 * @since v1.0.16
*/ */
get current(): IPublicModelNode | null; get current(): Node | null;
/** /**
* hover * hover
@ -42,5 +42,5 @@ export interface IPublicModelDetecting {
* set callback which will be called when hovering object changed. * set callback which will be called when hovering object changed.
* @since v1.1.0 * @since v1.1.0
*/ */
onDetectingChange(fn: (node: IPublicModelNode | null) => void): IPublicTypeDisposable; onDetectingChange(fn: (node: Node | null) => void): IPublicTypeDisposable;
} }

View File

@ -2,15 +2,22 @@ import { IPublicTypeRootSchema, IPublicTypeDragNodeDataObject, IPublicTypeDragNo
import { IPublicEnumTransformStage } from '../enum'; import { IPublicEnumTransformStage } from '../enum';
import { IPublicApiProject } from '../api'; import { IPublicApiProject } from '../api';
import { IPublicModelDropLocation, IPublicModelDetecting, IPublicModelNode, IPublicModelSelection, IPublicModelHistory, IPublicModelModalNodesManager } from './'; 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 * instance of selection
*/ */
selection: IPublicModelSelection; selection: Selection;
/** /**
* hover * hover
@ -22,7 +29,7 @@ export interface IPublicModelDocumentModel {
* *
* instance of history * instance of history
*/ */
history: IPublicModelHistory; history: History;
/** /**
* id * id
@ -36,30 +43,30 @@ export interface IPublicModelDocumentModel {
* get project which this documentModel belongs to * get project which this documentModel belongs to
* @returns * @returns
*/ */
get project(): IPublicApiProject; get project(): Project;
/** /**
* *
* root node of this documentModel * root node of this documentModel
* @returns * @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 * @returns
*/ */
get nodesMap(): Map<string, IPublicModelNode>; get nodesMap(): Map<string, Node>;
/** /**
* *
* get instance of modalNodesManager * get instance of modalNodesManager
*/ */
get modalNodesManager(): IPublicModelModalNodesManager | null; get modalNodesManager(): ModalNodesManager | null;
/** /**
* nodeId Node * nodeId Node
@ -67,7 +74,7 @@ export interface IPublicModelDocumentModel {
* @param nodeId * @param nodeId
* @returns * @returns
*/ */
getNodeById(nodeId: string): IPublicModelNode | null; getNodeById(nodeId: string): Node | null;
/** /**
* schema * schema
@ -89,11 +96,11 @@ export interface IPublicModelDocumentModel {
* insert a node * insert a node
*/ */
insertNode( insertNode(
parent: IPublicModelNode, parent: Node,
thing: IPublicModelNode, thing: Node | IPublicTypeNodeData,
at?: number | null | undefined, at?: number | null | undefined,
copy?: boolean | undefined copy?: boolean | undefined
): IPublicModelNode | null; ): Node | null;
/** /**
* *
@ -101,14 +108,14 @@ export interface IPublicModelDocumentModel {
* @param data * @param data
* @returns * @returns
*/ */
createNode(data: any): IPublicModelNode | null; createNode(data: IPublicTypeNodeSchema): Node | null;
/** /**
* /id * /id
* remove a node by node instance or nodeId * remove a node by node instance or nodeId
* @param idOrNode * @param idOrNode
*/ */
removeNode(idOrNode: string | IPublicModelNode): void; removeNode(idOrNode: string | Node): void;
/** /**
* componentsMap of documentModel * componentsMap of documentModel
@ -126,7 +133,7 @@ export interface IPublicModelDocumentModel {
* @since v1.0.16 * @since v1.0.16
*/ */
checkNesting( checkNesting(
dropTarget: IPublicModelNode, dropTarget: Node,
dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject
): boolean; ): boolean;
@ -134,26 +141,26 @@ export interface IPublicModelDocumentModel {
* document * document
* set callback for event on node is created for a 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 * document document
* set callback for event on node is mounted to canvas * 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 * document
* set callback for event on node is removed * set callback for event on node is removed
*/ */
onRemoveNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; onRemoveNode(fn: (node: Node) => void): IPublicTypeDisposable;
/** /**
* document hover * document hover
* *
* set callback for event on detecting changed * set callback for event on detecting changed
*/ */
onChangeDetecting(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; onChangeDetecting(fn: (node: Node) => void): IPublicTypeDisposable;
/** /**
* document * document
@ -166,19 +173,19 @@ export interface IPublicModelDocumentModel {
* set callback for event on visibility changed for certain node * set callback for event on visibility changed for certain node
* @param fn * @param fn
*/ */
onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): IPublicTypeDisposable; onChangeNodeVisible(fn: (node: Node, visible: boolean) => void): IPublicTypeDisposable;
/** /**
* document children * document children
* @param fn * @param fn
*/ */
onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): IPublicTypeDisposable; onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions<Node>) => void): IPublicTypeDisposable;
/** /**
* document * document
* @param fn * @param fn
*/ */
onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable; onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions<Node>) => void): IPublicTypeDisposable;
/** /**
* import schema event * import schema event
@ -193,21 +200,21 @@ export interface IPublicModelDocumentModel {
* @param node * @param node
* @since v1.1.0 * @since v1.1.0
*/ */
isDetectingNode(node: IPublicModelNode): boolean; isDetectingNode(node: Node): boolean;
/** /**
* DropLocation * DropLocation
* get current drop location * get current drop location
* @since v1.1.0 * @since v1.1.0
*/ */
get dropLocation(): IPublicModelDropLocation | null; get dropLocation(): DropLocation | null;
/** /**
* DropLocation * DropLocation
* set current drop location * set current drop location
* @since v1.1.0 * @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 * @since v1.1.0
*/ */
onFocusNodeChanged( onFocusNodeChanged(
fn: (doc: IPublicModelDocumentModel, focusNode: IPublicModelNode) => void, fn: (doc: IPublicModelDocumentModel, focusNode: Node) => void,
): IPublicTypeDisposable; ): IPublicTypeDisposable;
/** /**

View File

@ -1,3 +1,4 @@
import { IPublicTypeDisposable } from '../type';
import { IPublicModelPreference } from './'; import { IPublicModelPreference } from './';
export interface IPublicModelEngineConfig { export interface IPublicModelEngineConfig {
@ -52,7 +53,7 @@ export interface IPublicModelEngineConfig {
* @param fn * @param fn
* @returns * @returns
*/ */
onGot(key: string, fn: (data: any) => void): () => void; onGot(key: string, fn: (data: any) => void): IPublicTypeDisposable;
/** /**
* Preference, Preference Panel * Preference, Preference Panel

View File

@ -1,8 +1,10 @@
import { IPublicModelNode } from '..'; import { IPublicModelNode, IPublicTypeTitleContent } from '..';
export interface IPublicModelExclusiveGroup { export interface IPublicModelExclusiveGroup<
readonly id: string; Node = IPublicModelNode,
readonly title: string; > {
get firstNode(): IPublicModelNode; readonly id: string | undefined;
readonly title: IPublicTypeTitleContent | undefined;
get firstNode(): Node | null;
setVisible(node: Node): void; setVisible(node: Node): void;
} }

View File

@ -1,6 +1,6 @@
import { IPublicModelNode } from './'; import { IPublicModelNode } from './';
export interface IPublicModelModalNodesManager { export interface IPublicModelModalNodesManager<Node = IPublicModelNode> {
/** /**
* *
@ -12,13 +12,13 @@ export interface IPublicModelModalNodesManager {
* *
* get modal nodes * get modal nodes
*/ */
getModalNodes(): IPublicModelNode[]; getModalNodes(): Node[];
/** /**
* *
* get current visible modal 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 * set specfic model node as visible
* @param node Node * @param node Node
*/ */
setVisible(node: IPublicModelNode): void; setVisible(node: Node): void;
/** /**
* *
* set specfic model node as invisible * set specfic model node as invisible
* @param node Node * @param node Node
*/ */
setInvisible(node: IPublicModelNode): void; setInvisible(node: Node): void;
} }

View File

@ -2,13 +2,15 @@ import { IPublicTypeNodeSchema, IPublicTypeNodeData } from '../type';
import { IPublicEnumTransformStage } from '../enum'; import { IPublicEnumTransformStage } from '../enum';
import { IPublicModelNode } from './'; import { IPublicModelNode } from './';
export interface IPublicModelNodeChildren { export interface IPublicModelNodeChildren<
Node = IPublicModelNode
> {
/** /**
* children * children
* get owner node of this nodeChildren * get owner node of this nodeChildren
*/ */
get owner(): IPublicModelNode | null; get owner(): Node | null;
/** /**
* children * children
@ -25,6 +27,7 @@ export interface IPublicModelNodeChildren {
/** /**
* *
*
* @returns * @returns
*/ */
get isEmptyNode(): boolean; get isEmptyNode(): boolean;
@ -42,104 +45,121 @@ export interface IPublicModelNodeChildren {
/** /**
* *
*
* delete the node * delete the node
* @param node * @param node
*/ */
delete(node: IPublicModelNode): boolean; delete(node: Node): boolean;
/** /**
* *
*
* insert a node at specific position * insert a node at specific position
* @param node * @param node
* @param at * @param at
* @returns * @returns
*/ */
insert(node: IPublicModelNode, at?: number | null): void; insert(node: Node, at?: number | null): void;
/** /**
* *
*
* get index of node in current children * get index of node in current children
* @param node * @param node
* @returns * @returns
*/ */
indexOf(node: IPublicModelNode): number; indexOf(node: Node): number;
/** /**
* splice * splice
*
* provide the same function with {Array.prototype.splice} * provide the same function with {Array.prototype.splice}
* @param start * @param start
* @param deleteCount * @param deleteCount
* @param node * @param node
*/ */
splice(start: number, deleteCount: number, node?: IPublicModelNode): any; splice(start: number, deleteCount: number, node?: Node): any;
/** /**
* *
*
* get node with index * get node with index
* @param index * @param index
* @returns * @returns
*/ */
get(index: number): IPublicModelNode | null; get(index: number): Node | null;
/** /**
* *
*
* check if node exists in current children * check if node exists in current children
* @param node * @param node
* @returns * @returns
*/ */
has(node: IPublicModelNode): boolean; has(node: Node): boolean;
/** /**
* forEach * forEach
*
* provide the same function with {Array.prototype.forEach} * provide the same function with {Array.prototype.forEach}
* @param fn * @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(): Node[];
/** /**
* map * map
*
* provide the same function with {Array.prototype.map} * provide the same function with {Array.prototype.map}
* @param fn * @param fn
*/ */
map<T>(fn: (node: IPublicModelNode, index: number) => T[]): any[] | null; map<T = any>(fn: (node: Node, index: number) => T): T[] | null;
/** /**
* every * every
* provide the same function with {Array.prototype.every} * provide the same function with {Array.prototype.every}
* @param fn * @param fn
*/ */
every(fn: (node: IPublicModelNode, index: number) => boolean): boolean; every(fn: (node: Node, index: number) => boolean): boolean;
/** /**
* some * some
* provide the same function with {Array.prototype.some} * provide the same function with {Array.prototype.some}
* @param fn * @param fn
*/ */
some(fn: (node: IPublicModelNode, index: number) => boolean): boolean; some(fn: (node: Node, index: number) => boolean): boolean;
/** /**
* filter * filter
* provide the same function with {Array.prototype.filter} * provide the same function with {Array.prototype.filter}
* @param fn * @param fn
*/ */
filter(fn: (node: IPublicModelNode, index: number) => boolean): any; filter(fn: (node: Node, index: number) => boolean): any;
/** /**
* find * find
* provide the same function with {Array.prototype.find} * provide the same function with {Array.prototype.find}
* @param fn * @param fn
*/ */
find(fn: (node: IPublicModelNode, index: number) => boolean): IPublicModelNode | null; find(fn: (node: Node, index: number) => boolean): Node | null | undefined;
/** /**
* reduce * reduce
*
* provide the same function with {Array.prototype.reduce} * provide the same function with {Array.prototype.reduce}
* @param fn * @param fn
*/ */
reduce(fn: (acc: any, cur: IPublicModelNode) => any, initialValue: any): void; reduce(fn: (acc: any, cur: Node) => any, initialValue: any): void;
/** /**
* schema * schema
*
* import schema * import schema
* @param data * @param data
*/ */
@ -147,6 +167,7 @@ export interface IPublicModelNodeChildren {
/** /**
* schema * schema
*
* export schema * export schema
* @param stage * @param stage
*/ */
@ -154,15 +175,16 @@ export interface IPublicModelNodeChildren {
/** /**
* *
*
* excute remove/add/sort operations * excute remove/add/sort operations
* @param remover * @param remover
* @param adder * @param adder
* @param sorter * @param sorter
*/ */
mergeChildren( mergeChildren(
remover: (node: IPublicModelNode, idx: number) => boolean, remover: (node: Node, idx: number) => boolean,
adder: (children: IPublicModelNode[]) => IPublicTypeNodeData[] | null, adder: (children: Node[]) => IPublicTypeNodeData[] | null,
sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number sorter: (firstNode: Node, secondNode: Node) => number
): any; ): any;
} }

View File

@ -3,7 +3,16 @@ import { IPublicTypeNodeSchema, IPublicTypeIconType, IPublicTypeI18nData, IPubli
import { IPublicEnumTransformStage } from '../enum'; import { IPublicEnumTransformStage } from '../enum';
import { IPublicModelNodeChildren, IPublicModelComponentMeta, IPublicModelProp, IPublicModelProps, IPublicModelSettingTopEntry, IPublicModelDocumentModel, IPublicModelExclusiveGroup } from './'; 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,
Props = IPublicModelProps,
Prop = IPublicModelProp,
ExclusiveGroup = IPublicModelExclusiveGroup
> {
/** /**
* id * id
@ -161,7 +170,7 @@ export interface IPublicModelNode {
* *
* index * index
*/ */
get index(): number; get index(): number | undefined;
/** /**
* *
@ -185,55 +194,55 @@ export interface IPublicModelNode {
* *
* get component meta of this node * get component meta of this node
*/ */
get componentMeta(): IPublicModelComponentMeta | null; get componentMeta(): ComponentMeta | null;
/** /**
* *
* get documentModel of this node * get documentModel of this node
*/ */
get document(): IPublicModelDocumentModel | null; get document(): Document | null;
/** /**
* *
* get previous sibling of this node * get previous sibling of this node
*/ */
get prevSibling(): IPublicModelNode | null; get prevSibling(): Node | null | undefined;
/** /**
* *
* get next sibling of this node * get next sibling of this node
*/ */
get nextSibling(): IPublicModelNode | null; get nextSibling(): Node | null | undefined;
/** /**
* *
* get parent of this node * get parent of this node
*/ */
get parent(): IPublicModelNode | null; get parent(): Node | null;
/** /**
* *
* get children of this node * get children of this node
*/ */
get children(): IPublicModelNodeChildren | null; get children(): NodeChildren | null;
/** /**
* *
* get slots of this node * get slots of this node
*/ */
get slots(): IPublicModelNode[]; get slots(): Node[];
/** /**
* *
* return coresponding prop when this node is a slot node * return coresponding prop when this node is a slot node
*/ */
get slotFor(): IPublicModelProp | null; get slotFor(): Prop | null | undefined;
/** /**
* *
* get props * get props
*/ */
get props(): IPublicModelProps | null; get props(): Props | null;
/** /**
* *
@ -244,7 +253,7 @@ export interface IPublicModelNode {
/** /**
* get conditionGroup * get conditionGroup
*/ */
get conditionGroup(): IPublicModelExclusiveGroup | null; get conditionGroup(): ExclusiveGroup | null;
/** /**
* - schema * - schema
@ -258,7 +267,7 @@ export interface IPublicModelNode {
* get setting entry of this node * get setting entry of this node
* @since v1.1.0 * @since v1.1.0
*/ */
get settingEntry(): IPublicModelSettingTopEntry; get settingEntry(): SettingTopEntry;
/** /**
* *
@ -289,7 +298,7 @@ export interface IPublicModelNode {
* get prop by path * get prop by path
* @param path a / a.b / a.0 * @param path a / a.b / a.0
*/ */
getProp(path: string, createIfNone: boolean): IPublicModelProp | null; getProp(path: string, createIfNone: boolean): Prop | null;
/** /**
* path * path
@ -307,7 +316,7 @@ export interface IPublicModelNode {
* @param path a / a.b / a.0 * @param path a / a.b / a.0
* @param createIfNone * @param createIfNone
*/ */
getExtraProp(path: string, createIfNone?: boolean): IPublicModelProp | null; getExtraProp(path: string, createIfNone?: boolean): Prop | null;
/** /**
* path * path
@ -359,8 +368,8 @@ export interface IPublicModelNode {
* @param useMutator * @param useMutator
*/ */
insertBefore( insertBefore(
node: IPublicModelNode, node: Node,
ref?: IPublicModelNode | undefined, ref?: Node | undefined,
useMutator?: boolean, useMutator?: boolean,
): void; ): void;
@ -372,8 +381,8 @@ export interface IPublicModelNode {
* @param useMutator * @param useMutator
*/ */
insertAfter( insertAfter(
node: IPublicModelNode, node: Node,
ref?: IPublicModelNode | undefined, ref?: Node | undefined,
useMutator?: boolean, useMutator?: boolean,
): void; ): void;
@ -384,7 +393,7 @@ export interface IPublicModelNode {
* @param data * @param data
* @returns * @returns
*/ */
replaceChild(node: IPublicModelNode, data: any): IPublicModelNode | null; replaceChild(node: Node, data: any): Node | null;
/** /**
* *
@ -427,9 +436,9 @@ export interface IPublicModelNode {
* @since v1.1.0 * @since v1.1.0
*/ */
mergeChildren( mergeChildren(
remover: (node: IPublicModelNode, idx: number) => boolean, remover: (node: Node, idx: number) => boolean,
adder: (children: IPublicModelNode[]) => any, adder: (children: Node[]) => any,
sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number sorter: (firstNode: Node, secondNode: Node) => number
): any; ): any;
/** /**
@ -438,7 +447,7 @@ export interface IPublicModelNode {
* @param node * @param node
* @since v1.1.0 * @since v1.1.0
*/ */
contains(node: IPublicModelNode): boolean; contains(node: Node): boolean;
/** /**
* action * action
@ -475,4 +484,11 @@ export interface IPublicModelNode {
* @since v1.1.0 * @since v1.1.0
*/ */
setConditionalVisible(): void; setConditionalVisible(): void;
/**
* dom
*/
getDOMNode(): HTMLElement;
} }
export interface IPublicModelNode extends IBaseModelNode<IPublicModelDocumentModel, IPublicModelNode> {}

View File

@ -10,6 +10,7 @@ import {
IPublicApiCanvas, IPublicApiCanvas,
IPluginPreferenceMananger, IPluginPreferenceMananger,
IPublicApiPlugins, IPublicApiPlugins,
IPublicApiWorkspace,
} from '../api'; } from '../api';
import { IPublicModelEngineConfig } from './'; import { IPublicModelEngineConfig } from './';
@ -28,31 +29,88 @@ export interface IPublicModelPluginContext {
* by using this, init options can be accessed from inside plugin * by using this, init options can be accessed from inside plugin
*/ */
preference: IPluginPreferenceMananger; preference: IPluginPreferenceMananger;
/**
* skeleton API
* @tutorial https://lowcode-engine.cn/site/docs/api/skeleton
*/
get skeleton(): IPublicApiSkeleton; get skeleton(): IPublicApiSkeleton;
/**
* hotkey API
* @tutorial https://lowcode-engine.cn/site/docs/api/hotkey
*/
get hotkey(): IPublicApiHotkey; get hotkey(): IPublicApiHotkey;
/**
* setter API
* @tutorial https://lowcode-engine.cn/site/docs/api/setters
*/
get setters(): IPublicApiSetters; get setters(): IPublicApiSetters;
/**
* config API
* @tutorial https://lowcode-engine.cn/site/docs/api/config
*/
get config(): IPublicModelEngineConfig; get config(): IPublicModelEngineConfig;
/**
* material API
* @tutorial https://lowcode-engine.cn/site/docs/api/material
*/
get material(): IPublicApiMaterial; get material(): IPublicApiMaterial;
/** /**
* event API
* this event works globally, can be used between plugins and engine. * this event works globally, can be used between plugins and engine.
* @tutorial https://lowcode-engine.cn/site/docs/api/event
*/ */
get event(): IPublicApiEvent; get event(): IPublicApiEvent;
/**
* project API
* @tutorial https://lowcode-engine.cn/site/docs/api/project
*/
get project(): IPublicApiProject; get project(): IPublicApiProject;
/**
* common API
* @tutorial https://lowcode-engine.cn/site/docs/api/common
*/
get common(): IPublicApiCommon; get common(): IPublicApiCommon;
/**
* plugins API
* @tutorial https://lowcode-engine.cn/site/docs/api/plugins
*/
get plugins(): IPublicApiPlugins; get plugins(): IPublicApiPlugins;
/**
* logger API
* @tutorial https://lowcode-engine.cn/site/docs/api/logger
*/
get logger(): IPublicApiLogger; get logger(): IPublicApiLogger;
/** /**
* this event works within current plugin, on an emit locally. * this event works within current plugin, on an emit locally.
* @tutorial https://lowcode-engine.cn/site/docs/api/event
*/ */
get pluginEvent(): IPublicApiEvent; get pluginEvent(): IPublicApiEvent;
/**
* canvas API
* @tutorial https://lowcode-engine.cn/site/docs/api/canvas
*/
get canvas(): IPublicApiCanvas; get canvas(): IPublicApiCanvas;
/**
* workspace API
* @tutorial https://lowcode-engine.cn/site/docs/api/workspace
*/
get workspace(): IPublicApiWorkspace;
} }
/** /**
*
*
* @deprecated please use IPublicModelPluginContext instead * @deprecated please use IPublicModelPluginContext instead
*/ */
export interface ILowCodePluginContext extends IPublicModelPluginContext { export interface ILowCodePluginContext extends IPublicModelPluginContext {

View File

@ -2,7 +2,9 @@ import { IPublicEnumTransformStage } from '../enum';
import { IPublicTypeCompositeValue } from '../type'; import { IPublicTypeCompositeValue } from '../type';
import { IPublicModelNode } from './'; import { IPublicModelNode } from './';
export interface IPublicModelProp { export interface IPublicModelProp<
Node = IPublicModelNode
> {
/** /**
* id * id
@ -25,14 +27,14 @@ export interface IPublicModelProp {
* *
* get node instance, which this prop belongs to * get node instance, which this prop belongs to
*/ */
get node(): IPublicModelNode | null; get node(): Node | null;
/** /**
* prop Slot slotNode * prop Slot slotNode
* return the slot node (only if the current prop represents a slot) * return the slot node (only if the current prop represents a slot)
* @since v1.1.0 * @since v1.1.0
*/ */
get slotNode(): IPublicModelNode | undefined | null; get slotNode(): Node | undefined | null;
/** /**
* Prop , true * Prop , true

View File

@ -1,7 +1,9 @@
import { IPublicTypeCompositeValue } from '../type'; import { IPublicTypeCompositeValue } from '../type';
import { IPublicModelNode, IPublicModelProp } from './'; import { IPublicModelNode } from './';
export interface IPublicModelProps { export interface IBaseModelProps<
Prop
> {
/** /**
* id * id
@ -24,7 +26,7 @@ export interface IPublicModelProps {
* get prop by path * get prop by path
* @param path a / a.b / a.0 * @param path a / a.b / a.0
*/ */
getProp(path: string): IPublicModelProp | null; getProp(path: string): Prop | null;
/** /**
* path * path
@ -39,7 +41,7 @@ export interface IPublicModelProps {
* get extra prop by path * get extra prop by path
* @param path a / a.b / a.0 * @param path a / a.b / a.0
*/ */
getExtraProp(path: string): IPublicModelProp | null; getExtraProp(path: string): Prop | null;
/** /**
* path * path
@ -83,3 +85,5 @@ export interface IPublicModelProps {
add(value: IPublicTypeCompositeValue, key?: string | number | undefined): any; add(value: IPublicTypeCompositeValue, key?: string | number | undefined): any;
} }
export type IPublicModelProps = IBaseModelProps<IPublicModelProps>;

View File

@ -5,11 +5,15 @@ export interface IPublicModelResource {
get icon(): ReactElement | undefined; get icon(): ReactElement | undefined;
get options(): Object; get options(): Record<string, any>;
get name(): string | undefined; get name(): string | undefined;
get type(): string | undefined; get type(): string | undefined;
get category(): string | undefined; get category(): string | undefined;
get children(): IPublicModelResource[];
get viewName(): string | undefined;
} }

View File

@ -1,7 +1,9 @@
import { IPublicModelNode } from './'; import { IPublicModelNode } from './';
import { IPublicTypeDisposable } from '../type'; import { IPublicTypeDisposable } from '../type';
export interface IPublicModelSelection { export interface IPublicModelSelection<
Node = IPublicModelNode
> {
/** /**
* id * id
@ -14,7 +16,7 @@ export interface IPublicModelSelection {
* return selected Node instancereturn the first one if multiple nodes are selected * return selected Node instancereturn the first one if multiple nodes are selected
* @since v1.1.0 * @since v1.1.0
*/ */
get node(): IPublicModelNode | null; get node(): Node | null;
/** /**
* *
@ -62,7 +64,7 @@ export interface IPublicModelSelection {
* *
* get selected nodes * get selected nodes
*/ */
getNodes(): IPublicModelNode[]; getNodes(): Node[];
/** /**
* *
@ -72,7 +74,7 @@ export interface IPublicModelSelection {
* getTopNodes() will return [A, B], subA will be removed * getTopNodes() will return [A, B], subA will be removed
* @since v1.0.16 * @since v1.0.16
*/ */
getTopNodes(includeRoot?: boolean): IPublicModelNode[]; getTopNodes(includeRoot?: boolean): Node[];
/** /**
* selection * selection

View File

@ -1,7 +1,7 @@
import { IPublicModelNode } from '..'; import { IPublicModelNode } from '..';
import { IPublicEnumDragObjectType } from '../enum'; import { IPublicEnumDragObjectType } from '../enum';
export interface IPublicTypeDragNodeObject { export interface IPublicTypeDragNodeObject<Node = IPublicModelNode> {
type: IPublicEnumDragObjectType.Node; type: IPublicEnumDragObjectType.Node;
nodes: IPublicModelNode[]; nodes: Node[];
} }

View File

@ -13,7 +13,7 @@ export interface IPublicTypeFieldConfig extends IPublicTypeFieldExtraProps {
/** /**
* the name of this setting field, which used in quickEditor * the name of this setting field, which used in quickEditor
*/ */
name: string | number; name?: string | number;
/** /**
* the field title * the field title

View File

@ -1,59 +1,72 @@
import { IPublicModelSettingTarget } from '../model'; import { IPublicModelSettingPropEntry, IPublicModelSettingTarget } from '../model';
import { IPublicTypeLiveTextEditingConfig } from './'; import { IPublicTypeLiveTextEditingConfig } from './';
/** /**
* extra props for field * extra props for field
*/ */
export interface IPublicTypeFieldExtraProps { export interface IPublicTypeFieldExtraProps {
/** /**
* *
*/ */
isRequired?: boolean; isRequired?: boolean;
/** /**
* default value of target prop for setter use * default value of target prop for setter use
*/ */
defaultValue?: any; defaultValue?: any;
/** /**
* get value for field * get value for field
*/ */
getValue?: (target: IPublicModelSettingTarget, fieldValue: any) => any; getValue?: (target: IPublicModelSettingPropEntry, fieldValue: any) => any;
/** /**
* set value for field * 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 * the field conditional show, is not set always true
* @default undefined * @default undefined
*/ */
condition?: (target: IPublicModelSettingTarget) => boolean; condition?: (target: IPublicModelSettingPropEntry) => boolean;
/** /**
* autorun when something change * autorun when something change
*/ */
autorun?: (target: IPublicModelSettingTarget) => void; autorun?: (target: IPublicModelSettingTarget) => void;
/** /**
* is this field is a virtual field that not save to schema * is this field is a virtual field that not save to schema
*/ */
virtual?: (target: IPublicModelSettingTarget) => boolean; virtual?: (target: IPublicModelSettingTarget) => boolean;
/** /**
* default collapsed when display accordion * default collapsed when display accordion
*/ */
defaultCollapsed?: boolean; defaultCollapsed?: boolean;
/** /**
* important field * important field
*/ */
important?: boolean; important?: boolean;
/** /**
* internal use * internal use
*/ */
forceInline?: number; forceInline?: number;
/** /**
* *
*/ */
supportVariable?: boolean; supportVariable?: boolean;
/** /**
* compatiable vision display * compatiable vision display
*/ */
display?: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry'; display?: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry';
// @todo 这个 omit 是否合理? // @todo 这个 omit 是否合理?
/** /**
* @todo * @todo

View File

@ -1,5 +1,5 @@
import { IPublicTypePropType, IPublicTypeComponentAction } from './'; 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 { export interface IPublicTypeCallbacks {
// hooks // hooks
onMouseDownHook?: (e: MouseEvent, currentNode: any) => any; onMouseDownHook?: (e: MouseEvent, currentNode: IPublicModelNode) => any;
onDblClickHook?: (e: MouseEvent, currentNode: any) => any; onDblClickHook?: (e: MouseEvent, currentNode: IPublicModelNode) => any;
onClickHook?: (e: MouseEvent, currentNode: any) => any; onClickHook?: (e: MouseEvent, currentNode: IPublicModelNode) => any;
// onLocateHook?: (e: any, currentNode: any) => any; // onLocateHook?: (e: any, currentNode: any) => any;
// onAcceptHook?: (currentNode: any, locationData: any) => any; // onAcceptHook?: (currentNode: any, locationData: any) => any;
onMoveHook?: (currentNode: any) => boolean; onMoveHook?: (currentNode: IPublicModelNode) => boolean;
// thinkof 限制性拖拽 // thinkof 限制性拖拽
onHoverHook?: (currentNode: any) => boolean; onHoverHook?: (currentNode: IPublicModelNode) => boolean;
onChildMoveHook?: (childNode: any, currentNode: any) => boolean; onChildMoveHook?: (childNode: IPublicModelNode, currentNode: IPublicModelNode) => boolean;
// events // events
onNodeRemove?: (removedNode: any, currentNode: any) => void; onNodeRemove?: (removedNode: IPublicModelNode | null, currentNode: IPublicModelNode | null) => void;
onNodeAdd?: (addedNode: any, currentNode: any) => void; onNodeAdd?: (addedNode: IPublicModelNode | null, currentNode: IPublicModelNode | null) => void;
onSubtreeModified?: (currentNode: any, options: any) => void; onSubtreeModified?: (currentNode: IPublicModelNode, options: any) => void;
onResize?: ( onResize?: (
e: MouseEvent & { e: MouseEvent & {
trigger: string; trigger: string;
@ -220,6 +220,6 @@ export interface IPublicTypeCallbacks {
deltaX?: number; deltaX?: number;
deltaY?: number; deltaY?: number;
}, },
currentNode: any, currentNode: IPublicModelNode,
) => void; ) => void;
} }

View File

@ -1,6 +1,8 @@
import { IPublicModelNode } from '..'; import { IPublicModelNode } from '..';
export interface IPublicTypeOnChangeOptions { export interface IPublicTypeOnChangeOptions<
Node = IPublicModelNode
> {
type: string; type: string;
node: IPublicModelNode; node: Node;
} }

Some files were not shown because too many files have changed in this diff Show More