diff --git a/docs/docs/api/model/document-model.md b/docs/docs/api/model/document-model.md
index 68efe0575..0716588ce 100644
--- a/docs/docs/api/model/document-model.md
+++ b/docs/docs/api/model/document-model.md
@@ -42,6 +42,12 @@ sidebar_position: 0
参见 [模态节点管理](./modal-nodes-manager)
+### dropLocation
+文档的 dropLocation
+相关类型:[IPublicModelDropLocation](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/drop-location.ts)
+
+**@since v1.1.0**
+
## 方法签名
### getNodeById
@@ -90,6 +96,24 @@ removeNode(idOrNode: string | Node)
function checkNesting(dropTarget: Node, dragObject: DragNodeObject | DragNodeDataObject): boolean {}
```
+### isDetectingNode
+检查拖拽放置的目标节点是否可以放置该拖拽对象
+
+```typescript
+/**
+ * 判断是否当前节点处于被探测状态
+ * check is node being detected
+ * @param node
+ * @since v1.1.0
+ */
+isDetectingNode(node: IPublicModelNode): boolean;
+```
+相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
+
+
+**@since v1.1.0**
+
+
## 事件
### onAddNode
@@ -144,7 +168,53 @@ onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void)
### onImportSchema
当前 document 导入新的 schema 事件
-版本 >= 1.0.15
```typescript
-onImportSchema(fn: (schema: any) => void)
-```
\ No newline at end of file
+/**
+ * import schema event
+ * @param fn
+ * @since v1.0.15
+ */
+onImportSchema(fn: (schema: IPublicTypeRootSchema) => void): IPublicTypeDisposable;
+```
+相关类型:
+- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
+- [IPublicTypeRootSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/root-schema.ts)
+
+**@since v1.0.15**
+
+### onFocusNodeChanged
+设置聚焦节点变化的回调
+
+```typescript
+/**
+ * 设置聚焦节点变化的回调
+ * triggered focused node is set mannually from plugin
+ * @param fn
+ * @since v1.1.0
+ */
+onFocusNodeChanged(
+ fn: (doc: IPublicModelDocumentModel, focusNode: IPublicModelNode) => void,
+): IPublicTypeDisposable;
+```
+相关类型:
+- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
+- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
+
+**@since v1.1.0**
+
+### onDropLocationChanged
+设置 DropLocation 变化的回调
+
+```typescript
+/**
+ * 设置 DropLocation 变化的回调
+ * triggered when drop location changed
+ * @param fn
+ * @since v1.1.0
+ */
+onDropLocationChanged(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable;
+```
+
+相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
+
+**@since v1.1.0**
\ No newline at end of file
diff --git a/packages/designer/src/designer/active-tracker.ts b/packages/designer/src/designer/active-tracker.ts
index bf37efe80..d62ad9fe5 100644
--- a/packages/designer/src/designer/active-tracker.ts
+++ b/packages/designer/src/designer/active-tracker.ts
@@ -7,8 +7,9 @@ import {
import { isNode } from '@alilc/lowcode-utils';
export interface IActiveTracker extends IPublicModelActiveTracker {
-
+ track(originalTarget: IPublicTypeActiveTarget | INode): void;
}
+
export class ActiveTracker implements IActiveTracker {
private emitter: IEventBus = createModuleEventBus('ActiveTracker');
diff --git a/packages/designer/src/designer/location.ts b/packages/designer/src/designer/location.ts
index c219a259d..a690b28d5 100644
--- a/packages/designer/src/designer/location.ts
+++ b/packages/designer/src/designer/location.ts
@@ -103,15 +103,11 @@ export interface IDropLocation extends IPublicModelDropLocation {
readonly target: INode;
- readonly detail: IPublicTypeLocationDetail;
-
readonly event: ILocateEvent;
readonly source: string;
get document(): IPublicModelDocumentModel;
-
- clone(event: ILocateEvent): IDropLocation;
}
export class DropLocation implements IDropLocation {
diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts
index f38c2f8bc..5e0717e03 100644
--- a/packages/designer/src/document/document-model.ts
+++ b/packages/designer/src/document/document-model.ts
@@ -14,7 +14,6 @@ import {
IPublicModelNode,
IPublicApiProject,
IPublicModelDropLocation,
- IPublicEnumEventNames,
IPublicEnumTransformStage,
} from '@alilc/lowcode-types';
import { Project } from '../project';
@@ -326,7 +325,7 @@ export class DocumentModel implements IDocumentModel {
this._dropLocation = loc;
// pub event
this.designer.editor.eventBus.emit(
- IPublicEnumEventNames.DOCUMENT_DROPLOCATION_CHANGED,
+ 'document.dropLocation.changed',
{ document: this, location: loc },
);
}
diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts
index a6a5f6ae6..649c45271 100644
--- a/packages/editor-skeleton/src/skeleton.ts
+++ b/packages/editor-skeleton/src/skeleton.ts
@@ -26,7 +26,6 @@ import {
PluginClassSet,
IPublicTypeWidgetBaseConfig,
IPublicTypeWidgetConfigArea,
- IPublicEnumEventNames,
} from '@alilc/lowcode-types';
const logger = new Logger({ level: 'warn', bizName: 'skeleton' });
@@ -174,7 +173,7 @@ export class Skeleton {
*/
setupEvents() {
// adjust pinned status when panel shown
- this.editor.eventBus.on(IPublicEnumEventNames.SKELETON_PANEL_SHOW, (panelName, panel) => {
+ this.editor.eventBus.on(SkeletonEvents.PANEL_SHOW, (panelName, panel) => {
const panelNameKey = `${panelName}-pinned-status-isFloat`;
const isInFloatAreaPreferenceExists = engineConfig.getPreference()?.contains(panelNameKey, 'skeleton');
if (isInFloatAreaPreferenceExists) {
diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts
index 1af53e9ba..d8d81aefc 100644
--- a/packages/engine/src/engine-core.ts
+++ b/packages/engine/src/engine-core.ts
@@ -171,7 +171,7 @@ export async function init(
engineConfig.setEngineOptions(engineOptions as any);
// 注册一批内置插件
- await plugins.register(OutlinePlugin);
+ await plugins.register(OutlinePlugin, {}, { autoInit: true });
await plugins.register(componentMetaParser(designer));
await plugins.register(setterRegistry, {}, { autoInit: true });
await plugins.register(defaultPanelRegistry(editor, designer));
diff --git a/packages/plugin-outline-pane/src/controllers/pane-controller.ts b/packages/plugin-outline-pane/src/controllers/pane-controller.ts
index c472d4c9a..a368c8288 100644
--- a/packages/plugin-outline-pane/src/controllers/pane-controller.ts
+++ b/packages/plugin-outline-pane/src/controllers/pane-controller.ts
@@ -7,7 +7,7 @@ import {
isLocationChildrenDetail,
} from '@alilc/lowcode-utils';
import {
- DragObject,
+ IPublicModelDragObject,
IPublicModelScrollable,
ISensor,
IPublicTypeLocationChildrenDetail,
@@ -50,7 +50,6 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
setup();
}
-
/** -------------------- ISensor begin -------------------- */
private indentTrack = new IndentTrack();
@@ -107,12 +106,12 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
const document = project.getCurrentDocument();
const pos = getPosFromEvent(e, this._shell);
const irect = this.getInsertionRect();
- const originLoc = document.dropLocation;
+ const originLoc = document?.dropLocation;
- const componentMeta = e.dragObject.nodes ? e.dragObject.nodes[0].componentMeta : null;
- if (e.dragObject.type === 'node' && componentMeta && componentMeta.isModal) {
+ const componentMeta = e.dragObject?.nodes ? e.dragObject.nodes[0].componentMeta : null;
+ if (e.dragObject?.type === 'node' && componentMeta && componentMeta.isModal && document?.focusNode) {
return canvas.createLocation({
- target: document.focusNode,
+ target: document?.focusNode,
detail: {
type: IPublicTypeLocationDetailType.Children,
index: 0,
@@ -123,7 +122,9 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
});
}
- if (originLoc && ((pos && pos === 'unchanged') || (irect && globalY >= irect.top && globalY <= irect.bottom))) {
+ if (originLoc
+ && ((pos && pos === 'unchanged') || (irect && globalY >= irect.top && globalY <= irect.bottom))
+ && dragObject) {
const loc = originLoc.clone(e);
const indented = this.indentTrack.getIndentParent(originLoc, loc);
if (indented) {
@@ -138,7 +139,7 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
detail: {
type: IPublicTypeLocationDetailType.Children,
index,
- valid: document.checkNesting(parent, e.dragObject as any),
+ valid: document?.checkNesting(parent, e.dragObject as any),
},
});
}
@@ -177,7 +178,7 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
}
}
if (p !== node) {
- node = p || document.focusNode;
+ node = p || document?.focusNode;
treeNode = tree.getTreeNode(node);
focusSlots = false;
}
@@ -258,7 +259,7 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
cancelIdleCallback(this.tryScrollAgain);
this.tryScrollAgain = null;
}
- if (this.sensing || !this.bounds || !this.scroller || !this.scrollTarget) {
+ if (!this.bounds || !this.scroller || !this.scrollTarget) {
// is a active sensor
return;
}
@@ -305,7 +306,7 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
focus = { type: 'slots' };
} else {
index = 0;
- valid = document.checkNesting(target, event.dragObject as any);
+ valid = !!document?.checkNesting(target, event.dragObject as any);
}
canvas.createLocation({
target,
@@ -320,23 +321,28 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
});
});
- private getNear(treeNode: TreeNode, e: IPublicModelLocateEvent, index?: number, rect?: DOMRect) {
+ private getNear(treeNode: TreeNode, e: IPublicModelLocateEvent, originalIndex?: number, originalRect?: DOMRect) {
const { canvas, project } = this.pluginContext;
const document = project.getCurrentDocument();
const { globalY, dragObject } = e;
+ if (!dragObject) {
+ return null;
+ }
// TODO: check dragObject is anyData
const { node, expanded } = treeNode;
+ let rect = originalRect;
if (!rect) {
rect = this.getTreeNodeRect(treeNode);
if (!rect) {
return null;
}
}
+ let index = originalIndex;
if (index == null) {
index = node.index;
}
- if (node.isSlot) {
+ if (node.isSlotNode) {
// 是个插槽根节点
if (!treeNode.isContainer() && !treeNode.hasSlots()) {
return canvas.createLocation({
@@ -385,7 +391,7 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
detail: {
type: IPublicTypeLocationDetailType.Children,
index,
- valid: document.checkNesting(node.parent!, dragObject as any),
+ valid: document?.checkNesting(node.parent!, dragObject as any),
near: { node, pos: 'before' },
focus: checkRecursion(focusNode, dragObject) ? { type: 'node', node: focusNode } : undefined,
},
@@ -412,7 +418,7 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
detail: {
type: IPublicTypeLocationDetailType.Children,
index: index + 1,
- valid: document.checkNesting(node.parent!, dragObject as any),
+ valid: document?.checkNesting(node.parent!, dragObject as any),
near: { node, pos: 'after' },
focus: checkRecursion(focusNode, dragObject) ? { type: 'node', node: focusNode } : undefined,
},
@@ -423,6 +429,9 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
const { canvas, project } = this.pluginContext;
const document = project.getCurrentDocument();
const { dragObject, globalY } = e;
+ if (!dragObject) {
+ return null;
+ }
if (!checkRecursion(treeNode.node, dragObject)) {
return null;
@@ -454,7 +463,7 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
detail.valid = false;
} else {
detail.index = 0;
- detail.valid = document.checkNesting(container, dragObject);
+ detail.valid = document?.checkNesting(container, dragObject);
}
}
@@ -526,7 +535,7 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
} else {
detail.index = l;
}
- detail.valid = document.checkNesting(container, dragObject);
+ detail.valid = document?.checkNesting(container, dragObject);
}
return canvas.createLocation(locationData);
@@ -572,9 +581,26 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
return;
}
this._shell = shell;
+ const { canvas, project } = this.pluginContext;
if (shell) {
- this._scrollTarget = this.pluginContext.canvas.createScrollTarget(shell);
+ this._scrollTarget = canvas.createScrollTarget(shell);
this._sensorAvailable = true;
+
+ // check if there is current selection and scroll to it
+ const selection = project.currentDocument?.selection;
+ const topNodes = selection?.getTopNodes(true);
+ const tree = this.treeMaster?.currentTree;
+ if (topNodes && topNodes[0] && tree) {
+ const treeNode = tree.getTreeNodeById(topNodes[0].id);
+ if (treeNode) {
+ // at this moment, it is possible that pane is not ready yet, so
+ // put ui related operations to the next loop
+ setTimeout(() => {
+ tree.setNodeSelected(treeNode.id);
+ this.scrollToNode(treeNode, null, 4);
+ }, 0);
+ }
+ }
} else {
this._scrollTarget = undefined;
this._sensorAvailable = false;
@@ -610,7 +636,7 @@ export class PaneController implements ISensor, ITreeBoard, IPublicModelScrollab
}
}
-function checkRecursion(parent: IPublicModelNode | undefined | null, dragObject: DragObject): boolean {
+function checkRecursion(parent: IPublicModelNode | undefined | null, dragObject: IPublicModelDragObject): boolean {
if (!parent) {
return false;
}
@@ -633,14 +659,14 @@ function getPosFromEvent(
if (target.matches('.insertion')) {
return 'unchanged';
}
- target = target.closest('[data-id]');
- if (!target || !stop.contains(target)) {
+ const closest = target.closest('[data-id]');
+ if (!closest || !stop.contains(closest)) {
return null;
}
- const nodeId = (target as HTMLDivElement).dataset.id!;
+ const nodeId = (closest as HTMLDivElement).dataset.id!;
return {
- focusSlots: target.matches('.tree-node-slots'),
+ focusSlots: closest.matches('.tree-node-slots'),
nodeId,
};
}
diff --git a/packages/plugin-outline-pane/src/controllers/ric-shim.d.ts b/packages/plugin-outline-pane/src/controllers/ric-shim.d.ts
new file mode 100644
index 000000000..74f3fbd94
--- /dev/null
+++ b/packages/plugin-outline-pane/src/controllers/ric-shim.d.ts
@@ -0,0 +1 @@
+declare module 'ric-shim';
\ No newline at end of file
diff --git a/packages/plugin-outline-pane/src/controllers/tree-master.ts b/packages/plugin-outline-pane/src/controllers/tree-master.ts
index c660f0457..38b723a98 100644
--- a/packages/plugin-outline-pane/src/controllers/tree-master.ts
+++ b/packages/plugin-outline-pane/src/controllers/tree-master.ts
@@ -1,5 +1,5 @@
import { isLocationChildrenDetail } from '@alilc/lowcode-utils';
-import { IPublicModelPluginContext, IPublicTypeActiveTarget, IPublicModelNode, IPublicEnumEventNames } from '@alilc/lowcode-types';
+import { IPublicModelPluginContext, IPublicTypeActiveTarget, IPublicModelNode } from '@alilc/lowcode-types';
import TreeNode from './tree-node';
import { Tree } from './tree';
@@ -54,8 +54,8 @@ export class TreeMaster {
time: (endTime - startTime).toFixed(2),
});
});
- event.on(IPublicEnumEventNames.DESIGNER_DOCUMENT_REMOVE, (doc) => {
- const { id } = doc as any;
+ project.onRemoveDocument((data: {id: string}) => {
+ const { id } = data;
this.treeMap.delete(id);
});
}
diff --git a/packages/plugin-outline-pane/src/controllers/tree-node.ts b/packages/plugin-outline-pane/src/controllers/tree-node.ts
index daac5bc2c..b6063e724 100644
--- a/packages/plugin-outline-pane/src/controllers/tree-node.ts
+++ b/packages/plugin-outline-pane/src/controllers/tree-node.ts
@@ -24,6 +24,10 @@ export interface FilterResult {
export default class TreeNode {
readonly pluginContext: IPublicModelPluginContext;
onFilterResultChanged: () => void;
+ onExpandedChanged: (expanded: boolean) => void;
+ onHiddenChanged: (hidden: boolean) => void;
+ onLockedChanged: (locked: boolean) => void;
+ onTitleLabelChanged: (treeNode: TreeNode) => void;
get id(): string {
return this.node.id;
@@ -87,7 +91,7 @@ export default class TreeNode {
setExpanded(value: boolean) {
this._expanded = value;
- this.pluginContext.pluginEvent.emit('tree-node.expandedChanged', { expanded: value, nodeId: this.id });
+ this.onExpandedChanged && this.onExpandedChanged(value);
}
get detecting() {
@@ -108,7 +112,7 @@ export default class TreeNode {
return;
}
this.node.setVisible(!flag);
- this.pluginContext.pluginEvent.emit('tree-node.hiddenChanged', { hidden: flag, nodeId: this.id });
+ this.onHiddenChanged && this.onHiddenChanged(flag);
}
get locked(): boolean {
@@ -117,7 +121,7 @@ export default class TreeNode {
setLocked(flag: boolean) {
this.node.lock(flag);
- this.pluginContext.pluginEvent.emit('tree-node.lockedChanged', { locked: flag, nodeId: this.id });
+ this.onLockedChanged && this.onLockedChanged(flag);
}
get selected(): boolean {
@@ -162,7 +166,7 @@ export default class TreeNode {
} else {
this.node.getExtraProp('title', true)?.setValue(label);
}
- this.pluginContext.pluginEvent.emit('tree-node.titleLabelChanged', { titleLabel: label, nodeId: this.id });
+ this.onTitleLabelChanged && this.onTitleLabelChanged(this);
}
get icon() {
diff --git a/packages/plugin-outline-pane/src/controllers/tree.ts b/packages/plugin-outline-pane/src/controllers/tree.ts
index b99e04f64..a4106088b 100644
--- a/packages/plugin-outline-pane/src/controllers/tree.ts
+++ b/packages/plugin-outline-pane/src/controllers/tree.ts
@@ -20,6 +20,15 @@ export class Tree {
this.id = this.pluginContext.project.currentDocument?.id;
}
+ setNodeSelected(nodeId: string): void {
+ // 目标节点选中,其他节点展开
+ const treeNode = this.treeNodesMap.get(nodeId);
+ if (!treeNode) {
+ return;
+ }
+ this.expandAllAncestors(treeNode);
+ }
+
getTreeNode(node: IPublicModelNode): TreeNode {
if (this.treeNodesMap.has(node.id)) {
const tnode = this.treeNodesMap.get(node.id)!;
@@ -36,7 +45,29 @@ export class Tree {
return this.treeNodesMap.get(id);
}
- expandAllDecendants(treeNode: TreeNode | undefined) {
+ expandAllAncestors(treeNode: TreeNode | undefined | null) {
+ if (!treeNode) {
+ return;
+ }
+ if (treeNode.isRoot()) {
+ return;
+ }
+ const ancestors = [];
+ let currentNode: TreeNode | null | undefined = treeNode;
+ while (!treeNode.isRoot()) {
+ currentNode = currentNode?.parent;
+ if (currentNode) {
+ ancestors.unshift(currentNode);
+ } else {
+ break;
+ }
+ }
+ ancestors.forEach((ancestor) => {
+ ancestor.setExpanded(true);
+ });
+ }
+
+ expandAllDecendants(treeNode: TreeNode | undefined | null) {
if (!treeNode) {
return;
}
@@ -49,7 +80,7 @@ export class Tree {
}
}
- collapseAllDecendants(treeNode: TreeNode | undefined) {
+ collapseAllDecendants(treeNode: TreeNode | undefined | null): void {
if (!treeNode) {
return;
}
diff --git a/packages/plugin-outline-pane/src/helper/tree-title-extra.ts b/packages/plugin-outline-pane/src/helper/tree-title-extra.ts
deleted file mode 100644
index b1bcbf6ed..000000000
--- a/packages/plugin-outline-pane/src/helper/tree-title-extra.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { globalContext } from '@alilc/lowcode-editor-core';
-import { ReactElement } from 'react';
-
-const TREE_TITLE_EXTRA_KEY = 'TREE_TITLE_EXTRA_KEY';
-
-export const registerTreeTitleExtra = (extra: ReactElement) => {
- if (extra && !globalContext.has(TREE_TITLE_EXTRA_KEY)) {
- globalContext.register(extra, TREE_TITLE_EXTRA_KEY);
- }
-};
-
-export const getTreeTitleExtra = () => {
- try {
- return globalContext.get(TREE_TITLE_EXTRA_KEY);
- } catch (e) {
- // console.error('getTreeTitleExtra Error', e);
- }
-
- return null;
-};
diff --git a/packages/plugin-outline-pane/src/index.tsx b/packages/plugin-outline-pane/src/index.tsx
index 0a6ef527c..bf3c95b1a 100644
--- a/packages/plugin-outline-pane/src/index.tsx
+++ b/packages/plugin-outline-pane/src/index.tsx
@@ -1,11 +1,13 @@
import { Pane } from './views/pane';
import { IconOutline } from './icons/outline';
-import { IPublicModelPluginContext, IPublicEnumEventNames } from '@alilc/lowcode-types';
+import { IPublicModelPluginContext, IPublicModelDocumentModel } from '@alilc/lowcode-types';
import { enUS, zhCN } from './locale';
import { MasterPaneName, BackupPaneName } from './helper/consts';
+import { getTreeMaster } from './controllers/tree-master';
+import { PaneController } from './controllers/pane-controller';
export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => {
- const { skeleton, config, common, event, canvas } = ctx;
+ const { skeleton, config, common, event, canvas, project } = ctx;
const { intl, intlNode, getLocale } = common.utils.createIntl({
'en-US': enUS,
'zh-CN': zhCN,
@@ -24,7 +26,9 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => {
masterPane: false,
backupPane: false,
};
-
+ const treeMaster = getTreeMaster(ctx);
+ let masterPaneController: PaneController | null = null;
+ let backupPaneController: PaneController | null = null;
return {
async init() {
skeleton.add({
@@ -39,10 +43,13 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => {
description: intlNode('Outline Tree'),
},
content: (props: any) => {
+ masterPaneController = new PaneController(MasterPaneName, ctx, treeMaster);
return (
);
@@ -65,12 +72,17 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => {
props: {
hiddenWhenInit: true,
},
- content: (props: any) => (
-
- ),
+ content: (props: any) => {
+ backupPaneController = new PaneController(BackupPaneName, ctx, treeMaster);
+ return (
+
+ );
+ },
});
// 处理 master pane 和 backup pane 切换
@@ -91,8 +103,7 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => {
canvas.dragon?.onDragend(() => {
switchPanes();
});
-
- event.on(IPublicEnumEventNames.SKELETON_PANEL_SHOW, (key: string) => {
+ skeleton.onShowPanel((key: string) => {
if (key === MasterPaneName) {
showingPanes.masterPane = true;
}
@@ -100,7 +111,7 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => {
showingPanes.backupPane = true;
}
});
- event.on(IPublicEnumEventNames.SKELETON_PANEL_HIDE, (key: string) => {
+ skeleton.onHidePanel((key: string) => {
if (key === MasterPaneName) {
showingPanes.masterPane = false;
switchPanes();
@@ -109,6 +120,25 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => {
showingPanes.backupPane = false;
}
});
+ project.onChangeDocument((document: IPublicModelDocumentModel) => {
+ if (!document) {
+ return;
+ }
+
+ const { selection } = document;
+
+ selection?.onSelectionChange(() => {
+ const selectedNodes = selection?.getNodes();
+ if (!selectedNodes || selectedNodes.length === 0) {
+ return;
+ }
+ const tree = treeMaster.currentTree;
+ selectedNodes.forEach((node) => {
+ const treeNode = tree?.getTreeNodeById(node.id);
+ tree?.expandAllAncestors(treeNode);
+ });
+ });
+ });
},
};
};
diff --git a/packages/plugin-outline-pane/src/views/pane.tsx b/packages/plugin-outline-pane/src/views/pane.tsx
index 6d037eb5b..1ed4c74ba 100644
--- a/packages/plugin-outline-pane/src/views/pane.tsx
+++ b/packages/plugin-outline-pane/src/views/pane.tsx
@@ -4,35 +4,29 @@ import TreeView from './tree';
import './style.less';
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
import Filter from './filter';
-import { registerTreeTitleExtra } from '../helper/tree-title-extra';
-import { getTreeMaster, TreeMaster } from '../controllers/tree-master';
+import { TreeMaster } from '../controllers/tree-master';
export class Pane extends Component<{
config: any;
pluginContext: IPublicModelPluginContext;
+ treeMaster: TreeMaster;
+ controller: PaneController;
}> {
private controller;
private treeMaster: TreeMaster;
constructor(props: any) {
super(props);
- this.treeMaster = getTreeMaster(this.props.pluginContext);
- this.controller = new PaneController(
- this.props.config.name || this.props.config.pluginKey,
- this.props.pluginContext,
- this.treeMaster,
- );
+ const { controller, treeMaster } = props;
+ this.treeMaster = treeMaster;
+ this.controller = controller;
}
componentWillUnmount() {
this.controller.purge();
}
- componentDidMount() {
- registerTreeTitleExtra(this.props?.config?.contentProps?.treeTitleExtra);
- }
-
render() {
const tree = this.treeMaster.currentTree;
diff --git a/packages/plugin-outline-pane/src/views/root-tree-node.tsx b/packages/plugin-outline-pane/src/views/root-tree-node.tsx
deleted file mode 100644
index f82783835..000000000
--- a/packages/plugin-outline-pane/src/views/root-tree-node.tsx
+++ /dev/null
@@ -1,179 +0,0 @@
-import { Component } from 'react';
-import classNames from 'classnames';
-import TreeNode from '../controllers/tree-node';
-import TreeTitle from './tree-title';
-import TreeBranches from './tree-branches';
-import { IconEyeClose } from '../icons/eye-close';
-import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicEnumEventNames } from '@alilc/lowcode-types';
-
-class ModalTreeNodeView extends Component<{
- treeNode: TreeNode;
- pluginContext: IPublicModelPluginContext;
-}> {
- private modalNodesManager: IPublicModelModalNodesManager | undefined | null;
- readonly pluginContext: IPublicModelPluginContext;
-
- constructor(props: any) {
- super(props);
-
- // 模态管理对象
- this.pluginContext = props.pluginContext;
- const { project } = this.pluginContext;
- this.modalNodesManager = project.currentDocument?.modalNodesManager;
- }
-
- hideAllNodes() {
- this.modalNodesManager?.hideModalNodes();
- }
-
- render() {
- const { treeNode } = this.props;
- // 当指定了新的根节点时,要从原始的根节点去获取模态节点
- const { project } = this.pluginContext;
- const rootNode = project.currentDocument?.root;
- const rootTreeNode = treeNode.tree.getTreeNode(rootNode!);
- const modalNodes = rootTreeNode.children?.filter((item) => {
- return item.node.componentMeta?.isModal;
- });
- if (!modalNodes || modalNodes.length === 0) {
- return null;
- }
-
- const hasVisibleModalNode = !!this.modalNodesManager?.getVisibleModalNode();
- return (
-
-
-
模态视图层
-
- {hasVisibleModalNode ? : null}
-
-
-
-
-
-
- );
- }
-}
-
-export default class RootTreeNodeView extends Component<{
- treeNode: TreeNode;
- pluginContext: IPublicModelPluginContext;
-}> {
- state = {
- expanded: false,
- selected: false,
- hidden: false,
- locked: false,
- detecting: false,
- isRoot: false,
- highlight: false,
- dropping: false,
- conditionFlow: false,
- };
-
- eventOffCallbacks: Array<() => void> = [];
-
- componentDidMount() {
- const { treeNode, pluginContext } = this.props;
- const { pluginEvent, event } = pluginContext;
- const { id } = treeNode;
-
- this.state = {
- expanded: false,
- selected: false,
- hidden: false,
- locked: false,
- detecting: false,
- isRoot: treeNode.isRoot(),
- // 是否投放响应
- dropping: treeNode.dropDetail?.index != null,
- conditionFlow: treeNode.node.conditionGroup != null,
- highlight: treeNode.isFocusingNode(),
- };
-
- const doc = pluginContext.project.currentDocument;
-
- this.eventOffCallbacks.push(pluginEvent.on('tree-node.hiddenChanged', (payload: any) => {
- const { hidden, nodeId } = payload;
- if (nodeId === id) {
- this.setState({ hidden });
- }
- }));
-
- this.eventOffCallbacks.push(pluginEvent.on('tree-node.expandedChanged', (payload: any) => {
- const { expanded, nodeId } = payload;
- if (nodeId === id) {
- this.setState({ expanded });
- }
- }));
-
- this.eventOffCallbacks.push(pluginEvent.on('tree-node.lockedChanged', (payload: any) => {
- const { locked, nodeId } = payload;
- if (nodeId === id) {
- this.setState({ locked });
- }
- }));
-
- this.eventOffCallbacks.push(
- event.on(
- IPublicEnumEventNames.DOCUMENT_DROPLOCATION_CHANGED,
- (payload: any) => {
- const { document } = payload;
- if (document.id === doc?.id) {
- this.setState({
- dropping: treeNode.dropDetail?.index != null,
- });
- }
- },
- ),
- );
-
- const offSelectionChange = doc?.selection?.onSelectionChange(() => {
- this.setState({ selected: treeNode.selected });
- });
- this.eventOffCallbacks.push(offSelectionChange!);
- const offDetectingChange = doc?.detecting?.onDetectingChange(() => {
- this.setState({ detecting: treeNode.detecting });
- });
- this.eventOffCallbacks.push(offDetectingChange!);
- }
-
- componentWillUnmount(): void {
- this.eventOffCallbacks?.forEach((offFun: () => void) => {
- offFun();
- });
- }
-
- render() {
- const { treeNode } = this.props;
- const className = classNames('tree-node', {
- // 是否展开
- expanded: this.state.expanded,
- // 是否选中的
- selected: this.state.selected,
- // 是否隐藏的
- hidden: this.state.hidden,
- // 是否锁定的
- locked: this.state.locked,
- // 是否悬停中
- detecting: this.state.detecting,
- // 是否投放响应
- dropping: this.state.dropping,
- 'is-root': this.state.isRoot,
- 'condition-flow': this.state.conditionFlow,
- highlight: this.state.highlight,
- });
-
- return (
-
-
-
-
-
- );
- }
-}
diff --git a/packages/plugin-outline-pane/src/views/tree-branches.tsx b/packages/plugin-outline-pane/src/views/tree-branches.tsx
index 5dfdafb72..9af2dbd09 100644
--- a/packages/plugin-outline-pane/src/views/tree-branches.tsx
+++ b/packages/plugin-outline-pane/src/views/tree-branches.tsx
@@ -2,38 +2,33 @@ import { Component } from 'react';
import classNames from 'classnames';
import TreeNode from '../controllers/tree-node';
import TreeNodeView from './tree-node';
-import { IPublicModelPluginContext, IPublicModelExclusiveGroup, IPublicEnumEventNames, IPublicTypeLocationDetailType } from '@alilc/lowcode-types';
+import { IPublicModelPluginContext, IPublicModelExclusiveGroup } from '@alilc/lowcode-types';
export default class TreeBranches extends Component<{
treeNode: TreeNode;
isModal?: boolean;
pluginContext: IPublicModelPluginContext;
+ expanded: boolean;
}> {
state = {
- expanded: false,
filterWorking: false,
matchChild: false,
};
private offExpandedChanged: (() => void) | null;
- componentDidMount() {
- const { treeNode, pluginContext } = this.props;
- const { expanded } = treeNode;
- const { pluginEvent } = pluginContext;
+ constructor(props: any) {
+ super(props);
+ const { treeNode } = this.props;
const { filterWorking, matchChild } = treeNode.filterReult;
- this.setState({ expanded, filterWorking, matchChild });
+ this.setState({ filterWorking, matchChild });
+ }
+
+ componentDidMount() {
+ const { treeNode } = this.props;
treeNode.onFilterResultChanged = () => {
const { filterWorking: newFilterWorking, matchChild: newMatchChild } = treeNode.filterReult;
this.setState({ filterWorking: newFilterWorking, matchChild: newMatchChild });
};
-
- this.offExpandedChanged = pluginEvent.on('tree-node.expandedChanged', (payload: any) => {
- const { expanded: value, nodeId } = payload;
- const { id } = this.props.treeNode;
- if (nodeId === id) {
- this.setState({ expanded: value });
- }
- });
}
componentWillUnmount(): void {
@@ -43,8 +38,8 @@ export default class TreeBranches extends Component<{
}
render() {
- const { treeNode, isModal } = this.props;
- const { filterWorking, matchChild, expanded } = this.state;
+ const { treeNode, isModal, expanded } = this.props;
+ const { filterWorking, matchChild } = this.state;
// 条件过滤生效时,如果命中了子节点,需要将该节点展开
const expandInFilterResult = filterWorking && matchChild;
@@ -57,7 +52,11 @@ export default class TreeBranches extends Component<{
{
!isModal &&
}
-
+
);
}
@@ -77,7 +76,7 @@ class TreeNodeChildren extends Component<{
offLocationChanged: () => void;
componentDidMount() {
const { treeNode, pluginContext } = this.props;
- const { event } = pluginContext;
+ const { project } = pluginContext;
const { filterWorking, matchSelf, keywords } = treeNode.filterReult;
const { dropDetail } = treeNode;
this.setState({
@@ -98,11 +97,10 @@ class TreeNodeChildren extends Component<{
keywords: newKeywords,
});
};
- this.offLocationChanged = event.on(
- IPublicEnumEventNames.DOCUMENT_DROPLOCATION_CHANGED,
- (payload: any) => {
- this.setState({ dropDetail: treeNode.dropDetail });
- },
+ this.offLocationChanged = project.currentDocument?.onDropLocationChanged(
+ () => {
+ this.setState({ dropDetail: treeNode.dropDetail });
+ },
);
}
componentWillUnmount(): void {
diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx
index 72b68aef3..091530706 100644
--- a/packages/plugin-outline-pane/src/views/tree-node.tsx
+++ b/packages/plugin-outline-pane/src/views/tree-node.tsx
@@ -3,12 +3,67 @@ import classNames from 'classnames';
import TreeNode from '../controllers/tree-node';
import TreeTitle from './tree-title';
import TreeBranches from './tree-branches';
-import { IPublicModelPluginContext, IPublicEnumEventNames } from '@alilc/lowcode-types';
+import { IconEyeClose } from '../icons/eye-close';
+import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicModelDocumentModel } from '@alilc/lowcode-types';
+
+class ModalTreeNodeView extends Component<{
+ treeNode: TreeNode;
+ pluginContext: IPublicModelPluginContext;
+}> {
+ private modalNodesManager: IPublicModelModalNodesManager | undefined | null;
+ readonly pluginContext: IPublicModelPluginContext;
+
+ constructor(props: any) {
+ super(props);
+
+ // 模态管理对象
+ this.pluginContext = props.pluginContext;
+ const { project } = this.pluginContext;
+ this.modalNodesManager = project.currentDocument?.modalNodesManager;
+ }
+
+ hideAllNodes() {
+ this.modalNodesManager?.hideModalNodes();
+ }
+
+ render() {
+ const { treeNode } = this.props;
+ // 当指定了新的根节点时,要从原始的根节点去获取模态节点
+ const { project } = this.pluginContext;
+ const rootNode = project.currentDocument?.root;
+ const rootTreeNode = treeNode.tree.getTreeNode(rootNode!);
+ const expanded = rootTreeNode.expanded;
+
+ const hasVisibleModalNode = !!this.modalNodesManager?.getVisibleModalNode();
+ return (
+
+
+
模态视图层
+
+ {hasVisibleModalNode ? : null}
+
+
+
+
+
+
+ );
+ }
+}
export default class TreeNodeView extends Component<{
treeNode: TreeNode;
isModal?: boolean;
pluginContext: IPublicModelPluginContext;
+ isRootNode: boolean;
}> {
state = {
expanded: false,
@@ -20,64 +75,51 @@ export default class TreeNodeView extends Component<{
highlight: false,
dropping: false,
conditionFlow: false,
+ expandable: false,
};
eventOffCallbacks: Array<() => void> = [];
+ constructor(props: any) {
+ super(props);
- componentDidMount() {
- const { treeNode, pluginContext } = this.props;
- const { pluginEvent, event } = pluginContext;
- const { id } = treeNode;
-
+ const { treeNode, isRootNode } = this.props;
this.state = {
- expanded: false,
- selected: false,
- hidden: false,
- locked: false,
- detecting: false,
+ expanded: isRootNode ? true : treeNode.expanded,
+ selected: treeNode.selected,
+ hidden: treeNode.hidden,
+ locked: treeNode.locked,
+ detecting: treeNode.detecting,
isRoot: treeNode.isRoot(),
// 是否投放响应
dropping: treeNode.dropDetail?.index != null,
conditionFlow: treeNode.node.conditionGroup != null,
highlight: treeNode.isFocusingNode(),
+ expandable: treeNode.expandable,
+ };
+ }
+
+ componentDidMount() {
+ const { treeNode, pluginContext } = this.props;
+ const { event, project } = pluginContext;
+
+ const doc = project.currentDocument;
+
+ treeNode.onExpandedChanged = ((expanded: boolean) => {
+ this.setState({ expanded });
+ });
+ treeNode.onHiddenChanged = (hidden: boolean) => {
+ this.setState({ hidden });
+ };
+ treeNode.onLockedChanged = (locked: boolean) => {
+ this.setState({ locked });
};
- const doc = pluginContext.project.currentDocument;
-
-
- this.eventOffCallbacks.push(pluginEvent.on('tree-node.hiddenChanged', (payload: any) => {
- const { hidden, nodeId } = payload;
- if (nodeId === id) {
- this.setState({ hidden });
- }
- }));
-
- this.eventOffCallbacks.push(pluginEvent.on('tree-node.expandedChanged', (payload: any) => {
- const { expanded, nodeId } = payload;
- if (nodeId === id) {
- this.setState({ expanded });
- }
- }));
-
- this.eventOffCallbacks.push(pluginEvent.on('tree-node.lockedChanged', (payload: any) => {
- const { locked, nodeId } = payload;
- if (nodeId === id) {
- this.setState({ locked });
- }
- }));
-
this.eventOffCallbacks.push(
- event.on(
- IPublicEnumEventNames.DOCUMENT_DROPLOCATION_CHANGED,
- (payload: any) => {
- const { document } = payload;
- if (document.id === doc?.id) {
- this.setState({
- dropping: treeNode.dropDetail?.index != null,
- });
- }
- },
- ),
+ doc?.onDropLocationChanged((document: IPublicModelDocumentModel) => {
+ this.setState({
+ dropping: treeNode.dropDetail?.index != null,
+ });
+ }),
);
const offSelectionChange = doc?.selection?.onSelectionChange(() => {
@@ -95,8 +137,25 @@ export default class TreeNodeView extends Component<{
});
}
+ shouldShowModalTreeNode(): boolean {
+ const { treeNode, isRootNode, pluginContext } = this.props;
+ if (!isRootNode) {
+ // 只在 当前树 的根节点展示模态节点
+ return false;
+ }
+
+ // 当指定了新的根节点时,要从原始的根节点去获取模态节点
+ const { project } = pluginContext;
+ const rootNode = project.currentDocument?.root;
+ const rootTreeNode = treeNode.tree.getTreeNode(rootNode!);
+ const modalNodes = rootTreeNode.children?.filter((item) => {
+ return item.node.componentMeta?.isModal;
+ });
+ return !!(modalNodes && modalNodes.length > 0);
+ }
+
render() {
- const { treeNode, isModal } = this.props;
+ const { treeNode, isModal, isRootNode } = this.props;
const className = classNames('tree-node', {
// 是否展开
expanded: this.state.expanded,
@@ -114,24 +173,39 @@ export default class TreeNodeView extends Component<{
'condition-flow': this.state.conditionFlow,
highlight: this.state.highlight,
});
+ let shouldShowModalTreeNode: boolean = this.shouldShowModalTreeNode();
+ // filter 处理
const { filterWorking, matchChild, matchSelf } = treeNode.filterReult;
-
- // 条件过滤生效时,如果未命中本节点或子节点,则不展示该节点
- if (filterWorking && !matchChild && !matchSelf) {
+ if (!isRootNode && filterWorking && !matchChild && !matchSelf) {
+ // 条件过滤生效时,如果未命中本节点或子节点,则不展示该节点
+ // 根节点始终展示
return null;
}
-
return (
-
+
+ {shouldShowModalTreeNode &&
+
+ }
diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx
index 93f822988..92fac1bba 100644
--- a/packages/plugin-outline-pane/src/views/tree-title.tsx
+++ b/packages/plugin-outline-pane/src/views/tree-title.tsx
@@ -21,6 +21,10 @@ function emitOutlineEvent(event: IPublicApiEvent, type: string, treeNode: TreeNo
export default class TreeTitle extends Component<{
treeNode: TreeNode;
isModal?: boolean;
+ expanded: boolean;
+ hidden: boolean;
+ locked: boolean;
+ expandable: boolean;
pluginContext: IPublicModelPluginContext;
}> {
state: {
@@ -73,30 +77,18 @@ export default class TreeTitle extends Component<{
// 光标定位最后一个
// input.selectionStart = input.selectionEnd;
};
- offTitleLabelChanged: (() => void) | undefined;
componentDidMount() {
- const { treeNode, pluginContext } = this.props;
- const { id } = treeNode;
- const { pluginEvent } = pluginContext;
+ const { treeNode } = this.props;
this.setState({
editing: false,
title: treeNode.titleLabel,
});
- this.offTitleLabelChanged = pluginEvent.on('tree-node.titleLabelChanged', (payload: any) => {
- const { nodeId } = payload;
- if (nodeId === id) {
- this.setState({
- title: treeNode.titleLabel,
- });
- }
- });
- }
-
- componentWillUnmount(): void {
- if (this.offTitleLabelChanged) {
- this.offTitleLabelChanged();
- }
+ treeNode.onTitleLabelChanged = () => {
+ this.setState({
+ title: treeNode.titleLabel,
+ });
+ };
}
render() {
@@ -158,7 +150,7 @@ export default class TreeTitle extends Component<{
)}
- {isCNode && }
+ {isCNode && }
{createIcon(treeNode.icon)}
{editing ? (
@@ -200,8 +192,8 @@ export default class TreeTitle extends Component<{
)}
- {shouldShowHideBtn && }
- {shouldShowLockBtn && }
+ {shouldShowHideBtn && }
+ {shouldShowLockBtn && }
{shouldEditBtn && }
@@ -233,39 +225,10 @@ class RenameBtn extends Component<{
class LockBtn extends Component<{
treeNode: TreeNode;
pluginContext: IPublicModelPluginContext;
-}, {
locked: boolean;
}> {
- state = {
- locked: false,
- };
- offLockedChanged: () => void;
-
- componentDidMount(): void {
- const { treeNode, pluginContext } = this.props;
- const { id } = treeNode;
- const { pluginEvent } = pluginContext;
-
- this.setState({
- locked: treeNode.locked,
- });
-
- this.offLockedChanged = pluginEvent.on('tree-node.lockedChanged', (payload: any) => {
- const { locked, nodeId } = payload;
- if (nodeId === id) {
- this.setState({ locked });
- }
- });
- }
-
- componentWillUnmount() {
- if (this.offLockedChanged) {
- this.offLockedChanged();
- }
- }
-
render() {
- const { treeNode } = this.props;
+ const { treeNode, locked } = this.props;
const { intl, common } = this.props.pluginContext;
const Tip = common.editorCabin.Tip;
return (
@@ -273,11 +236,11 @@ class LockBtn extends Component<{
className="tree-node-lock-btn"
onClick={(e) => {
e.stopPropagation();
- treeNode.setLocked(!this.state.locked);
+ treeNode.setLocked(!locked);
}}
>
- {this.state.locked ? : }
- {this.state.locked ? intl('Unlock') : intl('Lock')}
+ {locked ? : }
+ {locked ? intl('Unlock') : intl('Lock')}
);
}
@@ -285,35 +248,13 @@ class LockBtn extends Component<{
class HideBtn extends Component<{
treeNode: TreeNode;
+ hidden: boolean;
pluginContext: IPublicModelPluginContext;
}, {
hidden: boolean;
}> {
- state = {
- hidden: false,
- };
- offHiddenChanged: () => void;
- componentDidMount(): void {
- const { treeNode, pluginContext } = this.props;
- const { pluginEvent } = pluginContext;
- const { id } = treeNode;
- this.setState({
- hidden: treeNode.hidden,
- });
- this.offHiddenChanged = pluginEvent.on('tree-node.hiddenChanged', (payload: any) => {
- const { hidden, nodeId } = payload;
- if (nodeId === id) {
- this.setState({ hidden });
- }
- });
- }
- componentWillUnmount(): void {
- if (this.offHiddenChanged) {
- this.offHiddenChanged();
- }
- }
render() {
- const { treeNode } = this.props;
+ const { treeNode, hidden } = this.props;
const { intl, common } = this.props.pluginContext;
const Tip = common.editorCabin.Tip;
return (
@@ -321,12 +262,12 @@ class HideBtn extends Component<{
className="tree-node-hide-btn"
onClick={(e) => {
e.stopPropagation();
- emitOutlineEvent(this.props.pluginContext.event, this.state.hidden ? 'show' : 'hide', treeNode);
- treeNode.setHidden(!this.state.hidden);
+ emitOutlineEvent(this.props.pluginContext.event, hidden ? 'show' : 'hide', treeNode);
+ treeNode.setHidden(!hidden);
}}
>
- {this.state.hidden ? : }
- {this.state.hidden ? intl('Show') : intl('Hide')}
+ {hidden ? : }
+ {hidden ? intl('Show') : intl('Hide')}
);
}
@@ -336,52 +277,24 @@ class HideBtn extends Component<{
class ExpandBtn extends Component<{
treeNode: TreeNode;
pluginContext: IPublicModelPluginContext;
-}, {
expanded: boolean;
expandable: boolean;
}> {
- state = {
- expanded: false,
- expandable: false,
- };
-
- offExpandedChanged: () => void;
-
- componentDidMount(): void {
- const { treeNode, pluginContext } = this.props;
- const { id } = treeNode;
- const { pluginEvent } = pluginContext;
- this.setState({
- expanded: treeNode.expanded,
- expandable: treeNode.expandable,
- });
- this.offExpandedChanged = pluginEvent.on('tree-node.expandedChanged', (payload: any) => {
- const { expanded, nodeId } = payload;
- if (nodeId === id) {
- this.setState({ expanded });
- }
- });
- }
- componentWillUnmount(): void {
- if (this.offExpandedChanged) {
- this.offExpandedChanged();
- }
- }
render() {
- const { treeNode } = this.props;
- if (!this.state.expandable) {
+ const { treeNode, expanded, expandable } = this.props;
+ if (!expandable) {
return ;
}
return (
{
- if (this.state.expanded) {
+ if (expanded) {
e.stopPropagation();
}
- emitOutlineEvent(this.props.pluginContext.event, this.state.expanded ? 'collapse' : 'expand', treeNode);
- treeNode.setExpanded(!this.state.expanded);
+ emitOutlineEvent(this.props.pluginContext.event, expanded ? 'collapse' : 'expand', treeNode);
+ treeNode.setExpanded(!expanded);
}}
>
diff --git a/packages/plugin-outline-pane/src/views/tree.tsx b/packages/plugin-outline-pane/src/views/tree.tsx
index bc4704b43..4eb1dbfee 100644
--- a/packages/plugin-outline-pane/src/views/tree.tsx
+++ b/packages/plugin-outline-pane/src/views/tree.tsx
@@ -1,8 +1,8 @@
import { Component, MouseEvent as ReactMouseEvent } from 'react';
import { isFormEvent, canClickNode, isShaken } from '@alilc/lowcode-utils';
import { Tree } from '../controllers/tree';
-import RootTreeNodeView from './root-tree-node';
-import { IPublicEnumDragObjectType, IPublicModelPluginContext, IPublicModelNode, IPublicEnumEventNames } from '@alilc/lowcode-types';
+import TreeNodeView from './tree-node';
+import { IPublicEnumDragObjectType, IPublicModelPluginContext, IPublicModelNode } from '@alilc/lowcode-types';
function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string {
let target: Element | null = e.target as Element;
@@ -81,6 +81,9 @@ export default class TreeView extends Component<{
private onDoubleClick = (e: ReactMouseEvent) => {
e.preventDefault();
const treeNode = this.getTreeNodeFromEvent(e);
+ if (treeNode?.id === this.state.root?.id) {
+ return;
+ }
if (!treeNode?.expanded) {
this.props.tree.expandAllDecendants(treeNode);
} else {
@@ -173,17 +176,13 @@ export default class TreeView extends Component<{
componentDidMount() {
const { tree, pluginContext } = this.props;
const { root } = tree;
- const { event, project } = pluginContext;
+ const { project } = pluginContext;
this.setState({ root });
const doc = project.currentDocument;
- // root 变化
- event.on(IPublicEnumEventNames.DOCUMENT_FOCUS_NODE_CHANGED, (payload: any) => {
- const { document } = payload;
- if (document.id === doc?.id) {
- this.setState({
- root: tree.root,
- });
- }
+ doc?.onFocusNodeChanged(() => {
+ this.setState({
+ root: tree.root,
+ });
});
}
@@ -201,7 +200,12 @@ export default class TreeView extends Component<{
onDoubleClick={this.onDoubleClick}
onMouseLeave={this.onMouseLeave}
>
-
+
);
}
diff --git a/packages/shell/src/api/canvas.ts b/packages/shell/src/api/canvas.ts
index eb3b7e4cf..6c7040311 100644
--- a/packages/shell/src/api/canvas.ts
+++ b/packages/shell/src/api/canvas.ts
@@ -13,9 +13,11 @@ import {
import {
ScrollTarget as InnerScrollTarget,
} from '@alilc/lowcode-designer';
-import { editorSymbol, designerSymbol } from '../symbols';
+import { editorSymbol, designerSymbol, nodeSymbol } from '../symbols';
import { Dragon } from '../model';
import { DropLocation } from '../model/drop-location';
+import { ActiveTracker } from '../model/active-tracker';
+
export class Canvas implements IPublicApiCanvas {
private readonly [editorSymbol]: IPublicModelEditor;
@@ -40,7 +42,10 @@ export class Canvas implements IPublicApiCanvas {
* 创建插入位置,考虑放到 dragon 中
*/
createLocation(locationData: IPublicTypeLocationData): IPublicModelDropLocation {
- return this[designerSymbol].createLocation(locationData);
+ return this[designerSymbol].createLocation({
+ ...locationData,
+ target: (locationData.target as any)[nodeSymbol],
+ });
}
get dragon(): IPublicModelDragon | null {
@@ -48,8 +53,10 @@ export class Canvas implements IPublicApiCanvas {
}
get activeTracker(): IPublicModelActiveTracker | null {
- return this[designerSymbol].activeTracker;
+ const activeTracker = new ActiveTracker(this[designerSymbol].activeTracker);
+ return activeTracker;
}
+
/**
* @deprecated
*/
diff --git a/packages/shell/src/api/event.ts b/packages/shell/src/api/event.ts
index 9b7f765ab..1f82d5f87 100644
--- a/packages/shell/src/api/event.ts
+++ b/packages/shell/src/api/event.ts
@@ -1,5 +1,5 @@
import { Editor as InnerEditor, EventBus } from '@alilc/lowcode-editor-core';
-import { getLogger, isPublicEventName, isPluginEventName } from '@alilc/lowcode-utils';
+import { getLogger, isPluginEventName } from '@alilc/lowcode-utils';
import { IPublicApiEvent, IPublicTypeDisposable } from '@alilc/lowcode-types';
const logger = getLogger({ level: 'warn', bizName: 'shell-event' });
@@ -34,10 +34,10 @@ export class Event implements IPublicApiEvent {
* @param listener 事件回调
*/
on(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable {
- if (isPluginEventName(event) || isPublicEventName(event)) {
+ if (isPluginEventName(event)) {
return this[eventBusSymbol].on(event, listener);
} else {
- logger.warn(`fail to monitor on event ${event}, which is neither a engine public event nor a plugin event`);
+ logger.warn(`fail to monitor on event ${event}, event should have a prefix like 'somePrefix:eventName'`);
return () => {};
}
}
diff --git a/packages/shell/src/api/project.ts b/packages/shell/src/api/project.ts
index 31c3277d4..9cae7d72e 100644
--- a/packages/shell/src/api/project.ts
+++ b/packages/shell/src/api/project.ts
@@ -11,7 +11,6 @@ import {
IPublicApiSimulatorHost,
IPublicModelDocumentModel,
IPublicTypePropsTransducer,
- IPublicEnumEventNames,
IPublicEnumTransformStage,
IPublicTypeDisposable,
} from '@alilc/lowcode-types';
@@ -166,7 +165,7 @@ export class Project implements IPublicApiProject {
*/
onRemoveDocument(fn: (data: { id: string}) => void): IPublicTypeDisposable {
return this[editorSymbol].eventBus.on(
- IPublicEnumEventNames.DESIGNER_DOCUMENT_REMOVE,
+ 'designer.document.remove',
(data: { id: string }) => fn(data),
);
}
diff --git a/packages/shell/src/model/active-tracker.ts b/packages/shell/src/model/active-tracker.ts
new file mode 100644
index 000000000..0c9c42efe
--- /dev/null
+++ b/packages/shell/src/model/active-tracker.ts
@@ -0,0 +1,36 @@
+import { IPublicModelActiveTracker, IPublicModelNode, IPublicTypeActiveTarget } from '@alilc/lowcode-types';
+import { IActiveTracker } from '@alilc/lowcode-designer';
+import { Node } from './node';
+import { nodeSymbol } from '../symbols';
+
+const activeTrackerSymbol = Symbol('activeTracker');
+
+
+export class ActiveTracker implements IPublicModelActiveTracker {
+ private readonly [activeTrackerSymbol]: IActiveTracker;
+
+
+ constructor(innerTracker: IActiveTracker) {
+ this[activeTrackerSymbol] = innerTracker;
+ }
+
+ onChange(fn: (target: IPublicTypeActiveTarget) => void): () => void {
+ if (!fn) {
+ return () => {};
+ }
+ return this[activeTrackerSymbol].onChange((t: IPublicTypeActiveTarget) => {
+ const { node: innerNode, detail, instance } = t;
+ const publicNode = Node.create(innerNode);
+ const publicActiveTarget = {
+ node: publicNode!,
+ detail,
+ instance,
+ };
+ fn(publicActiveTarget);
+ });
+ }
+
+ track(node: IPublicModelNode) {
+ this[activeTrackerSymbol].track((node as any)[nodeSymbol]);
+ }
+}
\ No newline at end of file
diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts
index c48d4c6ac..1d31d8132 100644
--- a/packages/shell/src/model/document-model.ts
+++ b/packages/shell/src/model/document-model.ts
@@ -22,8 +22,8 @@ import {
IPublicModelModalNodesManager,
IPublicTypePropChangeOptions,
IPublicModelDropLocation,
- IPublicEnumEventNames,
IPublicApiCanvas,
+ IPublicTypeDisposable,
} from '@alilc/lowcode-types';
import { Node } from './node';
import { Selection } from './selection';
@@ -108,7 +108,7 @@ export class DocumentModel implements IPublicModelDocumentModel {
set focusNode(node: IPublicModelNode | null) {
this._focusNode = node;
this[editorSymbol].eventBus.emit(
- IPublicEnumEventNames.DOCUMENT_FOCUS_NODE_CHANGED,
+ 'shell.document.focusNodeChanged',
{ document: this, focusNode: node },
);
}
@@ -157,7 +157,7 @@ export class DocumentModel implements IPublicModelDocumentModel {
*/
importSchema(schema: IPublicTypeRootSchema): void {
this[documentSymbol].import(schema);
- this[editorSymbol].eventBus.emit(IPublicEnumEventNames.DOCUMENT_IMPORT_SCHEMA, schema);
+ this[editorSymbol].eventBus.emit('shell.document.importSchema', schema);
}
/**
@@ -241,7 +241,7 @@ export class DocumentModel implements IPublicModelDocumentModel {
/**
* 当前 document 新增节点事件
*/
- onAddNode(fn: (node: IPublicModelNode) => void): () => void {
+ onAddNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable {
return this[documentSymbol].onNodeCreate((node: InnerNode) => {
fn(Node.create(node)!);
});
@@ -250,7 +250,7 @@ export class DocumentModel implements IPublicModelDocumentModel {
/**
* 当前 document 新增节点事件,此时节点已经挂载到 document 上
*/
- onMountNode(fn: (payload: { node: IPublicModelNode }) => void): () => void {
+ onMountNode(fn: (payload: { node: IPublicModelNode }) => void): IPublicTypeDisposable {
this[editorSymbol].eventBus.on('node.add', fn as any);
return () => {
this[editorSymbol].eventBus.off('node.add', fn as any);
@@ -260,7 +260,7 @@ export class DocumentModel implements IPublicModelDocumentModel {
/**
* 当前 document 删除节点事件
*/
- onRemoveNode(fn: (node: IPublicModelNode) => void): () => void {
+ onRemoveNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable {
return this[documentSymbol].onNodeDestroy((node: InnerNode) => {
fn(Node.create(node)!);
});
@@ -269,7 +269,7 @@ export class DocumentModel implements IPublicModelDocumentModel {
/**
* 当前 document 的 hover 变更事件
*/
- onChangeDetecting(fn: (node: IPublicModelNode) => void): () => void {
+ onChangeDetecting(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable {
return this[documentSymbol].designer.detecting.onDetectingChange((node: InnerNode) => {
fn(Node.create(node)!);
});
@@ -278,7 +278,7 @@ export class DocumentModel implements IPublicModelDocumentModel {
/**
* 当前 document 的选中变更事件
*/
- onChangeSelection(fn: (ids: string[]) => void): () => void {
+ onChangeSelection(fn: (ids: string[]) => void): IPublicTypeDisposable {
return this[documentSymbol].selection.onSelectionChange((ids: string[]) => {
fn(ids);
});
@@ -338,11 +338,39 @@ export class DocumentModel implements IPublicModelDocumentModel {
* import schema event
* @param fn
*/
- onImportSchema(fn: (schema: IPublicTypeRootSchema) => void): void {
- this[editorSymbol].on(IPublicEnumEventNames.DOCUMENT_IMPORT_SCHEMA, fn as any);
+ onImportSchema(fn: (schema: IPublicTypeRootSchema) => void): IPublicTypeDisposable {
+ return this[editorSymbol].eventBus.on('shell.document.importSchema', fn as any);
}
isDetectingNode(node: IPublicModelNode): boolean {
return this.detecting.current === node;
}
+
+ onFocusNodeChanged(
+ fn: (doc: IPublicModelDocumentModel, focusNode: IPublicModelNode) => void,
+ ): IPublicTypeDisposable {
+ if (!fn) {
+ return () => {};
+ }
+ return this[editorSymbol].eventBus.on(
+ 'shell.document.focusNodeChanged',
+ (payload) => {
+ const { document, focusNode } = payload;
+ fn(document, focusNode);
+ },
+ );
+ }
+
+ onDropLocationChanged(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable {
+ if (!fn) {
+ return () => {};
+ }
+ return this[editorSymbol].eventBus.on(
+ 'document.dropLocation.changed',
+ (payload) => {
+ const { document } = payload;
+ fn(document);
+ },
+ );
+ }
}
diff --git a/packages/shell/src/model/dragon.ts b/packages/shell/src/model/dragon.ts
index d9c79239d..38fa6323e 100644
--- a/packages/shell/src/model/dragon.ts
+++ b/packages/shell/src/model/dragon.ts
@@ -1,7 +1,7 @@
import {
ILocateEvent as InnerLocateEvent,
} from '@alilc/lowcode-designer';
-import { dragonSymbol } from '../symbols';
+import { dragonSymbol, nodeSymbol } from '../symbols';
import LocateEvent from './locate-event';
import { DragObject } from './drag-object';
import { globalContext } from '@alilc/lowcode-editor-core';
@@ -98,7 +98,10 @@ export class Dragon implements IPublicModelDragon {
* @param boostEvent 拖拽初始时事件
*/
boost(dragObject: DragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode): void {
- return this[dragonSymbol].boost(dragObject, boostEvent, fromRglNode);
+ return this[dragonSymbol].boost({
+ ...dragObject,
+ nodes: dragObject.nodes.map((node: any) => node[nodeSymbol]),
+ }, boostEvent, fromRglNode);
}
/**
diff --git a/packages/types/src/shell/enum/event-names.ts b/packages/types/src/shell/enum/event-names.ts
index ad8569e9a..1bb8682d4 100644
--- a/packages/types/src/shell/enum/event-names.ts
+++ b/packages/types/src/shell/enum/event-names.ts
@@ -6,10 +6,4 @@
*/
// eslint-disable-next-line no-shadow
export enum IPublicEnumEventNames {
- DOCUMENT_IMPORT_SCHEMA = 'shell.document.importSchema',
- DOCUMENT_FOCUS_NODE_CHANGED = 'shell.document.focusNodeChanged',
- SKELETON_PANEL_SHOW = 'skeleton.panel.show',
- SKELETON_PANEL_HIDE = 'skeleton.panel.hide',
- DESIGNER_DOCUMENT_REMOVE = 'designer.document.remove',
- DOCUMENT_DROPLOCATION_CHANGED = 'document.dropLocation.changed',
}
\ No newline at end of file
diff --git a/packages/types/src/shell/model/active-tracker.ts b/packages/types/src/shell/model/active-tracker.ts
index 5229d16f1..b0ceec11f 100644
--- a/packages/types/src/shell/model/active-tracker.ts
+++ b/packages/types/src/shell/model/active-tracker.ts
@@ -1,5 +1,8 @@
import { IPublicTypeActiveTarget } from '../type';
+import { IPublicModelNode } from './node';
export interface IPublicModelActiveTracker {
onChange(fn: (target: IPublicTypeActiveTarget) => void): () => void;
+
+ track(node: IPublicModelNode): void;
}
diff --git a/packages/types/src/shell/model/document-model.ts b/packages/types/src/shell/model/document-model.ts
index 08bdf2789..2ba3f8b67 100644
--- a/packages/types/src/shell/model/document-model.ts
+++ b/packages/types/src/shell/model/document-model.ts
@@ -1,4 +1,4 @@
-import { IPublicTypeRootSchema, IPublicTypeDragNodeDataObject, IPublicTypeDragNodeObject, IPublicTypePropChangeOptions } from '../type';
+import { IPublicTypeRootSchema, IPublicTypeDragNodeDataObject, IPublicTypeDragNodeObject, IPublicTypePropChangeOptions, IPublicTypeDisposable } from '../type';
import { IPublicEnumTransformStage } from '../enum';
import { IPublicApiProject } from '../api';
import { IPublicModelDropLocation, IPublicModelDetecting, IPublicModelNode, IPublicModelSelection, IPublicModelHistory, IPublicModelModalNodesManager } from './';
@@ -114,27 +114,27 @@ export interface IPublicModelDocumentModel {
/**
* 当前 document 新增节点事件
*/
- onAddNode(fn: (node: IPublicModelNode) => void): () => void;
+ onAddNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable;
/**
* 当前 document 新增节点事件,此时节点已经挂载到 document 上
*/
- onMountNode(fn: (payload: { node: IPublicModelNode }) => void): () => void;
+ onMountNode(fn: (payload: { node: IPublicModelNode }) => void): IPublicTypeDisposable;
/**
* 当前 document 删除节点事件
*/
- onRemoveNode(fn: (node: IPublicModelNode) => void): () => void;
+ onRemoveNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable;
/**
* 当前 document 的 hover 变更事件
*/
- onChangeDetecting(fn: (node: IPublicModelNode) => void): () => void;
+ onChangeDetecting(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable;
/**
* 当前 document 的选中变更事件
*/
- onChangeSelection(fn: (ids: string[]) => void): () => void;
+ onChangeSelection(fn: (ids: string[]) => void): IPublicTypeDisposable;
/**
* 当前 document 的节点显隐状态变更事件
@@ -152,16 +152,48 @@ export interface IPublicModelDocumentModel {
/**
* import schema event
* @param fn
+ * @since v1.0.15
*/
- onImportSchema(fn: (schema: IPublicTypeRootSchema) => void): void;
+ onImportSchema(fn: (schema: IPublicTypeRootSchema) => void): IPublicTypeDisposable;
+ /**
+ * 判断是否当前节点处于被探测状态
+ * check is node being detected
+ * @param node
+ * @since v1.1.0
+ */
isDetectingNode(node: IPublicModelNode): boolean;
/**
- * TODO: 待补充说明
+ * 获取当前的 DropLocation 信息
+ * get current drop location
+ * @since v1.1.0
*/
get dropLocation(): IPublicModelDropLocation;
-
+ /**
+ * 设置当前的 DropLocation 信息
+ * set current drop location
+ * @since v1.1.0
+ */
set dropLocation(loc: IPublicModelDropLocation | null);
+
+
+ /**
+ * 设置聚焦节点变化的回调
+ * triggered focused node is set mannually from plugin
+ * @param fn
+ * @since v1.1.0
+ */
+ onFocusNodeChanged(
+ fn: (doc: IPublicModelDocumentModel, focusNode: IPublicModelNode) => void,
+ ): IPublicTypeDisposable;
+
+ /**
+ * 设置 DropLocation 变化的回调
+ * triggered when drop location changed
+ * @param fn
+ * @since v1.1.0
+ */
+ onDropLocationChanged(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable;
}
diff --git a/packages/types/src/shell/model/drop-location.ts b/packages/types/src/shell/model/drop-location.ts
index 746850b1f..d1e57ccbf 100644
--- a/packages/types/src/shell/model/drop-location.ts
+++ b/packages/types/src/shell/model/drop-location.ts
@@ -1,3 +1,10 @@
+import { IPublicTypeLocationDetail } from '../type';
+import { IPublicModelLocateEvent } from './';
+
export interface IPublicModelDropLocation {
get target(): any;
+
+ readonly detail: IPublicTypeLocationDetail;
+
+ clone(event: IPublicModelLocateEvent): IPublicModelDropLocation;
}
diff --git a/packages/utils/src/asset.ts b/packages/utils/src/asset.ts
index 85908c827..4e5a360b8 100644
--- a/packages/utils/src/asset.ts
+++ b/packages/utils/src/asset.ts
@@ -16,7 +16,10 @@ export function isAssetBundle(obj: any): obj is AssetBundle {
return obj && obj.type === AssetType.Bundle;
}
-export function assetBundle(assets?: Asset | AssetList | null, level?: AssetLevel): AssetBundle | null {
+export function assetBundle(
+ assets?: Asset | AssetList | null,
+ level?: AssetLevel,
+ ): AssetBundle | null {
if (!assets) {
return null;
}
diff --git a/packages/utils/src/build-components.ts b/packages/utils/src/build-components.ts
index b58658972..9ed278996 100644
--- a/packages/utils/src/build-components.ts
+++ b/packages/utils/src/build-components.ts
@@ -1,10 +1,10 @@
import { ComponentType, forwardRef, createElement, FunctionComponent } from 'react';
import { IPublicTypeNpmInfo, IPublicTypeComponentSchema } from '@alilc/lowcode-types';
-import { Component } from '@alilc/lowcode-designer';
import { isESModule } from './is-es-module';
import { isReactComponent, acceptsRef, wrapReactClass } from './is-react';
import { isObject } from './is-object';
+type Component = ComponentType | object;
interface LibraryMap {
[key: string]: string;
}
diff --git a/packages/utils/src/create-content.ts b/packages/utils/src/create-content.ts
index 211c26f16..09a368d2b 100644
--- a/packages/utils/src/create-content.ts
+++ b/packages/utils/src/create-content.ts
@@ -1,7 +1,10 @@
import { ReactNode, ComponentType, isValidElement, cloneElement, createElement } from 'react';
import { isReactComponent } from './is-react';
-export function createContent(content: ReactNode | ComponentType, props?: Record): ReactNode {
+export function createContent(
+ content: ReactNode | ComponentType,
+ props?: Record,
+ ): ReactNode {
if (isValidElement(content)) {
return props ? cloneElement(content, props) : content;
}
diff --git a/packages/utils/src/create-icon.tsx b/packages/utils/src/create-icon.tsx
index ef22d4b1e..0f2500529 100644
--- a/packages/utils/src/create-icon.tsx
+++ b/packages/utils/src/create-icon.tsx
@@ -6,7 +6,10 @@ import { isESModule } from './is-es-module';
const URL_RE = /^(https?:)\/\//i;
-export function createIcon(icon?: IPublicTypeIconType | null, props?: Record): ReactNode {
+export function createIcon(
+ icon?: IPublicTypeIconType | null,
+ props?: Record,
+ ): ReactNode {
if (!icon) {
return null;
}
diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
index 950647639..e3f70ff80 100644
--- a/packages/utils/src/index.ts
+++ b/packages/utils/src/index.ts
@@ -26,7 +26,6 @@ export * from './node-helper';
export * from './clone-enumerable-property';
export * from './logger';
export * from './is-shaken';
-export * from './is-public-event-name';
export * from './is-plugin-event-name';
export * as css from './css-helper';
export { transactionManager } from './transaction-manager';
diff --git a/packages/utils/src/is-public-event-name.ts b/packages/utils/src/is-public-event-name.ts
deleted file mode 100644
index 7d225c663..000000000
--- a/packages/utils/src/is-public-event-name.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { IPublicEnumEventNames } from '@alilc/lowcode-types';
-
-export function isPublicEventName(eventName: string): boolean {
- for (const publicEvent in IPublicEnumEventNames) {
- if (eventName === (IPublicEnumEventNames as any)[publicEvent]) {
- return true;
- }
- }
- return false;
-}
\ No newline at end of file
diff --git a/packages/utils/src/misc.ts b/packages/utils/src/misc.ts
index 8a8211250..4510e8643 100644
--- a/packages/utils/src/misc.ts
+++ b/packages/utils/src/misc.ts
@@ -1,8 +1,8 @@
import { isI18NObject } from './is-object';
import { get } from 'lodash';
-import { ComponentMeta } from '@alilc/lowcode-designer';
-import { TransformStage } from '@alilc/lowcode-types';
+import { IPublicEnumTransformStage, IPublicModelComponentMeta } from '@alilc/lowcode-types';
+
interface Variable {
type: 'variable';
variable: string;
@@ -65,7 +65,7 @@ export function arrShallowEquals(arr1: any[], arr2: any[]): boolean {
* 判断当前 meta 是否从 vc prototype 转换而来
* @param meta
*/
- export function isFromVC(meta: ComponentMeta) {
+ export function isFromVC(meta: IPublicModelComponentMeta) {
return !!meta?.getMetadata().configure?.advanced;
}
@@ -86,12 +86,12 @@ const stageList = [
* @param stage
* @returns
*/
-export function compatStage(stage: TransformStage | number): TransformStage {
+export function compatStage(stage: IPublicEnumTransformStage | number): IPublicEnumTransformStage {
if (typeof stage === 'number') {
- console.warn('stage 直接指定为数字的使用方式已经过时,将在下一版本移除,请直接使用 TransformStage.Render|Serilize|Save|Clone|Init|Upgrade');
- return stageList[stage - 1] as TransformStage;
+ console.warn('stage 直接指定为数字的使用方式已经过时,将在下一版本移除,请直接使用 IPublicEnumTransformStage.Render|Serilize|Save|Clone|Init|Upgrade');
+ return stageList[stage - 1] as IPublicEnumTransformStage;
}
- return stage as TransformStage;
+ return stage as IPublicEnumTransformStage;
}
export function invariant(check: any, message: string, thing?: any) {
diff --git a/packages/utils/src/node-helper.ts b/packages/utils/src/node-helper.ts
index 5f0547274..9d6573cdc 100644
--- a/packages/utils/src/node-helper.ts
+++ b/packages/utils/src/node-helper.ts
@@ -1,7 +1,10 @@
// 仅使用类型
-import { Node } from '@alilc/lowcode-designer';
+import { IPublicModelNode } from '@alilc/lowcode-types';
-export const getClosestNode = (node: Node, until: (node: Node) => boolean): Node | undefined => {
+export const getClosestNode = (
+ node: IPublicModelNode,
+ until: (n: IPublicModelNode) => boolean,
+ ): IPublicModelNode | undefined => {
if (!node) {
return undefined;
}
@@ -19,7 +22,7 @@ export const getClosestNode = (node: Node, until: (node: Node) => boolean): Node
* @param {unknown} e 点击事件
* @returns {boolean} 是否可点击,true表示可点击
*/
-export const canClickNode = (node: Node, e: unknown): boolean => {
+export const canClickNode = (node: IPublicModelNode, e: unknown): boolean => {
const onClickHook = node.componentMeta?.getMetadata().configure?.advanced?.callbacks?.onClickHook;
const canClick = typeof onClickHook === 'function' ? onClickHook(e as MouseEvent, node) : true;
return canClick;
diff --git a/packages/workspace/src/base-context.ts b/packages/workspace/src/base-context.ts
index af606ddf0..66c2966bd 100644
--- a/packages/workspace/src/base-context.ts
+++ b/packages/workspace/src/base-context.ts
@@ -28,11 +28,13 @@ import {
Common,
Logger,
Workspace,
+ Canvas,
} from '@alilc/lowcode-shell';
import {
IPublicTypePluginMeta,
} from '@alilc/lowcode-types';
import { getLogger } from '@alilc/lowcode-utils';
+import { OutlinePlugin } from '@alilc/lowcode-plugin-outline-pane';
import { setterRegistry } from '../../engine/src/inner-plugins/setter-registry';
import { componentMetaParser } from '../../engine/src/inner-plugins/component-meta-parser';
import defaultPanelRegistry from '../../engine/src/inner-plugins/default-panel-registry';
@@ -58,6 +60,7 @@ export class BasicContext {
innerSkeleton: any;
innerHotkey: InnerHotkey;
innerPlugins: LowCodePluginManager;
+ canvas: Canvas;
constructor(innerWorkspace: any, viewName: string, public editorWindow?: EditorWindow) {
const editor = new Editor(viewName, true);
@@ -84,6 +87,7 @@ export class BasicContext {
const event = new Event(commonEvent, { prefix: 'common' });
const logger = getLogger({ level: 'warn', bizName: 'common' });
const skeleton = new Skeleton(innerSkeleton, 'any', true);
+ const canvas = new Canvas(editor);
editor.set('setters', setters);
editor.set('project', project);
editor.set('material', material);
@@ -103,6 +107,7 @@ export class BasicContext {
this.innerHotkey = innerHotkey;
this.editor = editor;
this.designer = designer;
+ this.canvas = canvas;
const common = new Common(editor, innerSkeleton);
let plugins: any;
@@ -120,6 +125,7 @@ export class BasicContext {
context.common = common;
context.plugins = plugins;
context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` });
+ context.canvas = canvas;
},
};
@@ -132,6 +138,7 @@ export class BasicContext {
// 注册一批内置插件
this.registerInnerPlugins = async function registerPlugins() {
+ await plugins.register(OutlinePlugin, {}, { autoInit: true });
await plugins.register(componentMetaParser(designer));
await plugins.register(setterRegistry, {}, { autoInit: true });
await plugins.register(defaultPanelRegistry(editor, designer));