mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-11 18:42:56 +00:00
feat(shell): add editor-view model
This commit is contained in:
parent
c50a0823db
commit
358dde43a4
21
docs/docs/api/model/editor-view.md
Normal file
21
docs/docs/api/model/editor-view.md
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
title: EditorView
|
||||
sidebar_position: 12
|
||||
---
|
||||
|
||||
> **[@experimental](./#experimental)**<br/>
|
||||
> **@types** [IPublicModelEditorView](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/editor-view.ts)<br/>
|
||||
> **@since** v1.1.7
|
||||
|
||||
窗口编辑视图
|
||||
|
||||
## 类型定义
|
||||
|
||||
```
|
||||
import { IPublicModelPluginContext } from "./plugin-context";
|
||||
|
||||
export interface IPublicModelEditorView extends IPublicModelPluginContext {};
|
||||
|
||||
```
|
||||
|
||||
相关类型定义: [IPublicModelPluginContext](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/plugin-context.ts)
|
||||
@ -38,6 +38,22 @@ sidebar_position: 12
|
||||
|
||||
关联模型 [IPublicModelResource](./resource)
|
||||
|
||||
### currentEditorView
|
||||
窗口当前视图
|
||||
|
||||
`@type {IPublicModelEditorView}`
|
||||
|
||||
关联模型 [IPublicModelEditorView](./editor-view)
|
||||
|
||||
### editorViews
|
||||
|
||||
窗口所有视图
|
||||
|
||||
`@type {IPublicModelEditorView[]}`
|
||||
|
||||
关联模型 [IPublicModelEditorView](./editor-view)
|
||||
|
||||
|
||||
## 方法
|
||||
|
||||
### importSchema
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
IPublicTypePluginMeta,
|
||||
IPublicTypePluginRegisterOptions,
|
||||
IPublicModelWindow,
|
||||
IPublicEnumPluginRegisterLevel,
|
||||
} from '@alilc/lowcode-types';
|
||||
import PluginContext from './plugin-context';
|
||||
|
||||
@ -58,6 +59,7 @@ export interface ILowCodePluginContextPrivate {
|
||||
set canvas(canvas: IPublicApiCanvas);
|
||||
set workspace(workspace: IPublicApiWorkspace);
|
||||
set editorWindow(window: IPublicModelWindow);
|
||||
set registerLevel(level: IPublicEnumPluginRegisterLevel);
|
||||
}
|
||||
export interface ILowCodePluginContextApiAssembler {
|
||||
assembleApis(
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
IPublicTypeDisposable,
|
||||
IPublicApiPlugins,
|
||||
IPublicApiWorkspace,
|
||||
IPublicEnumPluginRegisterLevel,
|
||||
} from '@alilc/lowcode-types';
|
||||
import {
|
||||
Designer,
|
||||
@ -138,6 +139,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = {
|
||||
context.plugins = plugins;
|
||||
context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` });
|
||||
context.workspace = workspace;
|
||||
context.registerLevel = IPublicEnumPluginRegisterLevel.Default;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -13,8 +13,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@alifd/next": "^1.19.16",
|
||||
"@alilc/lowcode-designer": "1.1.6",
|
||||
"@alilc/lowcode-editor-core": "1.1.6",
|
||||
"@alilc/lowcode-types": "1.1.6",
|
||||
"@alilc/lowcode-utils": "1.1.6",
|
||||
"classnames": "^2.2.6",
|
||||
|
||||
@ -16,16 +16,15 @@ import {
|
||||
IPublicModelDropLocation,
|
||||
IPublicModelScroller,
|
||||
IPublicModelScrollTarget,
|
||||
IPublicModelPluginContext,
|
||||
IPublicModelLocateEvent,
|
||||
} from '@alilc/lowcode-types';
|
||||
import TreeNode from './tree-node';
|
||||
import { IndentTrack } from '../helper/indent-track';
|
||||
import DwellTimer from '../helper/dwell-timer';
|
||||
import { ITreeBoard, TreeMaster } from './tree-master';
|
||||
import { IOutlinePanelPluginContext, ITreeBoard, TreeMaster } from './tree-master';
|
||||
|
||||
export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTypeScrollable {
|
||||
private pluginContext: IPublicModelPluginContext;
|
||||
private pluginContext: IOutlinePanelPluginContext;
|
||||
|
||||
private treeMaster?: TreeMaster;
|
||||
|
||||
@ -100,8 +99,8 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTy
|
||||
|
||||
private _shell: HTMLDivElement | null = null;
|
||||
|
||||
constructor(at: string | symbol, pluginContext: IPublicModelPluginContext, treeMaster: TreeMaster) {
|
||||
this.pluginContext = pluginContext;
|
||||
constructor(at: string | symbol, treeMaster: TreeMaster) {
|
||||
this.pluginContext = treeMaster.pluginContext;
|
||||
this.treeMaster = treeMaster;
|
||||
this.at = at;
|
||||
let inited = false;
|
||||
@ -237,7 +236,7 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTy
|
||||
let { node } = treeNode;
|
||||
if (isDragNodeObject(dragObject)) {
|
||||
const newNodes = operationalNodes;
|
||||
let i = newNodes.length;
|
||||
let i = newNodes?.length;
|
||||
let p: any = node;
|
||||
while (i-- > 0) {
|
||||
if (newNodes[i].contains(p)) {
|
||||
@ -482,7 +481,7 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTy
|
||||
const isSlotContainer = treeNode.hasSlots();
|
||||
const isContainer = treeNode.isContainer();
|
||||
|
||||
if (container.isSlot && !treeNode.expanded) {
|
||||
if (container.isSlotNode && !treeNode.expanded) {
|
||||
// 未展开,直接定位到内部第一个节点
|
||||
if (isSlotContainer) {
|
||||
detail.index = null;
|
||||
|
||||
@ -1,67 +1,139 @@
|
||||
import { isLocationChildrenDetail } from '@alilc/lowcode-utils';
|
||||
import { IPublicModelPluginContext, IPublicTypeActiveTarget, IPublicModelNode } from '@alilc/lowcode-types';
|
||||
import { IPublicModelPluginContext, IPublicTypeActiveTarget, IPublicModelNode, IPublicTypeDisposable, IPublicEnumPluginRegisterLevel } from '@alilc/lowcode-types';
|
||||
import TreeNode from './tree-node';
|
||||
import { Tree } from './tree';
|
||||
import EventEmitter from 'events';
|
||||
import { enUS, zhCN } from '../locale';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export interface ITreeBoard {
|
||||
readonly at: string | symbol;
|
||||
scrollToNode(treeNode: TreeNode, detail?: any): void;
|
||||
}
|
||||
|
||||
enum EVENT_NAMES {
|
||||
pluginContextChanged = 'pluginContextChanged',
|
||||
}
|
||||
|
||||
export interface IOutlinePanelPluginContext extends IPublicModelPluginContext {
|
||||
extraTitle?: string;
|
||||
intlNode(id: string, params?: object): ReactNode;
|
||||
intl(id: string, params?: object): string;
|
||||
getLocale(): string;
|
||||
}
|
||||
|
||||
export class TreeMaster {
|
||||
readonly pluginContext: IPublicModelPluginContext;
|
||||
pluginContext: IOutlinePanelPluginContext;
|
||||
|
||||
private boards = new Set<ITreeBoard>();
|
||||
|
||||
private treeMap = new Map<string, Tree>();
|
||||
|
||||
constructor(pluginContext: IPublicModelPluginContext) {
|
||||
this.pluginContext = pluginContext;
|
||||
private disposeEvents: (IPublicTypeDisposable | undefined)[] = [];
|
||||
|
||||
event = new EventEmitter();
|
||||
|
||||
constructor(pluginContext: IPublicModelPluginContext, readonly options: {
|
||||
extraTitle?: string;
|
||||
}) {
|
||||
this.setPluginContext(pluginContext);
|
||||
const { workspace } = this.pluginContext;
|
||||
this.initEvent();
|
||||
if (pluginContext.registerLevel === IPublicEnumPluginRegisterLevel.Workspace) {
|
||||
workspace.onWindowRendererReady(() => {
|
||||
this.setPluginContext(workspace.window?.currentEditorView);
|
||||
let dispose: IPublicTypeDisposable | undefined;
|
||||
const windowViewTypeChangeEvent = () => {
|
||||
dispose = workspace.window?.onChangeViewType(() => {
|
||||
this.setPluginContext(workspace.window?.currentEditorView);
|
||||
});
|
||||
};
|
||||
|
||||
windowViewTypeChangeEvent();
|
||||
|
||||
workspace.onChangeActiveWindow(() => {
|
||||
windowViewTypeChangeEvent();
|
||||
this.setPluginContext(workspace.window?.currentEditorView);
|
||||
dispose && dispose();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private setPluginContext(pluginContext: IPublicModelPluginContext | undefined) {
|
||||
if (!pluginContext) {
|
||||
return;
|
||||
}
|
||||
const { intl, intlNode, getLocale } = pluginContext.common.utils.createIntl({
|
||||
'en-US': enUS,
|
||||
'zh-CN': zhCN,
|
||||
});
|
||||
let _pluginContext: IOutlinePanelPluginContext = Object.assign(pluginContext, {
|
||||
intl,
|
||||
intlNode,
|
||||
getLocale,
|
||||
});
|
||||
_pluginContext.extraTitle = this.options && this.options['extraTitle'];
|
||||
this.pluginContext = _pluginContext;
|
||||
this.disposeEvent();
|
||||
this.initEvent();
|
||||
this.emitPluginContextChange();
|
||||
}
|
||||
|
||||
private disposeEvent() {
|
||||
this.disposeEvents.forEach(d => {
|
||||
d && d();
|
||||
});
|
||||
}
|
||||
|
||||
private initEvent() {
|
||||
let startTime: any;
|
||||
const { event, project, canvas } = this.pluginContext;
|
||||
canvas.dragon?.onDragstart(() => {
|
||||
startTime = Date.now() / 1000;
|
||||
// needs?
|
||||
this.toVision();
|
||||
});
|
||||
canvas.activeTracker?.onChange((target: IPublicTypeActiveTarget) => {
|
||||
const { node, detail } = target;
|
||||
const tree = this.currentTree;
|
||||
if (!tree/* || node.document !== tree.document */) {
|
||||
return;
|
||||
}
|
||||
const treeNode = tree.getTreeNode(node);
|
||||
if (detail && isLocationChildrenDetail(detail)) {
|
||||
treeNode.expand(true);
|
||||
} else {
|
||||
treeNode.expandParents();
|
||||
}
|
||||
this.boards.forEach((board) => {
|
||||
board.scrollToNode(treeNode, detail);
|
||||
});
|
||||
});
|
||||
canvas.dragon?.onDragend(() => {
|
||||
const endTime: any = Date.now() / 1000;
|
||||
const nodes = project.currentDocument?.selection?.getNodes();
|
||||
event.emit('outlinePane.dragend', {
|
||||
selected: nodes
|
||||
?.map((n) => {
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
const npm = n?.componentMeta?.npm;
|
||||
return (
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') || n?.componentMeta?.componentName
|
||||
);
|
||||
})
|
||||
.join('&'),
|
||||
time: (endTime - startTime).toFixed(2),
|
||||
});
|
||||
});
|
||||
project.onRemoveDocument((data: {id: string}) => {
|
||||
const { id } = data;
|
||||
this.treeMap.delete(id);
|
||||
});
|
||||
this.disposeEvents = [
|
||||
canvas.dragon?.onDragstart(() => {
|
||||
startTime = Date.now() / 1000;
|
||||
// needs?
|
||||
this.toVision();
|
||||
}),
|
||||
canvas.activeTracker?.onChange((target: IPublicTypeActiveTarget) => {
|
||||
const { node, detail } = target;
|
||||
const tree = this.currentTree;
|
||||
if (!tree/* || node.document !== tree.document */) {
|
||||
return;
|
||||
}
|
||||
const treeNode = tree.getTreeNode(node);
|
||||
if (detail && isLocationChildrenDetail(detail)) {
|
||||
treeNode.expand(true);
|
||||
} else {
|
||||
treeNode.expandParents();
|
||||
}
|
||||
this.boards.forEach((board) => {
|
||||
board.scrollToNode(treeNode, detail);
|
||||
});
|
||||
}),
|
||||
canvas.dragon?.onDragend(() => {
|
||||
const endTime: any = Date.now() / 1000;
|
||||
const nodes = project.currentDocument?.selection?.getNodes();
|
||||
event.emit('outlinePane.dragend', {
|
||||
selected: nodes
|
||||
?.map((n) => {
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
const npm = n?.componentMeta?.npm;
|
||||
return (
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') || n?.componentMeta?.componentName
|
||||
);
|
||||
})
|
||||
.join('&'),
|
||||
time: (endTime - startTime).toFixed(2),
|
||||
});
|
||||
}),
|
||||
project.onRemoveDocument((data: {id: string}) => {
|
||||
const { id } = data;
|
||||
this.treeMap.delete(id);
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
private toVision() {
|
||||
@ -86,6 +158,14 @@ export class TreeMaster {
|
||||
// todo others purge
|
||||
}
|
||||
|
||||
onPluginContextChange(fn: () => void) {
|
||||
this.event.on(EVENT_NAMES.pluginContextChanged, fn);
|
||||
}
|
||||
|
||||
emitPluginContextChange() {
|
||||
this.event.emit(EVENT_NAMES.pluginContextChanged);
|
||||
}
|
||||
|
||||
get currentTree(): Tree | null {
|
||||
const doc = this.pluginContext.project.getCurrentDocument();
|
||||
if (doc) {
|
||||
@ -93,7 +173,7 @@ export class TreeMaster {
|
||||
if (this.treeMap.has(id)) {
|
||||
return this.treeMap.get(id)!;
|
||||
}
|
||||
const tree = new Tree(this.pluginContext);
|
||||
const tree = new Tree(this);
|
||||
this.treeMap.set(id, tree);
|
||||
return tree;
|
||||
}
|
||||
|
||||
@ -2,12 +2,12 @@ import {
|
||||
IPublicTypeTitleContent,
|
||||
IPublicTypeLocationChildrenDetail,
|
||||
IPublicModelNode,
|
||||
IPublicModelPluginContext,
|
||||
IPublicTypeDisposable,
|
||||
} from '@alilc/lowcode-types';
|
||||
import { isI18nData, isLocationChildrenDetail } from '@alilc/lowcode-utils';
|
||||
import EventEmitter from 'events';
|
||||
import { Tree } from './tree';
|
||||
import { IOutlinePanelPluginContext } from './tree-master';
|
||||
|
||||
/**
|
||||
* 大纲树过滤结果
|
||||
@ -38,7 +38,7 @@ enum EVENT_NAMES {
|
||||
}
|
||||
|
||||
export default class TreeNode {
|
||||
readonly pluginContext: IPublicModelPluginContext;
|
||||
readonly pluginContext: IOutlinePanelPluginContext;
|
||||
event = new EventEmitter();
|
||||
|
||||
private _node: IPublicModelNode;
|
||||
@ -160,9 +160,9 @@ export default class TreeNode {
|
||||
return this._node;
|
||||
}
|
||||
|
||||
constructor(tree: Tree, node: IPublicModelNode, pluginContext: IPublicModelPluginContext) {
|
||||
constructor(tree: Tree, node: IPublicModelNode) {
|
||||
this.tree = tree;
|
||||
this.pluginContext = pluginContext;
|
||||
this.pluginContext = tree.pluginContext;
|
||||
this._node = node;
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import TreeNode from './tree-node';
|
||||
import { IPublicModelNode, IPublicModelPluginContext, IPublicTypePropChangeOptions } from '@alilc/lowcode-types';
|
||||
import { IPublicModelNode, IPublicTypePropChangeOptions } from '@alilc/lowcode-types';
|
||||
import { IOutlinePanelPluginContext, TreeMaster } from './tree-master';
|
||||
|
||||
export class Tree {
|
||||
private treeNodesMap = new Map<string, TreeNode>();
|
||||
|
||||
readonly id: string | undefined;
|
||||
|
||||
readonly pluginContext: IPublicModelPluginContext;
|
||||
readonly pluginContext: IOutlinePanelPluginContext;
|
||||
|
||||
get root(): TreeNode | null {
|
||||
if (this.pluginContext.project.currentDocument?.focusNode) {
|
||||
@ -15,8 +16,11 @@ export class Tree {
|
||||
return null;
|
||||
}
|
||||
|
||||
constructor(pluginContext: IPublicModelPluginContext) {
|
||||
this.pluginContext = pluginContext;
|
||||
readonly treeMaster: TreeMaster;
|
||||
|
||||
constructor(treeMaster: TreeMaster) {
|
||||
this.treeMaster = treeMaster;
|
||||
this.pluginContext = treeMaster.pluginContext;
|
||||
const doc = this.pluginContext.project.currentDocument;
|
||||
this.id = doc?.id;
|
||||
|
||||
@ -51,7 +55,7 @@ export class Tree {
|
||||
return tnode;
|
||||
}
|
||||
|
||||
const treeNode = new TreeNode(this, node, this.pluginContext);
|
||||
const treeNode = new TreeNode(this, node);
|
||||
this.treeNodesMap.set(node.id, treeNode);
|
||||
return treeNode;
|
||||
}
|
||||
|
||||
@ -1,21 +1,13 @@
|
||||
import { Pane } from './views/pane';
|
||||
import { IconOutline } from './icons/outline';
|
||||
import { IPublicModelPluginContext, IPublicModelDocumentModel } from '@alilc/lowcode-types';
|
||||
import { enUS, zhCN } from './locale';
|
||||
import { MasterPaneName, BackupPaneName } from './helper/consts';
|
||||
import { TreeMaster } from './controllers/tree-master';
|
||||
import { PaneController } from './controllers/pane-controller';
|
||||
import { useState } from 'react';
|
||||
|
||||
export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => {
|
||||
const { skeleton, config, common, event, canvas, project } = ctx;
|
||||
const { intl, intlNode, getLocale } = common.utils.createIntl({
|
||||
'en-US': enUS,
|
||||
'zh-CN': zhCN,
|
||||
});
|
||||
ctx.intl = intl;
|
||||
ctx.intlNode = intlNode;
|
||||
ctx.getLocale = getLocale;
|
||||
ctx.extraTitle = options && options['extraTitle'];
|
||||
const { skeleton, config, canvas, project } = ctx;
|
||||
|
||||
let isInFloatArea = true;
|
||||
const hasPreferenceForOutline = config.getPreference().contains('outline-pane-pinned-status-isFloat', 'skeleton');
|
||||
@ -26,8 +18,7 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => {
|
||||
masterPane: false,
|
||||
backupPane: false,
|
||||
};
|
||||
const treeMaster = new TreeMaster(ctx);
|
||||
let masterPaneController: PaneController | null = null;
|
||||
const treeMaster = new TreeMaster(ctx, options);
|
||||
let backupPaneController: PaneController | null = null;
|
||||
return {
|
||||
async init() {
|
||||
@ -40,16 +31,20 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => {
|
||||
name: MasterPaneName,
|
||||
props: {
|
||||
icon: IconOutline,
|
||||
description: intlNode('Outline Tree'),
|
||||
description: treeMaster.pluginContext.intlNode('Outline Tree'),
|
||||
},
|
||||
content: (props: any) => {
|
||||
masterPaneController = new PaneController(MasterPaneName, ctx, treeMaster);
|
||||
content: function Context(props: any) {
|
||||
const [masterPaneController, setMasterPaneController] = useState(new PaneController(MasterPaneName, treeMaster));
|
||||
treeMaster.onPluginContextChange(() => {
|
||||
setMasterPaneController(new PaneController(MasterPaneName, treeMaster));
|
||||
});
|
||||
|
||||
return (
|
||||
<Pane
|
||||
config={config}
|
||||
pluginContext={ctx}
|
||||
treeMaster={treeMaster}
|
||||
controller={masterPaneController}
|
||||
key={masterPaneController.id}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
@ -73,10 +68,9 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => {
|
||||
hiddenWhenInit: true,
|
||||
},
|
||||
content: (props: any) => {
|
||||
backupPaneController = new PaneController(BackupPaneName, ctx, treeMaster);
|
||||
backupPaneController = new PaneController(BackupPaneName, treeMaster);
|
||||
return (
|
||||
<Pane
|
||||
pluginContext={ctx}
|
||||
treeMaster={treeMaster}
|
||||
controller={backupPaneController}
|
||||
{...props}
|
||||
|
||||
@ -5,11 +5,9 @@ import { Search, Checkbox, Balloon, Divider } from '@alifd/next';
|
||||
import TreeNode from '../controllers/tree-node';
|
||||
import { Tree } from '../controllers/tree';
|
||||
import { matchTreeNode, FILTER_OPTIONS } from './filter-tree';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
|
||||
export default class Filter extends PureComponent<{
|
||||
tree: Tree;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
}, {
|
||||
keywords: string;
|
||||
filterOps: string[];
|
||||
@ -53,14 +51,16 @@ export default class Filter extends PureComponent<{
|
||||
|
||||
return (
|
||||
<div className="lc-outline-filter">
|
||||
{/* @ts-ignore */}
|
||||
<Search
|
||||
hasClear
|
||||
shape="simple"
|
||||
placeholder={this.props.pluginContext.intl('Filter Node')}
|
||||
placeholder={this.props.tree.pluginContext.intl('Filter Node')}
|
||||
className="lc-outline-filter-search-input"
|
||||
value={keywords}
|
||||
onChange={this.handleSearchChange}
|
||||
/>
|
||||
{/* @ts-ignore */}
|
||||
<Balloon
|
||||
v2
|
||||
align="br"
|
||||
@ -72,14 +72,17 @@ export default class Filter extends PureComponent<{
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
{/* @ts-ignore */}
|
||||
<Checkbox
|
||||
checked={checkAll}
|
||||
indeterminate={indeterminate}
|
||||
onChange={this.handleCheckAll}
|
||||
>
|
||||
{this.props.pluginContext.intlNode('Check All')}
|
||||
{this.props.tree.pluginContext.intlNode('Check All')}
|
||||
</Checkbox>
|
||||
{/* @ts-ignore */}
|
||||
<Divider />
|
||||
{/* @ts-ignore */}
|
||||
<Checkbox.Group
|
||||
value={filterOps}
|
||||
direction="ver"
|
||||
@ -91,7 +94,7 @@ export default class Filter extends PureComponent<{
|
||||
value={op.value}
|
||||
key={op.value}
|
||||
>
|
||||
{this.props.pluginContext.intlNode(op.label)}
|
||||
{this.props.tree.pluginContext.intlNode(op.label)}
|
||||
</Checkbox>
|
||||
))}
|
||||
</Checkbox.Group>
|
||||
|
||||
@ -1,47 +1,71 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Loading } from '@alifd/next';
|
||||
import { PaneController } from '../controllers/pane-controller';
|
||||
import TreeView from './tree';
|
||||
import './style.less';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
import Filter from './filter';
|
||||
import { TreeMaster } from '../controllers/tree-master';
|
||||
import { Tree } from '../controllers/tree';
|
||||
import { IPublicTypeDisposable } from '@alilc/lowcode-types';
|
||||
|
||||
export class Pane extends PureComponent<{
|
||||
config: any;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
treeMaster: TreeMaster;
|
||||
controller: PaneController;
|
||||
}, {
|
||||
tree: Tree | null;
|
||||
}> {
|
||||
private controller;
|
||||
private treeMaster: TreeMaster;
|
||||
|
||||
private dispose: IPublicTypeDisposable;
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
const { controller, treeMaster } = props;
|
||||
this.treeMaster = treeMaster;
|
||||
this.controller = controller;
|
||||
this.state = {
|
||||
tree: treeMaster.currentTree,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.controller.purge();
|
||||
this.dispose && this.dispose();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.dispose = this.props.treeMaster.pluginContext.project.onSimulatorRendererReady(() => {
|
||||
this.setState({
|
||||
tree: this.props.treeMaster.currentTree,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const tree = this.treeMaster.currentTree;
|
||||
const tree = this.state.tree;
|
||||
|
||||
if (!tree) {
|
||||
return (
|
||||
<div className="lc-outline-pane">
|
||||
<p className="lc-outline-notice">{this.props.pluginContext.intl('Initializing')}</p>
|
||||
<p className="lc-outline-notice">
|
||||
{/* @ts-ignore */}
|
||||
<Loading
|
||||
style={{
|
||||
display: 'block',
|
||||
marginTop: '40px',
|
||||
}}
|
||||
tip={this.props.treeMaster.pluginContext.intl('Initializing')}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="lc-outline-pane">
|
||||
<Filter tree={tree} pluginContext={this.props.pluginContext} />
|
||||
<Filter tree={tree} />
|
||||
<div ref={(shell) => this.controller.mount(shell)} className="lc-outline-tree-container">
|
||||
<TreeView key={tree.id} tree={tree} pluginContext={this.props.pluginContext} />
|
||||
<TreeView key={tree.id} tree={tree} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -2,12 +2,11 @@ import { PureComponent } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import TreeNode from '../controllers/tree-node';
|
||||
import TreeNodeView from './tree-node';
|
||||
import { IPublicModelPluginContext, IPublicModelExclusiveGroup, IPublicTypeDisposable, IPublicTypeLocationChildrenDetail } from '@alilc/lowcode-types';
|
||||
import { IPublicModelExclusiveGroup, IPublicTypeDisposable, IPublicTypeLocationChildrenDetail } from '@alilc/lowcode-types';
|
||||
|
||||
export default class TreeBranches extends PureComponent<{
|
||||
treeNode: TreeNode;
|
||||
isModal?: boolean;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
expanded: boolean;
|
||||
treeChildren: TreeNode[] | null;
|
||||
}> {
|
||||
@ -51,12 +50,11 @@ export default class TreeBranches extends PureComponent<{
|
||||
return (
|
||||
<div className="tree-node-branches">
|
||||
{
|
||||
!isModal && <TreeNodeSlots treeNode={treeNode} pluginContext={this.props.pluginContext} />
|
||||
!isModal && <TreeNodeSlots treeNode={treeNode} />
|
||||
}
|
||||
<TreeNodeChildren
|
||||
treeNode={treeNode}
|
||||
isModal={isModal || false}
|
||||
pluginContext={this.props.pluginContext}
|
||||
treeChildren={this.props.treeChildren}
|
||||
/>
|
||||
</div>
|
||||
@ -73,7 +71,6 @@ interface ITreeNodeChildrenState {
|
||||
class TreeNodeChildren extends PureComponent<{
|
||||
treeNode: TreeNode;
|
||||
isModal?: boolean;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
treeChildren: TreeNode[] | null;
|
||||
}, ITreeNodeChildrenState> {
|
||||
state: ITreeNodeChildrenState = {
|
||||
@ -84,8 +81,8 @@ class TreeNodeChildren extends PureComponent<{
|
||||
};
|
||||
offLocationChanged: IPublicTypeDisposable | undefined;
|
||||
componentDidMount() {
|
||||
const { treeNode, pluginContext } = this.props;
|
||||
const { project } = pluginContext;
|
||||
const { treeNode } = this.props;
|
||||
const { project } = treeNode.pluginContext;
|
||||
const { filterWorking, matchSelf, keywords } = treeNode.filterReult;
|
||||
const { dropDetail } = treeNode;
|
||||
this.setState({
|
||||
@ -122,13 +119,14 @@ class TreeNodeChildren extends PureComponent<{
|
||||
let groupContents: any[] = [];
|
||||
let currentGrp: IPublicModelExclusiveGroup;
|
||||
const { filterWorking, matchSelf, keywords } = this.state;
|
||||
const Title = this.props.pluginContext.common.editorCabin.Title;
|
||||
const Title = this.props.treeNode.pluginContext.common.editorCabin.Title;
|
||||
|
||||
const endGroup = () => {
|
||||
if (groupContents.length > 0) {
|
||||
children.push(
|
||||
<div key={currentGrp.id} className="condition-group-container" data-id={currentGrp.firstNode?.id}>
|
||||
<div className="condition-group-title">
|
||||
{/* @ts-ignore */}
|
||||
<Title
|
||||
title={currentGrp.title}
|
||||
match={filterWorking && matchSelf}
|
||||
@ -171,12 +169,12 @@ class TreeNodeChildren extends PureComponent<{
|
||||
children.push(insertion);
|
||||
}
|
||||
}
|
||||
groupContents.push(<TreeNodeView key={child.id} treeNode={child} isModal={isModal} pluginContext={this.props.pluginContext} />);
|
||||
groupContents.push(<TreeNodeView key={child.id} treeNode={child} isModal={isModal} />);
|
||||
} else {
|
||||
if (index === dropIndex) {
|
||||
children.push(insertion);
|
||||
}
|
||||
children.push(<TreeNodeView key={child.id} treeNode={child} isModal={isModal} pluginContext={this.props.pluginContext} />);
|
||||
children.push(<TreeNodeView key={child.id} treeNode={child} isModal={isModal} />);
|
||||
}
|
||||
});
|
||||
endGroup();
|
||||
@ -191,14 +189,13 @@ class TreeNodeChildren extends PureComponent<{
|
||||
|
||||
class TreeNodeSlots extends PureComponent<{
|
||||
treeNode: TreeNode;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
}> {
|
||||
render() {
|
||||
const { treeNode } = this.props;
|
||||
if (!treeNode.hasSlots()) {
|
||||
return null;
|
||||
}
|
||||
const Title = this.props.pluginContext.common.editorCabin.Title;
|
||||
const Title = this.props.treeNode.pluginContext.common.editorCabin.Title;
|
||||
return (
|
||||
<div
|
||||
className={classNames('tree-node-slots', {
|
||||
@ -207,10 +204,11 @@ class TreeNodeSlots extends PureComponent<{
|
||||
data-id={treeNode.id}
|
||||
>
|
||||
<div className="tree-node-slots-title">
|
||||
<Title title={{ type: 'i18n', intl: this.props.pluginContext.intlNode('Slots') }} />
|
||||
{/* @ts-ignore */}
|
||||
<Title title={{ type: 'i18n', intl: this.props.treeNode.pluginContext.intlNode('Slots') }} />
|
||||
</div>
|
||||
{treeNode.slots.map(tnode => (
|
||||
<TreeNodeView key={tnode.id} treeNode={tnode} pluginContext={this.props.pluginContext} />
|
||||
<TreeNodeView key={tnode.id} treeNode={tnode} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -4,22 +4,24 @@ 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, IPublicTypeDisposable } from '@alilc/lowcode-types';
|
||||
import { IPublicModelModalNodesManager, IPublicTypeDisposable } from '@alilc/lowcode-types';
|
||||
import { IOutlinePanelPluginContext } from '../controllers/tree-master';
|
||||
|
||||
class ModalTreeNodeView extends PureComponent<{
|
||||
treeNode: TreeNode;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
}, {
|
||||
treeChildren: TreeNode[] | null;
|
||||
}> {
|
||||
private modalNodesManager: IPublicModelModalNodesManager | undefined | null;
|
||||
readonly pluginContext: IPublicModelPluginContext;
|
||||
readonly pluginContext: IOutlinePanelPluginContext;
|
||||
|
||||
constructor(props: any) {
|
||||
constructor(props: {
|
||||
treeNode: TreeNode;
|
||||
}) {
|
||||
super(props);
|
||||
|
||||
// 模态管理对象
|
||||
this.pluginContext = props.pluginContext;
|
||||
this.pluginContext = props.treeNode.pluginContext;
|
||||
const { project } = this.pluginContext;
|
||||
this.modalNodesManager = project.currentDocument?.modalNodesManager;
|
||||
this.state = {
|
||||
@ -72,7 +74,6 @@ class ModalTreeNodeView extends PureComponent<{
|
||||
treeChildren={this.state.treeChildren}
|
||||
expanded={expanded}
|
||||
isModal
|
||||
pluginContext={this.pluginContext}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -83,7 +84,6 @@ class ModalTreeNodeView extends PureComponent<{
|
||||
export default class TreeNodeView extends PureComponent<{
|
||||
treeNode: TreeNode;
|
||||
isModal?: boolean;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
isRootNode?: boolean;
|
||||
}> {
|
||||
state: {
|
||||
@ -134,8 +134,8 @@ export default class TreeNodeView extends PureComponent<{
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { treeNode, pluginContext } = this.props;
|
||||
const { project } = pluginContext;
|
||||
const { treeNode } = this.props;
|
||||
const { project } = treeNode.pluginContext;
|
||||
|
||||
const doc = project.currentDocument;
|
||||
|
||||
@ -178,14 +178,14 @@ export default class TreeNodeView extends PureComponent<{
|
||||
}
|
||||
|
||||
shouldShowModalTreeNode(): boolean {
|
||||
const { treeNode, isRootNode, pluginContext } = this.props;
|
||||
const { treeNode, isRootNode } = this.props;
|
||||
if (!isRootNode) {
|
||||
// 只在 当前树 的根节点展示模态节点
|
||||
return false;
|
||||
}
|
||||
|
||||
// 当指定了新的根节点时,要从原始的根节点去获取模态节点
|
||||
const { project } = pluginContext;
|
||||
const { project } = treeNode.pluginContext;
|
||||
const rootNode = project.currentDocument?.root;
|
||||
const rootTreeNode = treeNode.tree.getTreeNode(rootNode!);
|
||||
const modalNodes = rootTreeNode.children?.filter((item) => {
|
||||
@ -234,19 +234,16 @@ export default class TreeNodeView extends PureComponent<{
|
||||
hidden={this.state.hidden}
|
||||
locked={this.state.locked}
|
||||
expandable={this.state.expandable}
|
||||
pluginContext={this.props.pluginContext}
|
||||
/>
|
||||
{shouldShowModalTreeNode &&
|
||||
<ModalTreeNodeView
|
||||
treeNode={treeNode}
|
||||
pluginContext={this.props.pluginContext}
|
||||
/>
|
||||
}
|
||||
<TreeBranches
|
||||
treeNode={treeNode}
|
||||
isModal={false}
|
||||
expanded={this.state.expanded}
|
||||
pluginContext={this.props.pluginContext}
|
||||
treeChildren={this.state.treeChildren}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { KeyboardEvent, FocusEvent, Fragment, PureComponent } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { createIcon } from '@alilc/lowcode-utils';
|
||||
import { IPublicModelPluginContext, IPublicApiEvent } from '@alilc/lowcode-types';
|
||||
import { IPublicApiEvent } from '@alilc/lowcode-types';
|
||||
import TreeNode from '../controllers/tree-node';
|
||||
import { IconLock, IconUnlock, IconArrowRight, IconEyeClose, IconEye, IconCond, IconLoop, IconRadioActive, IconRadio, IconSetting } from '../icons';
|
||||
|
||||
@ -23,7 +23,6 @@ export default class TreeTitle extends PureComponent<{
|
||||
hidden: boolean;
|
||||
locked: boolean;
|
||||
expandable: boolean;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
}> {
|
||||
state: {
|
||||
editing: boolean;
|
||||
@ -53,7 +52,7 @@ export default class TreeTitle extends PureComponent<{
|
||||
const { treeNode } = this.props;
|
||||
const value = (e.target as HTMLInputElement).value || '';
|
||||
treeNode.setTitleLabel(value);
|
||||
emitOutlineEvent(this.props.pluginContext.event, 'rename', treeNode, { value });
|
||||
emitOutlineEvent(this.props.treeNode.pluginContext.event, 'rename', treeNode, { value });
|
||||
this.cancelEdit();
|
||||
};
|
||||
|
||||
@ -90,7 +89,8 @@ export default class TreeTitle extends PureComponent<{
|
||||
}
|
||||
|
||||
render() {
|
||||
const { treeNode, isModal, pluginContext } = this.props;
|
||||
const { treeNode, isModal } = this.props;
|
||||
const { pluginContext } = treeNode;
|
||||
const { editing } = this.state;
|
||||
const isCNode = !treeNode.isRoot();
|
||||
const { node } = treeNode;
|
||||
@ -153,7 +153,7 @@ export default class TreeTitle extends PureComponent<{
|
||||
<IconRadio className="tree-node-modal-radio" />
|
||||
</div>
|
||||
)}
|
||||
{isCNode && <ExpandBtn expandable={this.props.expandable} expanded={this.props.expanded} treeNode={treeNode} pluginContext={this.props.pluginContext} />}
|
||||
{isCNode && <ExpandBtn expandable={this.props.expandable} expanded={this.props.expanded} treeNode={treeNode} />}
|
||||
<div className="tree-node-icon">{createIcon(treeNode.icon)}</div>
|
||||
<div className="tree-node-title-label">
|
||||
{editing ? (
|
||||
@ -166,6 +166,7 @@ export default class TreeTitle extends PureComponent<{
|
||||
/>
|
||||
) : (
|
||||
<Fragment>
|
||||
{/* @ts-ignore */}
|
||||
<Title
|
||||
title={this.state.title}
|
||||
match={filterWorking && matchSelf}
|
||||
@ -175,6 +176,7 @@ export default class TreeTitle extends PureComponent<{
|
||||
{node.slotFor && (
|
||||
<a className="tree-node-tag slot">
|
||||
{/* todo: click redirect to prop */}
|
||||
{/* @ts-ignore */}
|
||||
<Tip>{intlNode('Slot for {prop}', { prop: node.slotFor.key })}</Tip>
|
||||
</a>
|
||||
)}
|
||||
@ -182,6 +184,7 @@ export default class TreeTitle extends PureComponent<{
|
||||
<a className="tree-node-tag loop">
|
||||
{/* todo: click todo something */}
|
||||
<IconLoop />
|
||||
{/* @ts-ignore */}
|
||||
<Tip>{intlNode('Loop')}</Tip>
|
||||
</a>
|
||||
)}
|
||||
@ -189,15 +192,16 @@ export default class TreeTitle extends PureComponent<{
|
||||
<a className="tree-node-tag cond">
|
||||
{/* todo: click todo something */}
|
||||
<IconCond />
|
||||
{/* @ts-ignore */}
|
||||
<Tip>{intlNode('Conditional')}</Tip>
|
||||
</a>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
{shouldShowHideBtn && <HideBtn hidden={this.props.hidden} treeNode={treeNode} pluginContext={this.props.pluginContext} />}
|
||||
{shouldShowLockBtn && <LockBtn locked={this.props.locked} treeNode={treeNode} pluginContext={this.props.pluginContext} />}
|
||||
{shouldEditBtn && <RenameBtn treeNode={treeNode} pluginContext={this.props.pluginContext} onClick={this.enableEdit} /> }
|
||||
{shouldShowHideBtn && <HideBtn hidden={this.props.hidden} treeNode={treeNode} />}
|
||||
{shouldShowLockBtn && <LockBtn locked={this.props.locked} treeNode={treeNode} />}
|
||||
{shouldEditBtn && <RenameBtn treeNode={treeNode} onClick={this.enableEdit} /> }
|
||||
|
||||
</div>
|
||||
);
|
||||
@ -206,11 +210,10 @@ export default class TreeTitle extends PureComponent<{
|
||||
|
||||
class RenameBtn extends PureComponent<{
|
||||
treeNode: TreeNode;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
onClick: (e: any) => void;
|
||||
}> {
|
||||
render() {
|
||||
const { intl, common } = this.props.pluginContext;
|
||||
const { intl, common } = this.props.treeNode.pluginContext;
|
||||
const Tip = common.editorCabin.Tip;
|
||||
return (
|
||||
<div
|
||||
@ -218,6 +221,7 @@ class RenameBtn extends PureComponent<{
|
||||
onClick={this.props.onClick}
|
||||
>
|
||||
<IconSetting />
|
||||
{/* @ts-ignore */}
|
||||
<Tip>{intl('Rename')}</Tip>
|
||||
</div>
|
||||
);
|
||||
@ -226,12 +230,11 @@ class RenameBtn extends PureComponent<{
|
||||
|
||||
class LockBtn extends PureComponent<{
|
||||
treeNode: TreeNode;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
locked: boolean;
|
||||
}> {
|
||||
render() {
|
||||
const { treeNode, locked } = this.props;
|
||||
const { intl, common } = this.props.pluginContext;
|
||||
const { intl, common } = this.props.treeNode.pluginContext;
|
||||
const Tip = common.editorCabin.Tip;
|
||||
return (
|
||||
<div
|
||||
@ -242,6 +245,7 @@ class LockBtn extends PureComponent<{
|
||||
}}
|
||||
>
|
||||
{locked ? <IconUnlock /> : <IconLock /> }
|
||||
{/* @ts-ignore */}
|
||||
<Tip>{locked ? intl('Unlock') : intl('Lock')}</Tip>
|
||||
</div>
|
||||
);
|
||||
@ -251,24 +255,24 @@ class LockBtn extends PureComponent<{
|
||||
class HideBtn extends PureComponent<{
|
||||
treeNode: TreeNode;
|
||||
hidden: boolean;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
}, {
|
||||
hidden: boolean;
|
||||
}> {
|
||||
render() {
|
||||
const { treeNode, hidden } = this.props;
|
||||
const { intl, common } = this.props.pluginContext;
|
||||
const { intl, common } = treeNode.pluginContext;
|
||||
const Tip = common.editorCabin.Tip;
|
||||
return (
|
||||
<div
|
||||
className="tree-node-hide-btn"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
emitOutlineEvent(this.props.pluginContext.event, hidden ? 'show' : 'hide', treeNode);
|
||||
emitOutlineEvent(treeNode.pluginContext.event, hidden ? 'show' : 'hide', treeNode);
|
||||
treeNode.setHidden(!hidden);
|
||||
}}
|
||||
>
|
||||
{hidden ? <IconEye /> : <IconEyeClose />}
|
||||
{/* @ts-ignore */}
|
||||
<Tip>{hidden ? intl('Show') : intl('Hide')}</Tip>
|
||||
</div>
|
||||
);
|
||||
@ -277,7 +281,6 @@ class HideBtn extends PureComponent<{
|
||||
|
||||
class ExpandBtn extends PureComponent<{
|
||||
treeNode: TreeNode;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
expanded: boolean;
|
||||
expandable: boolean;
|
||||
}> {
|
||||
@ -294,7 +297,7 @@ class ExpandBtn extends PureComponent<{
|
||||
if (expanded) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
emitOutlineEvent(this.props.pluginContext.event, expanded ? 'collapse' : 'expand', treeNode);
|
||||
emitOutlineEvent(treeNode.pluginContext.event, expanded ? 'collapse' : 'expand', treeNode);
|
||||
treeNode.setExpanded(!expanded);
|
||||
}}
|
||||
>
|
||||
|
||||
@ -2,7 +2,7 @@ import { MouseEvent as ReactMouseEvent, PureComponent } from 'react';
|
||||
import { isFormEvent, canClickNode, isShaken } from '@alilc/lowcode-utils';
|
||||
import { Tree } from '../controllers/tree';
|
||||
import TreeNodeView from './tree-node';
|
||||
import { IPublicEnumDragObjectType, IPublicModelPluginContext, IPublicModelNode } from '@alilc/lowcode-types';
|
||||
import { IPublicEnumDragObjectType, IPublicModelNode } from '@alilc/lowcode-types';
|
||||
import TreeNode from '../controllers/tree-node';
|
||||
|
||||
function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string {
|
||||
@ -20,12 +20,21 @@ function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string
|
||||
|
||||
export default class TreeView extends PureComponent<{
|
||||
tree: Tree;
|
||||
pluginContext: IPublicModelPluginContext;
|
||||
}> {
|
||||
private shell: HTMLDivElement | null = null;
|
||||
|
||||
private ignoreUpSelected = false;
|
||||
|
||||
private boostEvent?: MouseEvent;
|
||||
|
||||
state: {
|
||||
root: TreeNode | null;
|
||||
} = {
|
||||
root: null,
|
||||
};
|
||||
|
||||
private hover(e: ReactMouseEvent) {
|
||||
const { project } = this.props.pluginContext;
|
||||
const { project } = this.props.tree.pluginContext;
|
||||
const detecting = project.currentDocument?.detecting;
|
||||
if (detecting?.enable) {
|
||||
return;
|
||||
@ -54,7 +63,7 @@ export default class TreeView extends PureComponent<{
|
||||
return;
|
||||
}
|
||||
|
||||
const { project, event, canvas } = this.props.pluginContext;
|
||||
const { project, event, canvas } = this.props.tree.pluginContext;
|
||||
const doc = project.currentDocument;
|
||||
const selection = doc?.selection;
|
||||
const focusNode = doc?.focusNode;
|
||||
@ -109,10 +118,6 @@ export default class TreeView extends PureComponent<{
|
||||
return tree.getTreeNodeById(id);
|
||||
}
|
||||
|
||||
private ignoreUpSelected = false;
|
||||
|
||||
private boostEvent?: MouseEvent;
|
||||
|
||||
private onMouseDown = (e: ReactMouseEvent) => {
|
||||
if (isFormEvent(e.nativeEvent)) {
|
||||
return;
|
||||
@ -127,7 +132,7 @@ export default class TreeView extends PureComponent<{
|
||||
if (!canClickNode(node, e)) {
|
||||
return;
|
||||
}
|
||||
const { project, canvas } = this.props.pluginContext;
|
||||
const { project, canvas } = this.props.tree.pluginContext;
|
||||
const selection = project.currentDocument?.selection;
|
||||
const focusNode = project.currentDocument?.focusNode;
|
||||
|
||||
@ -166,22 +171,16 @@ export default class TreeView extends PureComponent<{
|
||||
};
|
||||
|
||||
private onMouseLeave = () => {
|
||||
const { pluginContext } = this.props;
|
||||
const { pluginContext } = this.props.tree;
|
||||
const { project } = pluginContext;
|
||||
const doc = project.currentDocument;
|
||||
doc?.detecting.leave();
|
||||
};
|
||||
|
||||
state: {
|
||||
root: TreeNode | null
|
||||
} = {
|
||||
root: null,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { tree, pluginContext } = this.props;
|
||||
const { tree } = this.props;
|
||||
const { root } = tree;
|
||||
const { project } = pluginContext;
|
||||
const { project } = tree.pluginContext;
|
||||
this.setState({ root });
|
||||
const doc = project.currentDocument;
|
||||
doc?.onFocusNodeChanged(() => {
|
||||
@ -208,7 +207,6 @@ export default class TreeView extends PureComponent<{
|
||||
<TreeNodeView
|
||||
key={this.state.root?.id}
|
||||
treeNode={this.state.root}
|
||||
pluginContext={this.props.pluginContext}
|
||||
isRootNode
|
||||
/>
|
||||
</div>
|
||||
|
||||
27
packages/shell/src/model/editor-view.ts
Normal file
27
packages/shell/src/model/editor-view.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { editorViewSymbol, pluginContextSymbol } from '../symbols';
|
||||
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
|
||||
import { IViewContext } from '@alilc/lowcode-workspace';
|
||||
|
||||
export class EditorView {
|
||||
[editorViewSymbol]: IViewContext;
|
||||
|
||||
[pluginContextSymbol]: IPublicModelPluginContext;
|
||||
|
||||
constructor(editorView: IViewContext) {
|
||||
this[editorViewSymbol] = editorView;
|
||||
this[pluginContextSymbol] = this[editorViewSymbol].innerPlugins._getLowCodePluginContext({
|
||||
pluginName: '',
|
||||
});
|
||||
}
|
||||
|
||||
toProxy() {
|
||||
return new Proxy(this, {
|
||||
get(target, prop, receiver) {
|
||||
if ((target[pluginContextSymbol] as any)[prop as string]) {
|
||||
return Reflect.get(target[pluginContextSymbol], prop, receiver);
|
||||
}
|
||||
return Reflect.get(target, prop, receiver);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -19,3 +19,4 @@ export * from './active-tracker';
|
||||
export * from './plugin-instance';
|
||||
export * from './window';
|
||||
export * from './clipboard';
|
||||
export * from './editor-view';
|
||||
|
||||
@ -2,6 +2,7 @@ import { windowSymbol } from '../symbols';
|
||||
import { IPublicModelResource, IPublicModelWindow, IPublicTypeDisposable } from '@alilc/lowcode-types';
|
||||
import { IEditorWindow } from '@alilc/lowcode-workspace';
|
||||
import { Resource as ShellResource } from './resource';
|
||||
import { EditorView } from './editor-view';
|
||||
|
||||
export class Window implements IPublicModelWindow {
|
||||
private readonly [windowSymbol]: IEditorWindow;
|
||||
@ -42,7 +43,11 @@ export class Window implements IPublicModelWindow {
|
||||
return await this[windowSymbol].save();
|
||||
}
|
||||
|
||||
get plugins() {
|
||||
return this[windowSymbol].plugins;
|
||||
get currentEditorView() {
|
||||
return new EditorView(this[windowSymbol].editorView).toProxy() as any;
|
||||
}
|
||||
|
||||
get editorViews() {
|
||||
return Array.from(this[windowSymbol].editorViews.values()).map(d => new EditorView(d).toProxy() as any);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,3 +34,5 @@ export const resourceSymbol = Symbol('resource');
|
||||
export const clipboardSymbol = Symbol('clipboard');
|
||||
export const configSymbol = Symbol('configSymbol');
|
||||
export const conditionGroupSymbol = Symbol('conditionGroup');
|
||||
export const editorViewSymbol = Symbol('editorView');
|
||||
export const pluginContextSymbol = Symbol('pluginContext');
|
||||
@ -3,3 +3,4 @@ export * from './transition-type';
|
||||
export * from './transform-stage';
|
||||
export * from './drag-object-type';
|
||||
export * from './prop-value-changed-type';
|
||||
export * from './plugin-register-level';
|
||||
6
packages/types/src/shell/enum/plugin-register-level.ts
Normal file
6
packages/types/src/shell/enum/plugin-register-level.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export enum IPublicEnumPluginRegisterLevel {
|
||||
Default = 'default',
|
||||
Workspace = 'workspace',
|
||||
Resource = 'resource',
|
||||
EditorView = 'editorView',
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/* eslint-disable max-len */
|
||||
import { IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type';
|
||||
import { IPublicTypeDisposable, IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type';
|
||||
import { IPublicModelDragObject, IPublicModelLocateEvent, IPublicModelNode } from './';
|
||||
|
||||
export interface IPublicModelDragon<
|
||||
@ -19,7 +19,7 @@ export interface IPublicModelDragon<
|
||||
* @param func
|
||||
* @returns
|
||||
*/
|
||||
onDragstart(func: (e: LocateEvent) => any): () => void;
|
||||
onDragstart(func: (e: LocateEvent) => any): IPublicTypeDisposable;
|
||||
|
||||
/**
|
||||
* 绑定 drag 事件
|
||||
@ -27,7 +27,7 @@ export interface IPublicModelDragon<
|
||||
* @param func
|
||||
* @returns
|
||||
*/
|
||||
onDrag(func: (e: LocateEvent) => any): () => void;
|
||||
onDrag(func: (e: LocateEvent) => any): IPublicTypeDisposable;
|
||||
|
||||
/**
|
||||
* 绑定 dragend 事件
|
||||
@ -35,7 +35,7 @@ export interface IPublicModelDragon<
|
||||
* @param func
|
||||
* @returns
|
||||
*/
|
||||
onDragend(func: (o: { dragObject: IPublicModelDragObject; copy?: boolean }) => any): () => void;
|
||||
onDragend(func: (o: { dragObject: IPublicModelDragObject; copy?: boolean }) => any): IPublicTypeDisposable;
|
||||
|
||||
/**
|
||||
* 设置拖拽监听的区域 shell,以及自定义拖拽转换函数 boost
|
||||
|
||||
3
packages/types/src/shell/model/editor-view.ts
Normal file
3
packages/types/src/shell/model/editor-view.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { IPublicModelPluginContext } from './plugin-context';
|
||||
|
||||
export interface IPublicModelEditorView extends IPublicModelPluginContext {}
|
||||
@ -30,3 +30,4 @@ export * from './sensor';
|
||||
export * from './resource';
|
||||
export * from './clipboard';
|
||||
export * from './setting-field';
|
||||
export * from './editor-view';
|
||||
|
||||
@ -12,18 +12,11 @@ import {
|
||||
IPublicApiPlugins,
|
||||
IPublicApiWorkspace,
|
||||
} from '../api';
|
||||
import { IPublicEnumPluginRegisterLevel } from '../enum';
|
||||
import { IPublicModelEngineConfig } from './';
|
||||
|
||||
export interface IPublicModelPluginContext {
|
||||
|
||||
/**
|
||||
* 对于插件开发者来说,可以在 context 挂载自定义的内容,作为插件内全局上下文使用
|
||||
*
|
||||
* for plugin developers, costom properties can be add to plugin context
|
||||
* from inside plugin for convenience.
|
||||
*/
|
||||
[key: string]: any;
|
||||
|
||||
/**
|
||||
* 可通过该对象读取插件初始化配置
|
||||
* by using this, init options can be accessed from inside plugin
|
||||
@ -108,6 +101,12 @@ export interface IPublicModelPluginContext {
|
||||
* @tutorial https://lowcode-engine.cn/site/docs/api/workspace
|
||||
*/
|
||||
get workspace(): IPublicApiWorkspace;
|
||||
|
||||
/**
|
||||
* 插件注册层级
|
||||
* @since v1.1.7
|
||||
*/
|
||||
get registerLevel(): IPublicEnumPluginRegisterLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { ReactElement } from 'react';
|
||||
import { IPublicTypeDisposable, IPublicTypeNodeSchema } from '../type';
|
||||
import { IPublicModelResource } from './resource';
|
||||
import { IPublicModelEditorView } from './editor-view';
|
||||
|
||||
export interface IPublicModelWindow<
|
||||
Resource = IPublicModelResource
|
||||
@ -18,6 +19,18 @@ export interface IPublicModelWindow<
|
||||
/** 窗口资源类型 */
|
||||
resource?: Resource;
|
||||
|
||||
/**
|
||||
* 窗口当前视图
|
||||
* @since v1.1.7
|
||||
*/
|
||||
currentEditorView: IPublicModelEditorView;
|
||||
|
||||
/**
|
||||
* 窗口全部视图实例
|
||||
* @since v1.1.7
|
||||
*/
|
||||
editorViews: IPublicModelEditorView[];
|
||||
|
||||
/** 当前窗口导入 schema */
|
||||
importSchema(schema: IPublicTypeNodeSchema): void;
|
||||
|
||||
|
||||
@ -44,6 +44,7 @@ import {
|
||||
IPublicApiProject,
|
||||
IPublicApiSetters,
|
||||
IPublicApiSkeleton,
|
||||
IPublicEnumPluginRegisterLevel,
|
||||
IPublicModelPluginContext,
|
||||
IPublicTypePluginMeta,
|
||||
} from '@alilc/lowcode-types';
|
||||
@ -100,7 +101,7 @@ export class BasicContext implements IBasicContext {
|
||||
preference: IPluginPreferenceMananger;
|
||||
workspace: IWorkspace;
|
||||
|
||||
constructor(innerWorkspace: IWorkspace, viewName: string, public editorWindow?: IEditorWindow) {
|
||||
constructor(innerWorkspace: IWorkspace, viewName: string, registerLevel: IPublicEnumPluginRegisterLevel, public editorWindow?: IEditorWindow) {
|
||||
const editor = new Editor(viewName, true);
|
||||
|
||||
const innerSkeleton = new InnerSkeleton(editor, viewName);
|
||||
@ -168,6 +169,7 @@ export class BasicContext implements IBasicContext {
|
||||
if (editorWindow) {
|
||||
context.editorWindow = new Window(editorWindow);
|
||||
}
|
||||
context.registerLevel = registerLevel;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -1,12 +1,16 @@
|
||||
import { computed, makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||
import { IPublicEditorViewConfig, IPublicTypeEditorView } from '@alilc/lowcode-types';
|
||||
import { IPublicEditorViewConfig, IPublicEnumPluginRegisterLevel, IPublicTypeEditorView } from '@alilc/lowcode-types';
|
||||
import { flow } from 'mobx';
|
||||
import { IWorkspace } from '../workspace';
|
||||
import { BasicContext } from './base-context';
|
||||
import { BasicContext, IBasicContext } from './base-context';
|
||||
import { IEditorWindow } from '../window';
|
||||
import { getWebviewPlugin } from '../inner-plugins/webview';
|
||||
|
||||
export class Context extends BasicContext {
|
||||
export interface IViewContext extends IBasicContext {
|
||||
|
||||
}
|
||||
|
||||
export class Context extends BasicContext implements IViewContext {
|
||||
viewName = 'editor-view';
|
||||
|
||||
instance: IPublicEditorViewConfig;
|
||||
@ -30,7 +34,7 @@ export class Context extends BasicContext {
|
||||
});
|
||||
|
||||
constructor(public workspace: IWorkspace, public editorWindow: IEditorWindow, public editorView: IPublicTypeEditorView, options: Object | undefined) {
|
||||
super(workspace, editorView.viewName, editorWindow);
|
||||
super(workspace, editorView.viewName, IPublicEnumPluginRegisterLevel.EditorView, editorWindow);
|
||||
this.viewType = editorView.viewType || 'editor';
|
||||
this.viewName = editorView.viewName;
|
||||
this.instance = editorView(this.innerPlugins._getLowCodePluginContext({
|
||||
|
||||
@ -4,3 +4,4 @@ export * from './window';
|
||||
export * from './layouts/workbench';
|
||||
export { Resource } from './resource';
|
||||
export type { IResource } from './resource';
|
||||
export type { IViewContext } from './context/view-context';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ISkeleton } from '@alilc/lowcode-editor-skeleton';
|
||||
import { IPublicTypeEditorView, IPublicResourceData, IPublicResourceTypeConfig, IBaseModelResource } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeEditorView, IPublicResourceData, IPublicResourceTypeConfig, IBaseModelResource, IPublicEnumPluginRegisterLevel } from '@alilc/lowcode-types';
|
||||
import { Logger } from '@alilc/lowcode-utils';
|
||||
import { BasicContext, IBasicContext } from './context/base-context';
|
||||
import { ResourceType, IResourceType } from './resource-type';
|
||||
@ -75,7 +75,7 @@ export class Resource implements IResource {
|
||||
}
|
||||
|
||||
constructor(readonly resourceData: IPublicResourceData, readonly resourceType: IResourceType, readonly workspace: IWorkspace) {
|
||||
this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`);
|
||||
this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`, IPublicEnumPluginRegisterLevel.Resource);
|
||||
this.resourceTypeInstance = resourceType.resourceTypeModel(this.context.innerPlugins._getLowCodePluginContext({
|
||||
pluginName: '',
|
||||
}), this.options);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { uniqueId } from '@alilc/lowcode-utils';
|
||||
import { createModuleEventBus, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||
import { Context } from './context/view-context';
|
||||
import { Context, IViewContext } from './context/view-context';
|
||||
import { IWorkspace } from './workspace';
|
||||
import { IResource } from './resource';
|
||||
import { IPublicTypeDisposable } from '../../types/es/shell/type/disposable';
|
||||
@ -13,10 +13,12 @@ interface IWindowCOnfig {
|
||||
sleep?: boolean;
|
||||
}
|
||||
|
||||
export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'changeViewType'> {
|
||||
export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'changeViewType' | 'currentEditorView' | 'editorViews'> {
|
||||
readonly resource: IResource;
|
||||
|
||||
editorViews: Map<string, Context>;
|
||||
editorViews: Map<string, IViewContext>;
|
||||
|
||||
editorView: IViewContext;
|
||||
|
||||
changeViewType: (name: string, ignoreEmit?: boolean) => void;
|
||||
|
||||
@ -71,6 +73,9 @@ export class EditorWindow implements IEditorWindow {
|
||||
async save() {
|
||||
const value: any = {};
|
||||
const editorViews = this.resource.editorViews;
|
||||
if (!editorViews) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < editorViews.length; i++) {
|
||||
const name = editorViews[i].viewName;
|
||||
const saveResult = await this.editorViews.get(name)?.save();
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { IDesigner, ILowCodePluginManager, LowCodePluginManager } from '@alilc/lowcode-designer';
|
||||
import { createModuleEventBus, Editor, IEditor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core';
|
||||
import { IPublicApiPlugins, IPublicApiWorkspace, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types';
|
||||
import { IPublicApiPlugins, IPublicApiWorkspace, IPublicEnumPluginRegisterLevel, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types';
|
||||
import { BasicContext } from './context/base-context';
|
||||
import { EditorWindow } from './window';
|
||||
import type { IEditorWindow } from './window';
|
||||
@ -94,7 +94,7 @@ export class Workspace implements IWorkspace {
|
||||
readonly registryInnerPlugin: (designer: IDesigner, editor: IEditor, plugins: IPublicApiPlugins) => Promise<IPublicTypeDisposable>,
|
||||
readonly shellModelFactory: any,
|
||||
) {
|
||||
this.context = new BasicContext(this, '');
|
||||
this.context = new BasicContext(this, '', IPublicEnumPluginRegisterLevel.Workspace);
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user