mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-15 05:36:39 +00:00
feat: added workspace api to support registration of multiple resources
This commit is contained in:
parent
0a2427354b
commit
dae09e3bcb
@ -11,15 +11,41 @@ sidebar_position: 12
|
|||||||
|
|
||||||
低代码设计器窗口模型
|
低代码设计器窗口模型
|
||||||
|
|
||||||
|
## 变量
|
||||||
|
|
||||||
|
### id
|
||||||
|
|
||||||
|
窗口唯一 id
|
||||||
|
|
||||||
|
### title
|
||||||
|
|
||||||
|
窗口标题
|
||||||
|
|
||||||
|
### resourceName
|
||||||
|
|
||||||
|
窗口资源名字
|
||||||
|
|
||||||
## 方法签名
|
## 方法签名
|
||||||
|
|
||||||
### importSchema(schema: IPublicTypeNodeSchema)
|
### importSchema
|
||||||
当前窗口导入 schema
|
当前窗口导入 schema, 会调用当前窗口对应资源的 import 钩子
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function importSchema(schema: IPublicTypeNodeSchema): void
|
||||||
|
```
|
||||||
|
|
||||||
相关类型:[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)
|
相关类型:[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)
|
||||||
|
|
||||||
### changeViewType(viewName: string)
|
### changeViewType
|
||||||
修改当前窗口视图类型
|
修改当前窗口视图类型
|
||||||
|
|
||||||
### async save()
|
```typescript
|
||||||
调用当前窗口视图保存钩子
|
function changeViewType(viewName: string): void
|
||||||
|
```
|
||||||
|
|
||||||
|
### save
|
||||||
|
当前窗口的保存方法,会调用当前窗口对应资源的 save 钩子
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function save(): Promise(void)
|
||||||
|
```
|
||||||
|
|||||||
@ -21,6 +21,30 @@ sidebar_position: 12
|
|||||||
|
|
||||||
当前设计器窗口模型
|
当前设计器窗口模型
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
get window(): IPublicModelWindow
|
||||||
|
```
|
||||||
|
|
||||||
|
关联模型 [IPublicModelWindow](./model/window)
|
||||||
|
|
||||||
|
### plugins
|
||||||
|
|
||||||
|
应用级别的插件注册
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
get plugins(): IPublicApiPlugins
|
||||||
|
```
|
||||||
|
|
||||||
|
关联模型 [IPublicApiPlugins](./plugins)
|
||||||
|
|
||||||
|
### windows
|
||||||
|
|
||||||
|
当前设计器的编辑窗口
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
get window(): IPublicModelWindow[]
|
||||||
|
```
|
||||||
|
|
||||||
关联模型 [IPublicModelWindow](./model/window)
|
关联模型 [IPublicModelWindow](./model/window)
|
||||||
|
|
||||||
## 方法签名
|
## 方法签名
|
||||||
@ -34,3 +58,19 @@ registerResourceType(resourceName: string, resourceType: 'editor', options: IPub
|
|||||||
```
|
```
|
||||||
|
|
||||||
相关类型:[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts)
|
相关类型:[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts)
|
||||||
|
|
||||||
|
### onChangeWindows
|
||||||
|
|
||||||
|
窗口新增/删除的事件
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function onChangeWindows(fn: () => void): void;
|
||||||
|
```
|
||||||
|
|
||||||
|
### onChangeActiveWindow
|
||||||
|
|
||||||
|
active 窗口变更事件
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function onChangeActiveWindow(fn: () => void): void;
|
||||||
|
```
|
||||||
|
|||||||
155
packages/designer/src/component-actions.ts
Normal file
155
packages/designer/src/component-actions.ts
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
import { IPublicTypeComponentAction, IPublicTypeMetadataTransducer } from '@alilc/lowcode-types';
|
||||||
|
import { engineConfig } from '@alilc/lowcode-editor-core';
|
||||||
|
import { intlNode } from './locale';
|
||||||
|
import {
|
||||||
|
IconLock,
|
||||||
|
IconUnlock,
|
||||||
|
IconRemove,
|
||||||
|
IconClone,
|
||||||
|
IconHidden,
|
||||||
|
} from './icons';
|
||||||
|
import { Node } from './document';
|
||||||
|
import { componentDefaults, legacyIssues } from './transducers';
|
||||||
|
|
||||||
|
export class ComponentActions {
|
||||||
|
actions: IPublicTypeComponentAction[] = [
|
||||||
|
{
|
||||||
|
name: 'remove',
|
||||||
|
content: {
|
||||||
|
icon: IconRemove,
|
||||||
|
title: intlNode('remove'),
|
||||||
|
/* istanbul ignore next */
|
||||||
|
action(node: Node) {
|
||||||
|
node.remove();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
important: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'hide',
|
||||||
|
content: {
|
||||||
|
icon: IconHidden,
|
||||||
|
title: intlNode('hide'),
|
||||||
|
/* istanbul ignore next */
|
||||||
|
action(node: Node) {
|
||||||
|
node.setVisible(false);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/* istanbul ignore next */
|
||||||
|
condition: (node: Node) => {
|
||||||
|
return node.componentMeta.isModal;
|
||||||
|
},
|
||||||
|
important: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'copy',
|
||||||
|
content: {
|
||||||
|
icon: IconClone,
|
||||||
|
title: intlNode('copy'),
|
||||||
|
/* istanbul ignore next */
|
||||||
|
action(node: Node) {
|
||||||
|
// node.remove();
|
||||||
|
const { document: doc, parent, index } = node;
|
||||||
|
if (parent) {
|
||||||
|
const newNode = doc.insertNode(parent, node, index + 1, true);
|
||||||
|
newNode.select();
|
||||||
|
const { isRGL, rglNode } = node.getRGL();
|
||||||
|
if (isRGL) {
|
||||||
|
// 复制 layout 信息
|
||||||
|
let layout = rglNode.getPropValue('layout') || [];
|
||||||
|
let curLayout = layout.filter((item) => item.i === node.getPropValue('fieldId'));
|
||||||
|
if (curLayout && curLayout[0]) {
|
||||||
|
layout.push({
|
||||||
|
...curLayout[0],
|
||||||
|
i: newNode.getPropValue('fieldId'),
|
||||||
|
});
|
||||||
|
rglNode.setPropValue('layout', layout);
|
||||||
|
// 如果是磁贴块复制,则需要滚动到影响位置
|
||||||
|
setTimeout(() => newNode.document.simulator?.scrollToNode(newNode), 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
important: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'lock',
|
||||||
|
content: {
|
||||||
|
icon: IconLock, // 锁定 icon
|
||||||
|
title: intlNode('lock'),
|
||||||
|
/* istanbul ignore next */
|
||||||
|
action(node: Node) {
|
||||||
|
node.lock();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/* istanbul ignore next */
|
||||||
|
condition: (node: Node) => {
|
||||||
|
return engineConfig.get('enableCanvasLock', false) && node.isContainer() && !node.isLocked;
|
||||||
|
},
|
||||||
|
important: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'unlock',
|
||||||
|
content: {
|
||||||
|
icon: IconUnlock, // 解锁 icon
|
||||||
|
title: intlNode('unlock'),
|
||||||
|
/* istanbul ignore next */
|
||||||
|
action(node: Node) {
|
||||||
|
node.lock(false);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/* istanbul ignore next */
|
||||||
|
condition: (node: Node) => {
|
||||||
|
return engineConfig.get('enableCanvasLock', false) && node.isContainer() && node.isLocked;
|
||||||
|
},
|
||||||
|
important: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.registerMetadataTransducer(legacyIssues, 2, 'legacy-issues'); // should use a high level priority, eg: 2
|
||||||
|
this.registerMetadataTransducer(componentDefaults, 100, 'component-defaults');
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBuiltinComponentAction(name: string) {
|
||||||
|
const i = this.actions.findIndex((action) => action.name === name);
|
||||||
|
if (i > -1) {
|
||||||
|
this.actions.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addBuiltinComponentAction(action: IPublicTypeComponentAction) {
|
||||||
|
this.actions.push(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyBuiltinComponentAction(
|
||||||
|
actionName: string,
|
||||||
|
handle: (action: IPublicTypeComponentAction) => void,
|
||||||
|
) {
|
||||||
|
const builtinAction = this.actions.find((action) => action.name === actionName);
|
||||||
|
if (builtinAction) {
|
||||||
|
handle(builtinAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private metadataTransducers: IPublicTypeMetadataTransducer[] = [];
|
||||||
|
|
||||||
|
registerMetadataTransducer(
|
||||||
|
transducer: IPublicTypeMetadataTransducer,
|
||||||
|
level = 100,
|
||||||
|
id?: string,
|
||||||
|
) {
|
||||||
|
transducer.level = level;
|
||||||
|
transducer.id = id;
|
||||||
|
const i = this.metadataTransducers.findIndex((item) => item.level != null && item.level > level);
|
||||||
|
if (i < 0) {
|
||||||
|
this.metadataTransducers.push(transducer);
|
||||||
|
} else {
|
||||||
|
this.metadataTransducers.splice(i, 0, transducer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getRegisteredMetadataTransducers(): IPublicTypeMetadataTransducer[] {
|
||||||
|
return this.metadataTransducers;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,7 +4,6 @@ import {
|
|||||||
IPublicTypeNpmInfo,
|
IPublicTypeNpmInfo,
|
||||||
IPublicTypeNodeData,
|
IPublicTypeNodeData,
|
||||||
IPublicTypeNodeSchema,
|
IPublicTypeNodeSchema,
|
||||||
IPublicTypeComponentAction,
|
|
||||||
IPublicTypeTitleContent,
|
IPublicTypeTitleContent,
|
||||||
IPublicTypeTransformedComponentMetadata,
|
IPublicTypeTransformedComponentMetadata,
|
||||||
IPublicTypeNestingFilter,
|
IPublicTypeNestingFilter,
|
||||||
@ -15,20 +14,13 @@ import {
|
|||||||
IPublicModelComponentMeta,
|
IPublicModelComponentMeta,
|
||||||
} from '@alilc/lowcode-types';
|
} from '@alilc/lowcode-types';
|
||||||
import { deprecate, isRegExp, isTitleConfig } from '@alilc/lowcode-utils';
|
import { deprecate, isRegExp, isTitleConfig } from '@alilc/lowcode-utils';
|
||||||
import { computed, engineConfig, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
|
import { computed, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
|
||||||
import { componentDefaults, legacyIssues } from './transducers';
|
|
||||||
import { isNode, Node, INode } from './document';
|
import { isNode, Node, INode } from './document';
|
||||||
import { Designer } from './designer';
|
import { Designer } from './designer';
|
||||||
import { intlNode } from './locale';
|
|
||||||
import {
|
import {
|
||||||
IconLock,
|
|
||||||
IconUnlock,
|
|
||||||
IconContainer,
|
IconContainer,
|
||||||
IconPage,
|
IconPage,
|
||||||
IconComponent,
|
IconComponent,
|
||||||
IconRemove,
|
|
||||||
IconClone,
|
|
||||||
IconHidden,
|
|
||||||
} from './icons';
|
} from './icons';
|
||||||
|
|
||||||
export function ensureAList(list?: string | string[]): string[] | null {
|
export function ensureAList(list?: string | string[]): string[] | null {
|
||||||
@ -272,7 +264,7 @@ export class ComponentMeta implements IComponentMeta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private transformMetadata(metadta: IPublicTypeComponentMetadata): IPublicTypeTransformedComponentMetadata {
|
private transformMetadata(metadta: IPublicTypeComponentMetadata): IPublicTypeTransformedComponentMetadata {
|
||||||
const result = getRegisteredMetadataTransducers().reduce((prevMetadata, current) => {
|
const result = this.designer.componentActions.getRegisteredMetadataTransducers().reduce((prevMetadata, current) => {
|
||||||
return current(prevMetadata);
|
return current(prevMetadata);
|
||||||
}, preprocessMetadata(metadta));
|
}, preprocessMetadata(metadta));
|
||||||
|
|
||||||
@ -300,7 +292,7 @@ export class ComponentMeta implements IComponentMeta {
|
|||||||
const disabled =
|
const disabled =
|
||||||
ensureAList(disableBehaviors) ||
|
ensureAList(disableBehaviors) ||
|
||||||
(this.isRootComponent(false) ? ['copy', 'remove', 'lock', 'unlock'] : null);
|
(this.isRootComponent(false) ? ['copy', 'remove', 'lock', 'unlock'] : null);
|
||||||
actions = builtinComponentActions.concat(
|
actions = this.designer.componentActions.actions.concat(
|
||||||
this.designer.getGlobalComponentActions() || [],
|
this.designer.getGlobalComponentActions() || [],
|
||||||
actions || [],
|
actions || [],
|
||||||
);
|
);
|
||||||
@ -382,142 +374,3 @@ function preprocessMetadata(metadata: IPublicTypeComponentMetadata): IPublicType
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const metadataTransducers: IPublicTypeMetadataTransducer[] = [];
|
|
||||||
|
|
||||||
export function registerMetadataTransducer(
|
|
||||||
transducer: IPublicTypeMetadataTransducer,
|
|
||||||
level = 100,
|
|
||||||
id?: string,
|
|
||||||
) {
|
|
||||||
transducer.level = level;
|
|
||||||
transducer.id = id;
|
|
||||||
const i = metadataTransducers.findIndex((item) => item.level != null && item.level > level);
|
|
||||||
if (i < 0) {
|
|
||||||
metadataTransducers.push(transducer);
|
|
||||||
} else {
|
|
||||||
metadataTransducers.splice(i, 0, transducer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRegisteredMetadataTransducers(): IPublicTypeMetadataTransducer[] {
|
|
||||||
return metadataTransducers;
|
|
||||||
}
|
|
||||||
|
|
||||||
const builtinComponentActions: IPublicTypeComponentAction[] = [
|
|
||||||
{
|
|
||||||
name: 'remove',
|
|
||||||
content: {
|
|
||||||
icon: IconRemove,
|
|
||||||
title: intlNode('remove'),
|
|
||||||
/* istanbul ignore next */
|
|
||||||
action(node: Node) {
|
|
||||||
node.remove();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
important: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'hide',
|
|
||||||
content: {
|
|
||||||
icon: IconHidden,
|
|
||||||
title: intlNode('hide'),
|
|
||||||
/* istanbul ignore next */
|
|
||||||
action(node: Node) {
|
|
||||||
node.setVisible(false);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
/* istanbul ignore next */
|
|
||||||
condition: (node: Node) => {
|
|
||||||
return node.componentMeta.isModal;
|
|
||||||
},
|
|
||||||
important: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'copy',
|
|
||||||
content: {
|
|
||||||
icon: IconClone,
|
|
||||||
title: intlNode('copy'),
|
|
||||||
/* istanbul ignore next */
|
|
||||||
action(node: Node) {
|
|
||||||
// node.remove();
|
|
||||||
const { document: doc, parent, index } = node;
|
|
||||||
if (parent) {
|
|
||||||
const newNode = doc.insertNode(parent, node, index + 1, true);
|
|
||||||
newNode.select();
|
|
||||||
const { isRGL, rglNode } = node.getRGL();
|
|
||||||
if (isRGL) {
|
|
||||||
// 复制 layout 信息
|
|
||||||
let layout = rglNode.getPropValue('layout') || [];
|
|
||||||
let curLayout = layout.filter((item) => item.i === node.getPropValue('fieldId'));
|
|
||||||
if (curLayout && curLayout[0]) {
|
|
||||||
layout.push({
|
|
||||||
...curLayout[0],
|
|
||||||
i: newNode.getPropValue('fieldId'),
|
|
||||||
});
|
|
||||||
rglNode.setPropValue('layout', layout);
|
|
||||||
// 如果是磁贴块复制,则需要滚动到影响位置
|
|
||||||
setTimeout(() => newNode.document.simulator?.scrollToNode(newNode), 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
important: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'lock',
|
|
||||||
content: {
|
|
||||||
icon: IconLock, // 锁定 icon
|
|
||||||
title: intlNode('lock'),
|
|
||||||
/* istanbul ignore next */
|
|
||||||
action(node: Node) {
|
|
||||||
node.lock();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
/* istanbul ignore next */
|
|
||||||
condition: (node: Node) => {
|
|
||||||
return engineConfig.get('enableCanvasLock', false) && node.isContainer() && !node.isLocked;
|
|
||||||
},
|
|
||||||
important: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'unlock',
|
|
||||||
content: {
|
|
||||||
icon: IconUnlock, // 解锁 icon
|
|
||||||
title: intlNode('unlock'),
|
|
||||||
/* istanbul ignore next */
|
|
||||||
action(node: Node) {
|
|
||||||
node.lock(false);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
/* istanbul ignore next */
|
|
||||||
condition: (node: Node) => {
|
|
||||||
return engineConfig.get('enableCanvasLock', false) && node.isContainer() && node.isLocked;
|
|
||||||
},
|
|
||||||
important: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export function removeBuiltinComponentAction(name: string) {
|
|
||||||
const i = builtinComponentActions.findIndex((action) => action.name === name);
|
|
||||||
if (i > -1) {
|
|
||||||
builtinComponentActions.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function addBuiltinComponentAction(action: IPublicTypeComponentAction) {
|
|
||||||
builtinComponentActions.push(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function modifyBuiltinComponentAction(
|
|
||||||
actionName: string,
|
|
||||||
handle: (action: IPublicTypeComponentAction) => void,
|
|
||||||
) {
|
|
||||||
const builtinAction = builtinComponentActions.find((action) => action.name === actionName);
|
|
||||||
if (builtinAction) {
|
|
||||||
handle(builtinAction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registerMetadataTransducer(legacyIssues, 2, 'legacy-issues'); // should use a high level priority, eg: 2
|
|
||||||
registerMetadataTransducer(componentDefaults, 100, 'component-defaults');
|
|
||||||
|
|||||||
@ -32,6 +32,7 @@ import { OffsetObserver, createOffsetObserver } from './offset-observer';
|
|||||||
import { focusing } from './focusing';
|
import { focusing } from './focusing';
|
||||||
import { SettingTopEntry } from './setting';
|
import { SettingTopEntry } from './setting';
|
||||||
import { BemToolsManager } from '../builtin-simulator/bem-tools/manager';
|
import { BemToolsManager } from '../builtin-simulator/bem-tools/manager';
|
||||||
|
import { ComponentActions } from '../component-actions';
|
||||||
|
|
||||||
const logger = new Logger({ level: 'warn', bizName: 'designer' });
|
const logger = new Logger({ level: 'warn', bizName: 'designer' });
|
||||||
|
|
||||||
@ -60,6 +61,8 @@ export interface DesignerProps {
|
|||||||
export class Designer implements IDesigner {
|
export class Designer implements IDesigner {
|
||||||
readonly dragon = new Dragon(this);
|
readonly dragon = new Dragon(this);
|
||||||
|
|
||||||
|
readonly componentActions = new ComponentActions();
|
||||||
|
|
||||||
readonly activeTracker = new ActiveTracker();
|
readonly activeTracker = new ActiveTracker();
|
||||||
|
|
||||||
readonly detecting = new Detecting();
|
readonly detecting = new Detecting();
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { IPublicTypeTitleContent, IPublicTypeSetterType, IPublicTypeDynamicSette
|
|||||||
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 { SettingEntry } from './setting-entry';
|
||||||
import { computed, obx, makeObservable, action } from '@alilc/lowcode-editor-core';
|
import { computed, obx, makeObservable, action, untracked } 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: SettingEntry, config: IPublicTypeFieldConfig) {
|
||||||
@ -43,8 +43,10 @@ export class SettingField extends SettingPropEntry implements SettingEntry {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (isDynamicSetter(this._setter)) {
|
if (isDynamicSetter(this._setter)) {
|
||||||
|
return untracked(() => {
|
||||||
const shellThis = this.internalToShellPropEntry();
|
const shellThis = this.internalToShellPropEntry();
|
||||||
return this._setter.call(shellThis, shellThis);
|
return this._setter.call(shellThis, shellThis);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return this._setter;
|
return this._setter;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { Designer } from '../designer';
|
|||||||
import { BuiltinSimulatorHostView } from '../builtin-simulator';
|
import { BuiltinSimulatorHostView } from '../builtin-simulator';
|
||||||
import './project.less';
|
import './project.less';
|
||||||
|
|
||||||
class BuiltinLoading extends Component {
|
export class BuiltinLoading extends Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div id="engine-loading-wrapper">
|
<div id="engine-loading-wrapper">
|
||||||
|
|||||||
@ -30,6 +30,8 @@ export class Project implements IProject {
|
|||||||
|
|
||||||
private _simulator?: ISimulatorHost;
|
private _simulator?: ISimulatorHost;
|
||||||
|
|
||||||
|
private isRendererReady: boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模拟器
|
* 模拟器
|
||||||
*/
|
*/
|
||||||
@ -318,6 +320,7 @@ export class Project implements IProject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setRendererReady(renderer: any) {
|
setRendererReady(renderer: any) {
|
||||||
|
this.isRendererReady = true;
|
||||||
this.emitter.emit('lowcode_engine_renderer_ready', renderer);
|
this.emitter.emit('lowcode_engine_renderer_ready', renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +331,10 @@ export class Project implements IProject {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onRendererReady(fn: (args: any) => void): () => void {
|
onRendererReady(fn: () => void): () => void {
|
||||||
|
if (this.isRendererReady) {
|
||||||
|
fn();
|
||||||
|
}
|
||||||
this.emitter.on('lowcode_engine_renderer_ready', fn);
|
this.emitter.on('lowcode_engine_renderer_ready', fn);
|
||||||
return () => {
|
return () => {
|
||||||
this.emitter.removeListener('lowcode_engine_renderer_ready', fn);
|
this.emitter.removeListener('lowcode_engine_renderer_ready', fn);
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import '../../fixtures/window';
|
import '../../fixtures/window';
|
||||||
import { Node } from '../../../src/document/node/node';
|
|
||||||
import { Designer } from '../../../src/designer/designer';
|
import { Designer } from '../../../src/designer/designer';
|
||||||
import divMeta from '../../fixtures/component-metadata/div';
|
import divMeta from '../../fixtures/component-metadata/div';
|
||||||
import div2Meta from '../../fixtures/component-metadata/div2';
|
import div2Meta from '../../fixtures/component-metadata/div2';
|
||||||
@ -19,22 +18,18 @@ import page2Meta from '../../fixtures/component-metadata/page2';
|
|||||||
import {
|
import {
|
||||||
ComponentMeta,
|
ComponentMeta,
|
||||||
isComponentMeta,
|
isComponentMeta,
|
||||||
removeBuiltinComponentAction,
|
|
||||||
addBuiltinComponentAction,
|
|
||||||
modifyBuiltinComponentAction,
|
|
||||||
ensureAList,
|
ensureAList,
|
||||||
buildFilter,
|
buildFilter,
|
||||||
registerMetadataTransducer,
|
|
||||||
getRegisteredMetadataTransducers,
|
|
||||||
} from '../../../src/component-meta';
|
} from '../../../src/component-meta';
|
||||||
import { componentDefaults } from '../../../src/transducers';
|
|
||||||
|
|
||||||
const mockCreateSettingEntry = jest.fn();
|
|
||||||
jest.mock('../../../src/designer/designer', () => {
|
jest.mock('../../../src/designer/designer', () => {
|
||||||
return {
|
return {
|
||||||
Designer: jest.fn().mockImplementation(() => {
|
Designer: jest.fn().mockImplementation(() => {
|
||||||
|
const { ComponentActions } = require('../../../src/component-actions');
|
||||||
return {
|
return {
|
||||||
getGlobalComponentActions: () => [],
|
getGlobalComponentActions: () => [],
|
||||||
|
componentActions: new ComponentActions(),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@ -126,12 +121,12 @@ describe('组件元数据处理', () => {
|
|||||||
expect(meta.availableActions[1].name).toBe('hide');
|
expect(meta.availableActions[1].name).toBe('hide');
|
||||||
expect(meta.availableActions[2].name).toBe('copy');
|
expect(meta.availableActions[2].name).toBe('copy');
|
||||||
|
|
||||||
removeBuiltinComponentAction('remove');
|
designer.componentActions.removeBuiltinComponentAction('remove');
|
||||||
expect(meta.availableActions).toHaveLength(4);
|
expect(meta.availableActions).toHaveLength(4);
|
||||||
expect(meta.availableActions[0].name).toBe('hide');
|
expect(meta.availableActions[0].name).toBe('hide');
|
||||||
expect(meta.availableActions[1].name).toBe('copy');
|
expect(meta.availableActions[1].name).toBe('copy');
|
||||||
|
|
||||||
addBuiltinComponentAction({
|
designer.componentActions.addBuiltinComponentAction({
|
||||||
name: 'new',
|
name: 'new',
|
||||||
content: {
|
content: {
|
||||||
action() {},
|
action() {},
|
||||||
@ -227,17 +222,17 @@ describe('帮助函数', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('registerMetadataTransducer', () => {
|
it('registerMetadataTransducer', () => {
|
||||||
expect(getRegisteredMetadataTransducers()).toHaveLength(2);
|
expect(designer.componentActions.getRegisteredMetadataTransducers()).toHaveLength(2);
|
||||||
// 插入到 legacy-issues 和 component-defaults 的中间
|
// 插入到 legacy-issues 和 component-defaults 的中间
|
||||||
registerMetadataTransducer((metadata) => metadata, 3, 'noop');
|
designer.componentActions.registerMetadataTransducer((metadata) => metadata, 3, 'noop');
|
||||||
expect(getRegisteredMetadataTransducers()).toHaveLength(3);
|
expect(designer.componentActions.getRegisteredMetadataTransducers()).toHaveLength(3);
|
||||||
|
|
||||||
registerMetadataTransducer((metadata) => metadata);
|
designer.componentActions.registerMetadataTransducer((metadata) => metadata);
|
||||||
expect(getRegisteredMetadataTransducers()).toHaveLength(4);
|
expect(designer.componentActions.getRegisteredMetadataTransducers()).toHaveLength(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('modifyBuiltinComponentAction', () => {
|
it('modifyBuiltinComponentAction', () => {
|
||||||
modifyBuiltinComponentAction('copy', (action) => {
|
designer.componentActions.modifyBuiltinComponentAction('copy', (action) => {
|
||||||
expect(action.name).toBe('copy');
|
expect(action.name).toBe('copy');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -69,7 +69,7 @@ export class SettingsPrimaryPane extends Component<{ engineEditor: Editor; confi
|
|||||||
}
|
}
|
||||||
|
|
||||||
const workspace = globalContext.get('workspace');
|
const workspace = globalContext.get('workspace');
|
||||||
const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor');
|
const editor = this.props.engineEditor;
|
||||||
const designer = editor.get('designer');
|
const designer = editor.get('designer');
|
||||||
const current = designer?.currentSelection?.getNodes()?.[0];
|
const current = designer?.currentSelection?.getNodes()?.[0];
|
||||||
let node: Node | null = settings.first;
|
let node: Node | null = settings.first;
|
||||||
|
|||||||
@ -138,6 +138,16 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background-color: #edeff3;
|
background-color: #edeff3;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: -1;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
.lc-workbench {
|
.lc-workbench {
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,23 @@
|
|||||||
import { registerMetadataTransducer } from '@alilc/lowcode-designer';
|
|
||||||
import parseJSFunc from './transducers/parse-func';
|
import parseJSFunc from './transducers/parse-func';
|
||||||
import parseProps from './transducers/parse-props';
|
import parseProps from './transducers/parse-props';
|
||||||
import addonCombine from './transducers/addon-combine';
|
import addonCombine from './transducers/addon-combine';
|
||||||
|
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||||
|
|
||||||
export const registerDefaults = () => {
|
export const registerDefaults = (ctx: IPublicModelPluginContext) => {
|
||||||
|
const { material } = ctx;
|
||||||
|
return {
|
||||||
|
init() {
|
||||||
// parseFunc
|
// parseFunc
|
||||||
registerMetadataTransducer(parseJSFunc, 1, 'parse-func');
|
material.registerMetadataTransducer(parseJSFunc, 1, 'parse-func');
|
||||||
|
|
||||||
// parseProps
|
// parseProps
|
||||||
registerMetadataTransducer(parseProps, 5, 'parse-props');
|
material.registerMetadataTransducer(parseProps, 5, 'parse-props');
|
||||||
|
|
||||||
// addon/platform custom
|
// addon/platform custom
|
||||||
registerMetadataTransducer(addonCombine, 10, 'combine-props');
|
material.registerMetadataTransducer(addonCombine, 10, 'combine-props');
|
||||||
|
},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
registerDefaults.pluginName = '___register_defaults___';
|
||||||
|
|||||||
@ -50,6 +50,8 @@ export class Skeleton {
|
|||||||
|
|
||||||
readonly topArea: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>;
|
readonly topArea: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>;
|
||||||
|
|
||||||
|
readonly subTopArea: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>;
|
||||||
|
|
||||||
readonly toolbar: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>;
|
readonly toolbar: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>;
|
||||||
|
|
||||||
readonly leftFixedArea: Area<PanelConfig, Panel>;
|
readonly leftFixedArea: Area<PanelConfig, Panel>;
|
||||||
@ -88,6 +90,17 @@ export class Skeleton {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
this.subTopArea = new Area(
|
||||||
|
this,
|
||||||
|
'subTopArea',
|
||||||
|
(config) => {
|
||||||
|
if (isWidget(config)) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
return this.createWidget(config);
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
this.toolbar = new Area(
|
this.toolbar = new Area(
|
||||||
this,
|
this,
|
||||||
'toolbar',
|
'toolbar',
|
||||||
@ -389,6 +402,8 @@ export class Skeleton {
|
|||||||
case 'topArea':
|
case 'topArea':
|
||||||
case 'top':
|
case 'top':
|
||||||
return this.topArea.add(parsedConfig as PanelDockConfig);
|
return this.topArea.add(parsedConfig as PanelDockConfig);
|
||||||
|
case 'subTopArea':
|
||||||
|
return this.subTopArea.add(parsedConfig as PanelDockConfig);
|
||||||
case 'toolbar':
|
case 'toolbar':
|
||||||
return this.toolbar.add(parsedConfig as PanelDockConfig);
|
return this.toolbar.add(parsedConfig as PanelDockConfig);
|
||||||
case 'mainArea':
|
case 'mainArea':
|
||||||
|
|||||||
@ -59,8 +59,6 @@ export * from './modules/skeleton-types';
|
|||||||
export * from './modules/designer-types';
|
export * from './modules/designer-types';
|
||||||
export * from './modules/lowcode-types';
|
export * from './modules/lowcode-types';
|
||||||
|
|
||||||
registerDefaults();
|
|
||||||
|
|
||||||
async function registryInnerPlugin(designer: Designer, editor: Editor, plugins: Plugins) {
|
async function registryInnerPlugin(designer: Designer, editor: Editor, plugins: Plugins) {
|
||||||
// 注册一批内置插件
|
// 注册一批内置插件
|
||||||
await plugins.register(OutlinePlugin, {}, { autoInit: true });
|
await plugins.register(OutlinePlugin, {}, { autoInit: true });
|
||||||
@ -68,6 +66,7 @@ async function registryInnerPlugin(designer: Designer, editor: Editor, plugins:
|
|||||||
await plugins.register(setterRegistry, {}, { autoInit: true });
|
await plugins.register(setterRegistry, {}, { autoInit: true });
|
||||||
await plugins.register(defaultPanelRegistry(editor));
|
await plugins.register(defaultPanelRegistry(editor));
|
||||||
await plugins.register(builtinHotkey);
|
await plugins.register(builtinHotkey);
|
||||||
|
await plugins.register(registerDefaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
const innerWorkspace = new InnerWorkspace(registryInnerPlugin, shellModelFactory);
|
const innerWorkspace = new InnerWorkspace(registryInnerPlugin, shellModelFactory);
|
||||||
@ -82,6 +81,7 @@ editor.set('skeleton' as any, innerSkeleton);
|
|||||||
|
|
||||||
const designer = new Designer({ editor, shellModelFactory });
|
const designer = new Designer({ editor, shellModelFactory });
|
||||||
editor.set('designer' as any, designer);
|
editor.set('designer' as any, designer);
|
||||||
|
|
||||||
const { project: innerProject } = designer;
|
const { project: innerProject } = designer;
|
||||||
|
|
||||||
const innerHotkey = new InnerHotkey();
|
const innerHotkey = new InnerHotkey();
|
||||||
@ -195,6 +195,7 @@ export async function init(
|
|||||||
engineContainer,
|
engineContainer,
|
||||||
);
|
);
|
||||||
innerWorkspace.setActive(true);
|
innerWorkspace.setActive(true);
|
||||||
|
await innerWorkspace.plugins.init(pluginPreference);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,6 @@
|
|||||||
import { Editor, globalContext } from '@alilc/lowcode-editor-core';
|
import { Editor, globalContext } from '@alilc/lowcode-editor-core';
|
||||||
import {
|
import {
|
||||||
Designer,
|
Designer,
|
||||||
registerMetadataTransducer,
|
|
||||||
getRegisteredMetadataTransducers,
|
|
||||||
addBuiltinComponentAction,
|
|
||||||
removeBuiltinComponentAction,
|
|
||||||
modifyBuiltinComponentAction,
|
|
||||||
isComponentMeta,
|
isComponentMeta,
|
||||||
} from '@alilc/lowcode-designer';
|
} from '@alilc/lowcode-designer';
|
||||||
import { IPublicTypeAssetsJson } from '@alilc/lowcode-utils';
|
import { IPublicTypeAssetsJson } from '@alilc/lowcode-utils';
|
||||||
@ -85,20 +80,20 @@ export class Material implements IPublicApiMaterial {
|
|||||||
* @param level
|
* @param level
|
||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
registerMetadataTransducer(
|
registerMetadataTransducer = (
|
||||||
transducer: IPublicTypeMetadataTransducer,
|
transducer: IPublicTypeMetadataTransducer,
|
||||||
level?: number,
|
level?: number,
|
||||||
id?: string | undefined,
|
id?: string | undefined,
|
||||||
) {
|
) => {
|
||||||
registerMetadataTransducer(transducer, level, id);
|
this[designerSymbol].componentActions.registerMetadataTransducer(transducer, level, id);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有物料元数据管道函数
|
* 获取所有物料元数据管道函数
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
getRegisteredMetadataTransducers() {
|
getRegisteredMetadataTransducers() {
|
||||||
return getRegisteredMetadataTransducers();
|
return this[designerSymbol].componentActions.getRegisteredMetadataTransducers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -147,7 +142,7 @@ export class Material implements IPublicApiMaterial {
|
|||||||
* @param action
|
* @param action
|
||||||
*/
|
*/
|
||||||
addBuiltinComponentAction(action: IPublicTypeComponentAction) {
|
addBuiltinComponentAction(action: IPublicTypeComponentAction) {
|
||||||
addBuiltinComponentAction(action);
|
this[designerSymbol].componentActions.addBuiltinComponentAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,7 +150,7 @@ export class Material implements IPublicApiMaterial {
|
|||||||
* @param name
|
* @param name
|
||||||
*/
|
*/
|
||||||
removeBuiltinComponentAction(name: string) {
|
removeBuiltinComponentAction(name: string) {
|
||||||
removeBuiltinComponentAction(name);
|
this[designerSymbol].componentActions.removeBuiltinComponentAction(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -164,7 +159,7 @@ export class Material implements IPublicApiMaterial {
|
|||||||
* @param handle
|
* @param handle
|
||||||
*/
|
*/
|
||||||
modifyBuiltinComponentAction(actionName: string, handle: (action: IPublicTypeComponentAction) => void) {
|
modifyBuiltinComponentAction(actionName: string, handle: (action: IPublicTypeComponentAction) => void) {
|
||||||
modifyBuiltinComponentAction(actionName, handle);
|
this[designerSymbol].componentActions.modifyBuiltinComponentAction(actionName, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -18,14 +18,12 @@ import {
|
|||||||
|
|
||||||
import { DocumentModel } from '../model/document-model';
|
import { DocumentModel } from '../model/document-model';
|
||||||
import { SimulatorHost } from './simulator-host';
|
import { SimulatorHost } from './simulator-host';
|
||||||
import { editorSymbol, projectSymbol, simulatorHostSymbol, simulatorRendererSymbol, documentSymbol } from '../symbols';
|
import { editorSymbol, projectSymbol, simulatorHostSymbol, documentSymbol } from '../symbols';
|
||||||
|
|
||||||
const innerProjectSymbol = Symbol('innerProject');
|
const innerProjectSymbol = Symbol('innerProject');
|
||||||
export class Project implements IPublicApiProject {
|
export class Project implements IPublicApiProject {
|
||||||
private readonly [editorSymbol]: IPublicModelEditor;
|
|
||||||
private readonly [innerProjectSymbol]: InnerProject;
|
private readonly [innerProjectSymbol]: InnerProject;
|
||||||
private [simulatorHostSymbol]: BuiltinSimulatorHost;
|
private [simulatorHostSymbol]: BuiltinSimulatorHost;
|
||||||
private [simulatorRendererSymbol]: any;
|
|
||||||
get [projectSymbol](): InnerProject {
|
get [projectSymbol](): InnerProject {
|
||||||
if (this.workspaceMode) {
|
if (this.workspaceMode) {
|
||||||
return this[innerProjectSymbol];
|
return this[innerProjectSymbol];
|
||||||
@ -38,9 +36,12 @@ export class Project implements IPublicApiProject {
|
|||||||
return this[innerProjectSymbol];
|
return this[innerProjectSymbol];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get [editorSymbol](): IPublicModelEditor {
|
||||||
|
return this[projectSymbol]?.designer.editor;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(project: InnerProject, public workspaceMode: boolean = false) {
|
constructor(project: InnerProject, public workspaceMode: boolean = false) {
|
||||||
this[innerProjectSymbol] = project;
|
this[innerProjectSymbol] = project;
|
||||||
this[editorSymbol] = project?.designer.editor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static create(project: InnerProject) {
|
static create(project: InnerProject) {
|
||||||
@ -201,13 +202,9 @@ export class Project implements IPublicApiProject {
|
|||||||
* 当前 project 的渲染器 ready 事件
|
* 当前 project 的渲染器 ready 事件
|
||||||
*/
|
*/
|
||||||
onSimulatorRendererReady(fn: () => void): IPublicTypeDisposable {
|
onSimulatorRendererReady(fn: () => void): IPublicTypeDisposable {
|
||||||
const offFn = this[projectSymbol].onRendererReady((renderer: any) => {
|
const offFn = this[projectSymbol].onRendererReady(() => {
|
||||||
this[simulatorRendererSymbol] = renderer;
|
|
||||||
fn();
|
fn();
|
||||||
});
|
});
|
||||||
if (this[simulatorRendererSymbol]) {
|
|
||||||
fn();
|
|
||||||
}
|
|
||||||
return offFn;
|
return offFn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { IPublicApiWorkspace } from '@alilc/lowcode-types';
|
import { IPublicApiWorkspace } from '@alilc/lowcode-types';
|
||||||
import { Workspace as InnerWorkSpace } from '@alilc/lowcode-workspace';
|
import { Workspace as InnerWorkSpace } from '@alilc/lowcode-workspace';
|
||||||
|
import { Plugins } from '@alilc/lowcode-shell';
|
||||||
import { Window } from '../model/window';
|
import { Window } from '../model/window';
|
||||||
import { workspaceSymbol } from '../symbols';
|
import { workspaceSymbol } from '../symbols';
|
||||||
|
|
||||||
@ -21,4 +22,36 @@ export class Workspace implements IPublicApiWorkspace {
|
|||||||
registerResourceType(resourceName: string, resourceType: 'editor', options: any): void {
|
registerResourceType(resourceName: string, resourceType: 'editor', options: any): void {
|
||||||
this[workspaceSymbol].registerResourceType(resourceName, resourceType, options);
|
this[workspaceSymbol].registerResourceType(resourceName, resourceType, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openEditorWindow(resourceName: string, title: string, viewType?: string) {
|
||||||
|
this[workspaceSymbol].openEditorWindow(resourceName, title, viewType);
|
||||||
|
}
|
||||||
|
|
||||||
|
openEditorWindowById(id: string) {
|
||||||
|
this[workspaceSymbol].openEditorWindowById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeEditorWindow(resourceName: string, title: string) {
|
||||||
|
this[workspaceSymbol].removeEditorWindow(resourceName, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeEditorWindowById(id: string) {
|
||||||
|
this[workspaceSymbol].removeEditorWindowById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
get plugins() {
|
||||||
|
return new Plugins(this[workspaceSymbol].plugins, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
get windows() {
|
||||||
|
return this[workspaceSymbol].windows.map(d => new Window(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeWindows(fn: () => void) {
|
||||||
|
return this[workspaceSymbol].onChangeWindows(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeActiveWindow(fn: () => void) {
|
||||||
|
return this[workspaceSymbol].onChangeActiveWindow(fn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,22 @@ import { EditorWindow } from '@alilc/lowcode-workspace';
|
|||||||
export class Window implements IPublicModelWindow {
|
export class Window implements IPublicModelWindow {
|
||||||
private readonly [windowSymbol]: EditorWindow;
|
private readonly [windowSymbol]: EditorWindow;
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return this[windowSymbol].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return this[windowSymbol].title;
|
||||||
|
}
|
||||||
|
|
||||||
|
get icon() {
|
||||||
|
return this[windowSymbol].icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
get resourceName() {
|
||||||
|
return this[windowSymbol].resourceName;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(editorWindow: EditorWindow) {
|
constructor(editorWindow: EditorWindow) {
|
||||||
this[windowSymbol] = editorWindow;
|
this[windowSymbol] = editorWindow;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,6 @@ export const dragonSymbol = Symbol('dragon');
|
|||||||
export const componentMetaSymbol = Symbol('componentMeta');
|
export const componentMetaSymbol = Symbol('componentMeta');
|
||||||
export const dropLocationSymbol = Symbol('dropLocation');
|
export const dropLocationSymbol = Symbol('dropLocation');
|
||||||
export const simulatorHostSymbol = Symbol('simulatorHost');
|
export const simulatorHostSymbol = Symbol('simulatorHost');
|
||||||
export const simulatorRendererSymbol = Symbol('simulatorRenderer');
|
|
||||||
export const dragObjectSymbol = Symbol('dragObject');
|
export const dragObjectSymbol = Symbol('dragObject');
|
||||||
export const locateEventSymbol = Symbol('locateEvent');
|
export const locateEventSymbol = Symbol('locateEvent');
|
||||||
export const designerCabinSymbol = Symbol('designerCabin');
|
export const designerCabinSymbol = Symbol('designerCabin');
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { IPublicModelWindow } from '../model';
|
import { IPublicModelWindow } from '../model';
|
||||||
import { IPublicResourceOptions } from '../type';
|
import { IPublicResourceOptions } from '../type';
|
||||||
|
import { IPublicApiPlugins } from '@alilc/lowcode-types';
|
||||||
|
|
||||||
export interface IPublicApiWorkspace {
|
export interface IPublicApiWorkspace {
|
||||||
/** 是否启用 workspace 模式 */
|
/** 是否启用 workspace 模式 */
|
||||||
@ -10,4 +11,21 @@ export interface IPublicApiWorkspace {
|
|||||||
|
|
||||||
/** 注册资源 */
|
/** 注册资源 */
|
||||||
registerResourceType(resourceName: string, resourceType: 'editor', options: IPublicResourceOptions): void;
|
registerResourceType(resourceName: string, resourceType: 'editor', options: IPublicResourceOptions): void;
|
||||||
|
|
||||||
|
/** 打开视图窗口 */
|
||||||
|
openEditorWindow(resourceName: string, title: string, viewType?: string): void;
|
||||||
|
|
||||||
|
/** 移除窗口 */
|
||||||
|
removeEditorWindow(resourceName: string, title: string): void;
|
||||||
|
|
||||||
|
plugins: IPublicApiPlugins;
|
||||||
|
|
||||||
|
/** 当前设计器的编辑窗口 */
|
||||||
|
windows: IPublicModelWindow[];
|
||||||
|
|
||||||
|
/** 窗口新增/删除的事件 */
|
||||||
|
onChangeWindows: (fn: () => void) => void;
|
||||||
|
|
||||||
|
/** active 窗口变更事件 */
|
||||||
|
onChangeActiveWindow: (fn: () => void) => void;
|
||||||
}
|
}
|
||||||
@ -9,4 +9,13 @@ export interface IPublicModelWindow {
|
|||||||
|
|
||||||
/** 调用当前窗口视图保存钩子 */
|
/** 调用当前窗口视图保存钩子 */
|
||||||
save(): Promise<any>;
|
save(): Promise<any>;
|
||||||
|
|
||||||
|
/** 窗口 id */
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/** 窗口标题 */
|
||||||
|
title?: string;
|
||||||
|
|
||||||
|
/** 窗口资源名字 */
|
||||||
|
resourceName?: string;
|
||||||
}
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
export interface IPublicViewFunctions {
|
export interface IPublicViewFunctions {
|
||||||
/** 视图初始化 */
|
/** 视图初始化钩子 */
|
||||||
init?: () => Promise<void>;
|
init?: () => Promise<void>;
|
||||||
/** 资源保存时调用视图的钩子 */
|
/** 资源保存时,会调用视图的钩子 */
|
||||||
save?: () => Promise<void>;
|
save?: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,6 +20,9 @@ export interface IPublicResourceOptions {
|
|||||||
/** 资源描述 */
|
/** 资源描述 */
|
||||||
description?: string;
|
description?: string;
|
||||||
|
|
||||||
|
/** 资源 icon 标识 */
|
||||||
|
icon?: React.ReactElement;
|
||||||
|
|
||||||
/** 默认视图类型 */
|
/** 默认视图类型 */
|
||||||
defaultViewType: string;
|
defaultViewType: string;
|
||||||
|
|
||||||
@ -35,4 +38,7 @@ export interface IPublicResourceOptions {
|
|||||||
import?: (schema: any) => Promise<{
|
import?: (schema: any) => Promise<{
|
||||||
[viewName: string]: any;
|
[viewName: string]: any;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
/** 默认标题 */
|
||||||
|
defaultTitle?: string;
|
||||||
}
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
* 所有可能的停靠位置
|
* 所有可能的停靠位置
|
||||||
*/
|
*/
|
||||||
export type IPublicTypeWidgetConfigArea = 'leftArea' | 'left' | 'rightArea' |
|
export type IPublicTypeWidgetConfigArea = 'leftArea' | 'left' | 'rightArea' |
|
||||||
'right' | 'topArea' | 'top' |
|
'right' | 'topArea' | 'subTopArea' | 'top' |
|
||||||
'toolbar' | 'mainArea' | 'main' |
|
'toolbar' | 'mainArea' | 'main' |
|
||||||
'center' | 'centerArea' | 'bottomArea' |
|
'center' | 'centerArea' | 'bottomArea' |
|
||||||
'bottom' | 'leftFixedArea' |
|
'bottom' | 'leftFixedArea' |
|
||||||
|
|||||||
@ -33,7 +33,7 @@ import {
|
|||||||
IPublicTypePluginMeta,
|
IPublicTypePluginMeta,
|
||||||
} from '@alilc/lowcode-types';
|
} from '@alilc/lowcode-types';
|
||||||
import { getLogger } from '@alilc/lowcode-utils';
|
import { getLogger } from '@alilc/lowcode-utils';
|
||||||
import { Workspace as InnerWorkspace } from './index';
|
import { Workspace as InnerWorkspace } from './workspace';
|
||||||
import { EditorWindow } from './editor-window/context';
|
import { EditorWindow } from './editor-window/context';
|
||||||
|
|
||||||
export class BasicContext {
|
export class BasicContext {
|
||||||
@ -51,7 +51,7 @@ export class BasicContext {
|
|||||||
designer: Designer;
|
designer: Designer;
|
||||||
registerInnerPlugins: () => Promise<void>;
|
registerInnerPlugins: () => Promise<void>;
|
||||||
innerSetters: InnerSetters;
|
innerSetters: InnerSetters;
|
||||||
innerSkeleton: any;
|
innerSkeleton: InnerSkeleton;
|
||||||
innerHotkey: InnerHotkey;
|
innerHotkey: InnerHotkey;
|
||||||
innerPlugins: LowCodePluginManager;
|
innerPlugins: LowCodePluginManager;
|
||||||
canvas: Canvas;
|
canvas: Canvas;
|
||||||
@ -65,7 +65,7 @@ export class BasicContext {
|
|||||||
const designer: Designer = new Designer({
|
const designer: Designer = new Designer({
|
||||||
editor,
|
editor,
|
||||||
viewName,
|
viewName,
|
||||||
shellModelFactory: innerWorkspace.shellModelFactory,
|
shellModelFactory: innerWorkspace?.shellModelFactory,
|
||||||
});
|
});
|
||||||
editor.set('designer' as any, designer);
|
editor.set('designer' as any, designer);
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ export class BasicContext {
|
|||||||
|
|
||||||
// 注册一批内置插件
|
// 注册一批内置插件
|
||||||
this.registerInnerPlugins = async function registerPlugins() {
|
this.registerInnerPlugins = async function registerPlugins() {
|
||||||
await innerWorkspace.registryInnerPlugin(designer, editor, plugins);
|
await innerWorkspace?.registryInnerPlugin(designer, editor, plugins);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { makeObservable, obx } from '@alilc/lowcode-editor-core';
|
import { makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||||
import { IPublicEditorView, IPublicViewFunctions } from '@alilc/lowcode-types';
|
import { IPublicEditorView, IPublicViewFunctions } from '@alilc/lowcode-types';
|
||||||
import { flow } from 'mobx';
|
import { flow } from 'mobx';
|
||||||
import { Workspace as InnerWorkspace } from '../';
|
import { Workspace as InnerWorkspace } from '../workspace';
|
||||||
import { BasicContext } from '../base-context';
|
import { BasicContext } from '../base-context';
|
||||||
import { EditorWindow } from '../editor-window/context';
|
import { EditorWindow } from '../editor-window/context';
|
||||||
import { getWebviewPlugin } from '../inner-plugins/webview';
|
import { getWebviewPlugin } from '../inner-plugins/webview';
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
import { observer } from '@alilc/lowcode-editor-core';
|
import { BuiltinLoading } from '@alilc/lowcode-designer';
|
||||||
|
import { engineConfig, observer } from '@alilc/lowcode-editor-core';
|
||||||
import {
|
import {
|
||||||
Workbench,
|
Workbench,
|
||||||
} from '@alilc/lowcode-editor-skeleton';
|
} from '@alilc/lowcode-editor-skeleton';
|
||||||
import { Component } from 'react';
|
import { PureComponent } from 'react';
|
||||||
import { Context } from './context';
|
import { Context } from './context';
|
||||||
|
|
||||||
export * from '../base-context';
|
export * from '../base-context';
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class EditorView extends Component<{
|
export class EditorView extends PureComponent<{
|
||||||
editorView: Context;
|
editorView: Context;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
}, any> {
|
}, any> {
|
||||||
@ -17,7 +18,8 @@ export class EditorView extends Component<{
|
|||||||
const editorView = this.props.editorView;
|
const editorView = this.props.editorView;
|
||||||
const skeleton = editorView.innerSkeleton;
|
const skeleton = editorView.innerSkeleton;
|
||||||
if (!editorView.isInit) {
|
if (!editorView.isInit) {
|
||||||
return null;
|
const Loading = engineConfig.get('loadingComponent', BuiltinLoading);
|
||||||
|
return <Loading />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,12 +1,21 @@
|
|||||||
|
import { uniqueId } from '@alilc/lowcode-utils';
|
||||||
import { makeObservable, obx } from '@alilc/lowcode-editor-core';
|
import { makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||||
import { Context } from '../editor-view/context';
|
import { Context } from '../editor-view/context';
|
||||||
import { Workspace } from '..';
|
import { Workspace } from '../workspace';
|
||||||
import { Resource } from '../resource';
|
import { Resource } from '../resource';
|
||||||
|
|
||||||
export class EditorWindow {
|
export class EditorWindow {
|
||||||
constructor(readonly resource: Resource, readonly workspace: Workspace) {
|
id: string = uniqueId('window');
|
||||||
|
icon: React.ReactElement | undefined;
|
||||||
|
|
||||||
|
constructor(readonly resource: Resource, readonly workspace: Workspace, public title: string | undefined = '') {
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
this.init();
|
this.init();
|
||||||
|
this.icon = resource.icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
get resourceName(): string {
|
||||||
|
return this.resource.options.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
async importSchema(schema: any) {
|
async importSchema(schema: any) {
|
||||||
|
|||||||
@ -1,28 +1,35 @@
|
|||||||
import { Component } from 'react';
|
import { PureComponent } from 'react';
|
||||||
import { EditorView } from '../editor-view/view';
|
import { EditorView } from '../editor-view/view';
|
||||||
import { observer } from '@alilc/lowcode-editor-core';
|
import { engineConfig, observer } from '@alilc/lowcode-editor-core';
|
||||||
import { EditorWindow } from './context';
|
import { EditorWindow } from './context';
|
||||||
|
import { BuiltinLoading } from '@alilc/lowcode-designer';
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class EditorWindowView extends Component<{
|
export class EditorWindowView extends PureComponent<{
|
||||||
editorWindow: EditorWindow;
|
editorWindow: EditorWindow;
|
||||||
|
active: boolean;
|
||||||
}, any> {
|
}, any> {
|
||||||
render() {
|
render() {
|
||||||
const { resource, editorView, editorViews } = this.props.editorWindow;
|
const { active } = this.props;
|
||||||
|
const { editorView, editorViews } = this.props.editorWindow;
|
||||||
if (!editorView) {
|
if (!editorView) {
|
||||||
return null;
|
const Loading = engineConfig.get('loadingComponent', BuiltinLoading);
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<div className="workspace-engine-main">
|
<div className={`workspace-engine-main ${active ? 'active' : ''}`}>
|
||||||
|
<Loading />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`workspace-engine-main ${active ? 'active' : ''}`}>
|
||||||
{
|
{
|
||||||
Array.from(editorViews.values()).map((editorView: any) => {
|
Array.from(editorViews.values()).map((editorView: any) => {
|
||||||
return (
|
return (
|
||||||
<EditorView
|
<EditorView
|
||||||
resource={resource}
|
|
||||||
key={editorView.name}
|
key={editorView.name}
|
||||||
active={editorView.active}
|
active={editorView.active}
|
||||||
editorView={editorView}
|
editorView={editorView}
|
||||||
defaultViewType
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,70 +1 @@
|
|||||||
import { Designer } from '@alilc/lowcode-designer';
|
export { Workspace } from './workspace';
|
||||||
import { Editor } from '@alilc/lowcode-editor-core';
|
|
||||||
import {
|
|
||||||
Skeleton as InnerSkeleton,
|
|
||||||
} from '@alilc/lowcode-editor-skeleton';
|
|
||||||
import { Plugins } from '@alilc/lowcode-shell';
|
|
||||||
import { IPublicResourceOptions } from '@alilc/lowcode-types';
|
|
||||||
import { EditorWindow } from './editor-window/context';
|
|
||||||
import { Resource } from './resource';
|
|
||||||
|
|
||||||
export { Resource } from './resource';
|
|
||||||
export * from './editor-window/context';
|
|
||||||
export * from './layouts/workbench';
|
|
||||||
|
|
||||||
export class Workspace {
|
|
||||||
readonly editor = new Editor();
|
|
||||||
readonly skeleton = new InnerSkeleton(this.editor);
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
readonly registryInnerPlugin: (designer: Designer, editor: Editor, plugins: Plugins) => Promise<void>,
|
|
||||||
readonly shellModelFactory: any,
|
|
||||||
) {
|
|
||||||
if (this.defaultResource) {
|
|
||||||
this.window = new EditorWindow(this.defaultResource, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _isActive = false;
|
|
||||||
|
|
||||||
get isActive() {
|
|
||||||
return this._isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
setActive(value: boolean) {
|
|
||||||
this._isActive = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
editorWindows: [];
|
|
||||||
|
|
||||||
window: EditorWindow;
|
|
||||||
|
|
||||||
private resources: Map<string, Resource> = new Map();
|
|
||||||
|
|
||||||
registerResourceType(resourceName: string, resourceType: 'editor' | 'webview', options: IPublicResourceOptions): void {
|
|
||||||
if (resourceType === 'editor') {
|
|
||||||
const resource = new Resource(options);
|
|
||||||
this.resources.set(resourceName, resource);
|
|
||||||
|
|
||||||
if (!this.window) {
|
|
||||||
this.window = new EditorWindow(this.defaultResource, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get defaultResource() {
|
|
||||||
if (this.resources.size === 1) {
|
|
||||||
return this.resources.values().next().value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeResourceType(resourceName: string) {
|
|
||||||
if (this.resources.has(resourceName)) {
|
|
||||||
this.resources.delete(resourceName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
openEditorWindow() {}
|
|
||||||
}
|
|
||||||
@ -7,6 +7,9 @@ import { Area } from '@alilc/lowcode-editor-skeleton';
|
|||||||
export default class LeftArea extends Component<{ area: Area }> {
|
export default class LeftArea extends Component<{ area: Area }> {
|
||||||
render() {
|
render() {
|
||||||
const { area } = this.props;
|
const { area } = this.props;
|
||||||
|
if (area.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className={classNames('lc-left-area', {
|
<div className={classNames('lc-left-area', {
|
||||||
'lc-area-visible': area.visible,
|
'lc-area-visible': area.visible,
|
||||||
|
|||||||
67
packages/workspace/src/layouts/sub-top-area.tsx
Normal file
67
packages/workspace/src/layouts/sub-top-area.tsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { Component, Fragment } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { observer } from '@alilc/lowcode-editor-core';
|
||||||
|
import { Area } from '@alilc/lowcode-editor-skeleton';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class SubTopArea extends Component<{ area: Area; itemClassName?: string }> {
|
||||||
|
render() {
|
||||||
|
const { area, itemClassName } = this.props;
|
||||||
|
|
||||||
|
if (area.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classNames('lc-sub-top-area engine-actionpane', {
|
||||||
|
'lc-area-visible': area.visible,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Contents area={area} itemClassName={itemClassName} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class Contents extends Component<{ area: Area; itemClassName?: string }> {
|
||||||
|
render() {
|
||||||
|
const { area, itemClassName } = this.props;
|
||||||
|
const left: any[] = [];
|
||||||
|
const center: any[] = [];
|
||||||
|
const right: any[] = [];
|
||||||
|
area.container.items.slice().sort((a, b) => {
|
||||||
|
const index1 = a.config?.index || 0;
|
||||||
|
const index2 = b.config?.index || 0;
|
||||||
|
return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1);
|
||||||
|
}).forEach(item => {
|
||||||
|
const content = (
|
||||||
|
<div className={itemClassName || ''} key={`top-area-${item.name}`}>
|
||||||
|
{item.content}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
if (item.align === 'center') {
|
||||||
|
center.push(content);
|
||||||
|
} else if (item.align === 'left') {
|
||||||
|
left.push(content);
|
||||||
|
} else {
|
||||||
|
right.push(content);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let children = [];
|
||||||
|
if (left && left.length) {
|
||||||
|
children.push(<div className="lc-sub-top-area-left">{left}</div>);
|
||||||
|
}
|
||||||
|
if (center && center.length) {
|
||||||
|
children.push(<div className="lc-sub-top-area-center">{center}</div>);
|
||||||
|
}
|
||||||
|
if (right && right.length) {
|
||||||
|
children.push(<div className="lc-sub-top-area-right">{right}</div>);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{children}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,7 +8,7 @@ export default class TopArea extends Component<{ area: Area; itemClassName?: str
|
|||||||
render() {
|
render() {
|
||||||
const { area, itemClassName } = this.props;
|
const { area, itemClassName } = this.props;
|
||||||
|
|
||||||
if (!area?.container?.items?.length) {
|
if (area.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -138,7 +138,7 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background-color: #edeff3;
|
background-color: #edeff3;
|
||||||
.lc-top-area {
|
.lc-top-area, .lc-sub-top-area {
|
||||||
height: var(--top-area-height);
|
height: var(--top-area-height);
|
||||||
background-color: var(--color-pane-background);
|
background-color: var(--color-pane-background);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -150,18 +150,18 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lc-top-area-left {
|
.lc-top-area-left, .lc-sub-top-area-left {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lc-top-area-center {
|
.lc-top-area-center, .lc-sub-top-area-center {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 0 8px;
|
margin: 0 8px;
|
||||||
}
|
}
|
||||||
.lc-top-area-right {
|
.lc-top-area-right, .lc-sub-top-area-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
> * {
|
> * {
|
||||||
@ -335,6 +335,7 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
position: relative;
|
||||||
.lc-toolbar {
|
.lc-toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: var(--toolbar-height);
|
height: var(--toolbar-height);
|
||||||
@ -359,6 +360,12 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lc-workspace-workbench-window {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.lc-right-area {
|
.lc-right-area {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: var(--right-area-width);
|
width: var(--right-area-width);
|
||||||
|
|||||||
@ -11,10 +11,17 @@ import BottomArea from './bottom-area';
|
|||||||
import './workbench.less';
|
import './workbench.less';
|
||||||
import { SkeletonContext } from '../skeleton-context';
|
import { SkeletonContext } from '../skeleton-context';
|
||||||
import { EditorConfig, PluginClassSet } from '@alilc/lowcode-types';
|
import { EditorConfig, PluginClassSet } from '@alilc/lowcode-types';
|
||||||
import { Workspace } from '..';
|
import { Workspace } from '../workspace';
|
||||||
|
import SubTopArea from './sub-top-area';
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class Workbench extends Component<{ workspace: Workspace; config?: EditorConfig; components?: PluginClassSet; className?: string; topAreaItemClassName?: string }> {
|
export class Workbench extends Component<{
|
||||||
|
workspace: Workspace;
|
||||||
|
config?: EditorConfig;
|
||||||
|
components?: PluginClassSet;
|
||||||
|
className?: string;
|
||||||
|
topAreaItemClassName?: string;
|
||||||
|
}> {
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
const { config, components, workspace } = this.props;
|
const { config, components, workspace } = this.props;
|
||||||
@ -34,8 +41,20 @@ export class Workbench extends Component<{ workspace: Workspace; config?: Editor
|
|||||||
<LeftFloatPane area={skeleton.leftFloatArea} />
|
<LeftFloatPane area={skeleton.leftFloatArea} />
|
||||||
<LeftFixedPane area={skeleton.leftFixedArea} />
|
<LeftFixedPane area={skeleton.leftFixedArea} />
|
||||||
<div className="lc-workspace-workbench-center">
|
<div className="lc-workspace-workbench-center">
|
||||||
{/* <Toolbar area={skeleton.toolbar} /> */}
|
<>
|
||||||
<EditorWindowView editorWindow={workspace.window} />
|
<SubTopArea area={skeleton.subTopArea} itemClassName={topAreaItemClassName} />
|
||||||
|
<div className="lc-workspace-workbench-window">
|
||||||
|
{
|
||||||
|
workspace.windows.map(d => (
|
||||||
|
<EditorWindowView
|
||||||
|
active={d.id === workspace.window.id}
|
||||||
|
editorWindow={d}
|
||||||
|
key={d.id}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
<MainArea area={skeleton.mainArea} />
|
<MainArea area={skeleton.mainArea} />
|
||||||
<BottomArea area={skeleton.bottomArea} />
|
<BottomArea area={skeleton.bottomArea} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -19,6 +19,10 @@ export class Resource {
|
|||||||
this.options.init(ctx);
|
this.options.init(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get icon() {
|
||||||
|
return this.options.icon;
|
||||||
|
}
|
||||||
|
|
||||||
async import(schema: any) {
|
async import(schema: any) {
|
||||||
return await this.options.import?.(schema);
|
return await this.options.import?.(schema);
|
||||||
}
|
}
|
||||||
@ -38,4 +42,8 @@ export class Resource {
|
|||||||
async save(value: any) {
|
async save(value: any) {
|
||||||
return await this.options.save?.(value);
|
return await this.options.save?.(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return this.options.defaultTitle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
169
packages/workspace/src/workspace.ts
Normal file
169
packages/workspace/src/workspace.ts
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
import { Designer } from '@alilc/lowcode-designer';
|
||||||
|
import { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||||
|
import { Plugins } from '@alilc/lowcode-shell';
|
||||||
|
import { IPublicApiWorkspace, IPublicResourceOptions } from '@alilc/lowcode-types';
|
||||||
|
import { BasicContext } from './base-context';
|
||||||
|
import { EditorWindow } from './editor-window/context';
|
||||||
|
import { Resource } from './resource';
|
||||||
|
|
||||||
|
export { Resource } from './resource';
|
||||||
|
export * from './editor-window/context';
|
||||||
|
export * from './layouts/workbench';
|
||||||
|
|
||||||
|
enum event {
|
||||||
|
ChangeWindow = 'change_window',
|
||||||
|
|
||||||
|
ChangeActiveWindow = 'change_active_window',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Workspace implements IPublicApiWorkspace {
|
||||||
|
private context: BasicContext;
|
||||||
|
|
||||||
|
private emitter: IEventBus = createModuleEventBus('workspace');
|
||||||
|
|
||||||
|
get skeleton() {
|
||||||
|
return this.context.innerSkeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
get plugins() {
|
||||||
|
return this.context.innerPlugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly registryInnerPlugin: (designer: Designer, editor: Editor, plugins: Plugins) => Promise<void>,
|
||||||
|
readonly shellModelFactory: any,
|
||||||
|
) {
|
||||||
|
this.init();
|
||||||
|
makeObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.initWindow();
|
||||||
|
this.context = new BasicContext(this, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
initWindow() {
|
||||||
|
if (!this.defaultResource) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const title = this.defaultResource.title;
|
||||||
|
this.window = new EditorWindow(this.defaultResource, this, title);
|
||||||
|
this.editorWindowMap.set(this.window.id, this.window);
|
||||||
|
this.windows.push(this.window);
|
||||||
|
this.emitChangeWindow();
|
||||||
|
this.emitChangeActiveWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private _isActive = false;
|
||||||
|
|
||||||
|
get isActive() {
|
||||||
|
return this._isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
setActive(value: boolean) {
|
||||||
|
this._isActive = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
windows: EditorWindow[] = [];
|
||||||
|
|
||||||
|
editorWindowMap: Map<string, EditorWindow> = new Map<string, EditorWindow>();
|
||||||
|
|
||||||
|
@obx.ref window: EditorWindow;
|
||||||
|
|
||||||
|
private resources: Map<string, Resource> = new Map();
|
||||||
|
|
||||||
|
async registerResourceType(resourceName: string, resourceType: 'editor' | 'webview', options: IPublicResourceOptions): Promise<void> {
|
||||||
|
if (resourceType === 'editor') {
|
||||||
|
const resource = new Resource(options);
|
||||||
|
this.resources.set(resourceName, resource);
|
||||||
|
|
||||||
|
if (!this.window && this.defaultResource) {
|
||||||
|
this.initWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get defaultResource(): Resource | null {
|
||||||
|
if (this.resources.size > 1) {
|
||||||
|
return this.resources.values().next().value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeResourceType(resourceName: string) {
|
||||||
|
if (this.resources.has(resourceName)) {
|
||||||
|
this.resources.delete(resourceName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeEditorWindowById(id: string) {
|
||||||
|
const index = this.windows.findIndex(d => (d.id === id));
|
||||||
|
this.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private remove(index: number) {
|
||||||
|
const window = this.windows[index];
|
||||||
|
this.windows = this.windows.splice(index - 1, 1);
|
||||||
|
if (this.window === window) {
|
||||||
|
this.window = this.windows[index] || this.windows[index + 1] || this.windows[index - 1];
|
||||||
|
this.emitChangeActiveWindow();
|
||||||
|
}
|
||||||
|
this.emitChangeWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
removeEditorWindow(resourceName: string, title: string) {
|
||||||
|
const index = this.windows.findIndex(d => (d.resourceName === resourceName && d.title));
|
||||||
|
this.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
openEditorWindowById(id: string) {
|
||||||
|
const window = this.editorWindowMap.get(id);
|
||||||
|
if (window) {
|
||||||
|
this.window = window;
|
||||||
|
this.emitChangeActiveWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openEditorWindow(resourceName: string, title: string, viewType?: string) {
|
||||||
|
const resource = this.resources.get(resourceName);
|
||||||
|
if (!resource) {
|
||||||
|
console.error(`${resourceName} is not available`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const filterWindows = this.windows.filter(d => (d.resourceName === resourceName && d.title == title));
|
||||||
|
if (filterWindows && filterWindows.length) {
|
||||||
|
this.window = filterWindows[0];
|
||||||
|
this.emitChangeActiveWindow();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.window = new EditorWindow(resource, this, title);
|
||||||
|
this.windows.push(this.window);
|
||||||
|
this.editorWindowMap.set(this.window.id, this.window);
|
||||||
|
this.emitChangeWindow();
|
||||||
|
this.emitChangeActiveWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeWindows(fn: () => void) {
|
||||||
|
this.emitter.on(event.ChangeWindow, fn);
|
||||||
|
return () => {
|
||||||
|
this.emitter.removeListener(event.ChangeWindow, fn);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
emitChangeWindow() {
|
||||||
|
this.emitter.emit(event.ChangeWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
emitChangeActiveWindow() {
|
||||||
|
this.emitter.emit(event.ChangeActiveWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeActiveWindow(fn: () => void) {
|
||||||
|
this.emitter.on(event.ChangeActiveWindow, fn);
|
||||||
|
return () => {
|
||||||
|
this.emitter.removeListener(event.ChangeActiveWindow, fn);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user