mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-13 01:21:58 +00:00
fix outline backup mode
This commit is contained in:
parent
e1d3f1e5a6
commit
f75a51e77e
@ -331,6 +331,12 @@ body {
|
||||
display: none;
|
||||
flex-shrink: 0;
|
||||
margin-left: 2px;
|
||||
position: relative;
|
||||
>.lc-panel {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
&.lc-area-visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@ -110,7 +110,7 @@ export class Skeleton {
|
||||
}
|
||||
return this.createPanel(config);
|
||||
},
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
);
|
||||
this.mainArea = new Area(
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { ReactElement, ComponentType } from 'react';
|
||||
import { TitleContent, IconType, I18nData, TipContent } from '@ali/lowcode-types';
|
||||
import { IWidget } from './widget/widget';
|
||||
|
||||
export interface IWidgetBaseConfig {
|
||||
type: string;
|
||||
@ -16,6 +17,7 @@ export interface WidgetConfig extends IWidgetBaseConfig {
|
||||
type: "Widget";
|
||||
props?: {
|
||||
align?: "left" | "right" | "bottom" | "center" | "top";
|
||||
onInit?: (widget: IWidget) => void;
|
||||
};
|
||||
content?: string | ReactElement | ComponentType<any>; // children
|
||||
}
|
||||
@ -47,6 +49,7 @@ export function isDividerConfig(obj: any): obj is DividerConfig {
|
||||
export interface IDockBaseConfig extends IWidgetBaseConfig {
|
||||
props?: DockProps & {
|
||||
align?: "left" | "right" | "bottom" | "center" | "top";
|
||||
onInit?: (widget: IWidget) => void;
|
||||
};
|
||||
}
|
||||
|
||||
@ -95,7 +98,8 @@ export interface PanelProps {
|
||||
height?: number; // panel.props
|
||||
maxWidth?: number; // panel.props
|
||||
maxHeight?: number; // panel.props
|
||||
onInit?: () => any;
|
||||
condition?: (widget: IWidget) => any;
|
||||
onInit?: (widget: IWidget) => any;
|
||||
onDestroy?: () => any;
|
||||
shortcut?: string; // 只有在特定位置,可触发 toggle show
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ export default class Dock implements IWidget {
|
||||
this._body = createElement(DockView, props);
|
||||
}
|
||||
this.inited = true;
|
||||
|
||||
|
||||
return this._body;
|
||||
}
|
||||
|
||||
@ -54,6 +54,9 @@ export default class Dock implements IWidget {
|
||||
const { props = {}, name } = config;
|
||||
this.name = name;
|
||||
this.align = props.align;
|
||||
if (props.onInit) {
|
||||
props.onInit.call(this, this);
|
||||
}
|
||||
}
|
||||
|
||||
setVisible(flag: boolean) {
|
||||
|
||||
@ -83,6 +83,9 @@ export default class PanelDock implements IWidget {
|
||||
area: panelProps?.area,
|
||||
}) as Panel;
|
||||
}
|
||||
if (props?.onInit) {
|
||||
props.onInit.call(this, this);
|
||||
}
|
||||
}
|
||||
|
||||
setVisible(flag: boolean) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { createElement, ReactNode } from 'react';
|
||||
import { obx } from '@ali/lowcode-editor-core';
|
||||
import { obx, computed } from '@ali/lowcode-editor-core';
|
||||
import { uniqueId, createContent } from '@ali/lowcode-utils';
|
||||
import { TitleContent } from '@ali/lowcode-types';
|
||||
import WidgetContainer from './widget-container';
|
||||
@ -16,14 +16,18 @@ export default class Panel implements IWidget {
|
||||
readonly name: string;
|
||||
readonly id: string;
|
||||
@obx.ref inited = false;
|
||||
@obx.ref private _actived = false;
|
||||
@obx.ref private _actived: boolean = false;
|
||||
private emitter = new EventEmitter();
|
||||
get actived(): boolean {
|
||||
return this._actived;
|
||||
}
|
||||
|
||||
get visible(): boolean {
|
||||
if (this.parent?.visible) {
|
||||
@computed get visible(): boolean {
|
||||
if (!this.parent || this.parent.visible) {
|
||||
const { props } = this.config;
|
||||
if (props?.condition) {
|
||||
return props.condition(this);
|
||||
}
|
||||
return this._actived;
|
||||
}
|
||||
return false;
|
||||
@ -80,6 +84,9 @@ export default class Panel implements IWidget {
|
||||
);
|
||||
content.forEach((item) => this.add(item));
|
||||
}
|
||||
if (props.onInit) {
|
||||
props.onInit.call(this, this);
|
||||
}
|
||||
// todo: process shortcut
|
||||
}
|
||||
|
||||
|
||||
@ -60,6 +60,9 @@ export default class Widget implements IWidget {
|
||||
const { props = {}, name } = config;
|
||||
this.name = name;
|
||||
this.align = props.align;
|
||||
if (props.onInit) {
|
||||
props.onInit.call(this, this);
|
||||
}
|
||||
}
|
||||
|
||||
getId() {
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import Pane from './views/pane';
|
||||
import { OutlinePane } from './views/pane';
|
||||
import { OutlineBackupPane } from './views/backup-pane';
|
||||
import { IconOutline } from './icons/outline';
|
||||
import { intlNode } from './locale';
|
||||
import { getTreeMaster } from './tree-master';
|
||||
|
||||
export default {
|
||||
name: 'outline-pane',
|
||||
@ -8,9 +10,7 @@ export default {
|
||||
icon: IconOutline,
|
||||
description: intlNode('Outline Tree'),
|
||||
},
|
||||
content: Pane,
|
||||
content: OutlinePane,
|
||||
};
|
||||
|
||||
export { getTreeMaster } from './main';
|
||||
|
||||
export { Pane };
|
||||
export { OutlinePane, OutlineBackupPane, getTreeMaster };
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { computed, obx, Editor } from '@ali/lowcode-editor-core';
|
||||
import { computed, obx } from '@ali/lowcode-editor-core';
|
||||
import {
|
||||
Designer,
|
||||
ISensor,
|
||||
@ -18,108 +17,15 @@ import {
|
||||
contains,
|
||||
Node,
|
||||
} from '@ali/lowcode-designer';
|
||||
import { Tree } from './tree';
|
||||
import TreeNode from './tree-node';
|
||||
import { IndentTrack } from './helper/indent-track';
|
||||
import DwellTimer from './helper/dwell-timer';
|
||||
import { uniqueId } from '@ali/lowcode-utils';
|
||||
import { Backup } from './views/backup-pane';
|
||||
import { IEditor } from '@ali/lowcode-types';
|
||||
import { ITreeBoard, TreeMaster, getTreeMaster } from './tree-master';
|
||||
|
||||
export interface IScrollBoard {
|
||||
scrollToNode(treeNode: TreeNode, detail?: any): void;
|
||||
}
|
||||
|
||||
class TreeMaster {
|
||||
private emitter = new EventEmitter();
|
||||
private currentFixed?: OutlineMain;
|
||||
constructor(readonly designer: Designer) {
|
||||
designer.dragon.onDragstart((e) => {
|
||||
const tree = this.currentTree;
|
||||
if (tree) {
|
||||
tree.document.selection.getTopNodes().forEach((node) => {
|
||||
tree.getTreeNode(node).setExpanded(false);
|
||||
});
|
||||
}
|
||||
if (!this.currentFixed) {
|
||||
this.emitter.emit('enable-builtin');
|
||||
}
|
||||
});
|
||||
designer.activeTracker.onChange(({ node, detail }) => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setFixed(entry: OutlineMain) {
|
||||
this.currentFixed = entry;
|
||||
}
|
||||
|
||||
unFixed(entry: OutlineMain) {
|
||||
if (entry === this.currentFixed) {
|
||||
this.currentFixed = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
onceEnableBuiltin(fn: () => void): () => void {
|
||||
this.emitter.once('enable-builtin', fn);
|
||||
return () => {
|
||||
this.emitter.removeListener('enable-builtin', fn);
|
||||
}
|
||||
}
|
||||
|
||||
private boards = new Set<IScrollBoard>();
|
||||
addBoard(board: IScrollBoard) {
|
||||
this.boards.add(board);
|
||||
}
|
||||
removeBoard(board: IScrollBoard) {
|
||||
this.boards.delete(board);
|
||||
}
|
||||
|
||||
purge() {
|
||||
this.emitter.removeAllListeners();
|
||||
// todo others purge
|
||||
}
|
||||
|
||||
private treeMap = new Map<string, Tree>();
|
||||
@computed get currentTree(): Tree | null {
|
||||
const doc = this.designer?.currentDocument;
|
||||
if (doc) {
|
||||
const id = doc.id;
|
||||
if (this.treeMap.has(id)) {
|
||||
return this.treeMap.get(id)!;
|
||||
}
|
||||
const tree = new Tree(doc);
|
||||
// TODO: listen purge event to remove
|
||||
this.treeMap.set(id, tree);
|
||||
return tree;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const mastersMap = new Map<Designer, TreeMaster>();
|
||||
export function getTreeMaster(designer: Designer): TreeMaster {
|
||||
let master = mastersMap.get(designer);
|
||||
if (!master) {
|
||||
master = new TreeMaster(designer);
|
||||
mastersMap.set(designer, master);
|
||||
}
|
||||
return master;
|
||||
}
|
||||
|
||||
export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
|
||||
export class OutlineMain implements ISensor, ITreeBoard, IScrollable {
|
||||
private _designer?: Designer;
|
||||
@obx.ref private _master?: TreeMaster;
|
||||
get master() {
|
||||
@ -130,8 +36,11 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
|
||||
}
|
||||
readonly id = uniqueId('outline');
|
||||
|
||||
private fixed = false;
|
||||
constructor(readonly editor: Editor, at?: string) {
|
||||
@obx.ref _visible: boolean = false;
|
||||
get visible() {
|
||||
return this._visible;
|
||||
}
|
||||
constructor(readonly editor: IEditor, readonly at: string | Symbol) {
|
||||
let inited = false;
|
||||
const setup = async () => {
|
||||
if (inited) {
|
||||
@ -142,29 +51,18 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
|
||||
this.setupDesigner(designer);
|
||||
};
|
||||
|
||||
// FIXME: dirty connect to others
|
||||
if (at === '__IN_SETTINGS__') {
|
||||
if (at === Backup) {
|
||||
setup();
|
||||
} else {
|
||||
editor.on('skeleton.panel.show', (key: string) => {
|
||||
if (key === at) {
|
||||
setup();
|
||||
if (this.master) {
|
||||
this.master.setFixed(this);
|
||||
} else {
|
||||
this.fixed = true;
|
||||
}
|
||||
document.documentElement.classList.add('lowcode-has-fixed-tree');
|
||||
this._visible = true;
|
||||
}
|
||||
});
|
||||
editor.on('skeleton.panel.hide', (key: string) => {
|
||||
if (key === at) {
|
||||
document.documentElement.classList.remove('lowcode-has-fixed-tree');
|
||||
if (this.master) {
|
||||
this.master.unFixed(this);
|
||||
} else {
|
||||
this.fixed = false;
|
||||
}
|
||||
this._visible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -628,9 +526,6 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
|
||||
this._designer = designer;
|
||||
this._master = getTreeMaster(designer);
|
||||
this._master.addBoard(this);
|
||||
if (this.fixed) {
|
||||
this._master.setFixed(this);
|
||||
}
|
||||
designer.dragon.addSensor(this);
|
||||
this.scroller = designer.createScroller(this);
|
||||
}
|
||||
|
||||
93
packages/plugin-outline-pane/src/tree-master.ts
Normal file
93
packages/plugin-outline-pane/src/tree-master.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import { computed, obx } from '@ali/lowcode-editor-core';
|
||||
import { Designer, isLocationChildrenDetail } from '@ali/lowcode-designer';
|
||||
import TreeNode from './tree-node';
|
||||
import { Tree } from './tree';
|
||||
import { Backup } from './views/backup-pane';
|
||||
|
||||
export interface ITreeBoard {
|
||||
readonly visible: boolean;
|
||||
readonly at: string | Symbol;
|
||||
scrollToNode(treeNode: TreeNode, detail?: any): void;
|
||||
}
|
||||
|
||||
export class TreeMaster {
|
||||
constructor(readonly designer: Designer) {
|
||||
designer.dragon.onDragstart(() => {
|
||||
// needs?
|
||||
this.toVision();
|
||||
});
|
||||
designer.activeTracker.onChange(({ node, detail }) => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private toVision() {
|
||||
const tree = this.currentTree;
|
||||
if (tree) {
|
||||
tree.document.selection.getTopNodes().forEach((node) => {
|
||||
tree.getTreeNode(node).setExpanded(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@obx.val private boards = new Set<ITreeBoard>();
|
||||
addBoard(board: ITreeBoard) {
|
||||
this.boards.add(board);
|
||||
}
|
||||
removeBoard(board: ITreeBoard) {
|
||||
this.boards.delete(board);
|
||||
}
|
||||
|
||||
@computed hasVisibleTreeBoard() {
|
||||
for (const item of this.boards) {
|
||||
if (item.visible && item.at !== Backup) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
purge() {
|
||||
// todo others purge
|
||||
}
|
||||
|
||||
private treeMap = new Map<string, Tree>();
|
||||
@computed get currentTree(): Tree | null {
|
||||
const doc = this.designer?.currentDocument;
|
||||
if (doc) {
|
||||
const id = doc.id;
|
||||
if (this.treeMap.has(id)) {
|
||||
return this.treeMap.get(id)!;
|
||||
}
|
||||
const tree = new Tree(doc);
|
||||
// TODO: listen purge event to remove
|
||||
this.treeMap.set(id, tree);
|
||||
return tree;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const mastersMap = new Map<Designer, TreeMaster>();
|
||||
export function getTreeMaster(designer: Designer): TreeMaster {
|
||||
let master = mastersMap.get(designer);
|
||||
if (!master) {
|
||||
master = new TreeMaster(designer);
|
||||
mastersMap.set(designer, master);
|
||||
}
|
||||
return master;
|
||||
}
|
||||
@ -1,28 +1,16 @@
|
||||
import { PureComponent } from 'react';
|
||||
import { PluginProps } from '@ali/lowcode-types';
|
||||
import OutlinePane from './pane';
|
||||
import { OutlinePane } from './pane';
|
||||
|
||||
export const Backup = Symbol.for('backup-outline');
|
||||
|
||||
export class OutlineBackupPane extends PureComponent<PluginProps> {
|
||||
state = {
|
||||
outlineInited: false,
|
||||
};
|
||||
private dispose = this.props.main.onceOutlineVisible(() => {
|
||||
this.setState({
|
||||
outlineInited: true,
|
||||
});
|
||||
});
|
||||
componentWillUnmount() {
|
||||
this.dispose();
|
||||
}
|
||||
render() {
|
||||
if (!this.state.outlineInited) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<OutlinePane
|
||||
editor={this.props.main.editor}
|
||||
editor={this.props.editor}
|
||||
config={{
|
||||
name: '__IN_SETTINGS__',
|
||||
name: Backup,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -4,13 +4,11 @@ import { intl } from '../locale';
|
||||
import { OutlineMain } from '../main';
|
||||
import TreeView from './tree';
|
||||
import './style.less';
|
||||
import { IEditor } from '@ali/lowcode-types';
|
||||
|
||||
@observer
|
||||
export default class OutlinePane extends Component<{ config: any; editor: any; inSettings?: boolean }> {
|
||||
private main = new OutlineMain(
|
||||
this.props.editor,
|
||||
this.props.config.name || this.props.config.pluginKey,
|
||||
);
|
||||
export class OutlinePane extends Component<{ config: any; editor: IEditor }> {
|
||||
private main = new OutlineMain(this.props.editor, this.props.config.name || this.props.config.pluginKey);
|
||||
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
z-index: 20;
|
||||
background-color: white;
|
||||
|
||||
> .lc-outline-tree-container {
|
||||
top: 0;
|
||||
|
||||
@ -139,8 +139,6 @@ export interface Utils {
|
||||
export interface PluginProps {
|
||||
editor: IEditor;
|
||||
config: PluginConfig;
|
||||
i18n?: I18nFunction;
|
||||
ref?: RefObject<ReactElement>;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
|
||||
@ -732,11 +732,9 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
||||
|
||||
const supports: any = {};
|
||||
if (canUseCondition != null) {
|
||||
console.info('canUseCondition', componentName);
|
||||
supports.condition = canUseCondition;
|
||||
}
|
||||
if (canLoop != null) {
|
||||
console.info('canLoop', componentName);
|
||||
supports.loop = canLoop;
|
||||
}
|
||||
meta.configure = { props, component, supports };
|
||||
|
||||
@ -2,7 +2,7 @@ import { isJSBlock, isJSExpression, isJSSlot } from '@ali/lowcode-types';
|
||||
import { isPlainObject } from '@ali/lowcode-utils';
|
||||
import { globalContext, Editor } from '@ali/lowcode-editor-core';
|
||||
import { Designer, TransformStage, addBuiltinComponentAction } from '@ali/lowcode-designer';
|
||||
import Outline from '@ali/lowcode-plugin-outline-pane';
|
||||
import Outline, { OutlineBackupPane, getTreeMaster } from '@ali/lowcode-plugin-outline-pane';
|
||||
import { toCss } from '@ali/vu-css-style';
|
||||
|
||||
import DesignerPlugin from '@ali/lowcode-plugin-designer';
|
||||
@ -16,9 +16,11 @@ globalContext.register(editor, Editor);
|
||||
|
||||
export const skeleton = new Skeleton(editor);
|
||||
editor.set(Skeleton, skeleton);
|
||||
editor.set('skeleton', skeleton);
|
||||
|
||||
export const designer = new Designer({ editor: editor });
|
||||
editor.set(Designer, designer);
|
||||
editor.set('designer', designer);
|
||||
|
||||
// 节点 props 初始化
|
||||
designer.addPropsReducer((props, node) => {
|
||||
@ -146,6 +148,17 @@ skeleton.add({
|
||||
area: 'leftFixedArea',
|
||||
},
|
||||
});
|
||||
skeleton.add({
|
||||
area: 'rightArea',
|
||||
name: 'backupOutline',
|
||||
type: 'Panel',
|
||||
props: {
|
||||
condition: () => {
|
||||
return designer.dragon.dragging && !getTreeMaster(designer).hasVisibleTreeBoard();
|
||||
}
|
||||
},
|
||||
content: OutlineBackupPane,
|
||||
});
|
||||
|
||||
// skeleton.add({
|
||||
// name: 'sourceEditor',
|
||||
|
||||
@ -59,8 +59,6 @@ function upgradeConfig(config: OldPaneConfig): IWidgetBaseConfig & { area: strin
|
||||
title,
|
||||
description,
|
||||
align: place,
|
||||
onInit: init,
|
||||
onDestroy: destroy,
|
||||
},
|
||||
contentProps: props,
|
||||
index: index || props?.index,
|
||||
@ -84,6 +82,8 @@ function upgradeConfig(config: OldPaneConfig): IWidgetBaseConfig & { area: strin
|
||||
maxWidth,
|
||||
height,
|
||||
maxHeight,
|
||||
onInit: init,
|
||||
onDestroy: destroy,
|
||||
};
|
||||
|
||||
if (contents && Array.isArray(contents)) {
|
||||
@ -100,18 +100,22 @@ function upgradeConfig(config: OldPaneConfig): IWidgetBaseConfig & { area: strin
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (type === 'action') {
|
||||
newConfig.area = 'top';
|
||||
newConfig.type = 'Dock';
|
||||
} else if (type === 'tab') {
|
||||
newConfig.area = 'right';
|
||||
newConfig.type = 'Panel';
|
||||
} else if (type === 'stage') {
|
||||
newConfig.area = 'stages';
|
||||
newConfig.type = 'Widget';
|
||||
} else {
|
||||
newConfig.area = 'main';
|
||||
newConfig.type = 'Widget';
|
||||
newConfig.props.onInit = init;
|
||||
newConfig.props.onDestroy = destroy;
|
||||
if (type === 'action') {
|
||||
newConfig.area = 'top';
|
||||
newConfig.type = 'Dock';
|
||||
} else if (type === 'tab') {
|
||||
newConfig.area = 'right';
|
||||
newConfig.type = 'Panel';
|
||||
} else if (type === 'stage') {
|
||||
newConfig.area = 'stages';
|
||||
newConfig.type = 'Widget';
|
||||
} else {
|
||||
newConfig.area = 'main';
|
||||
newConfig.type = 'Widget';
|
||||
}
|
||||
}
|
||||
|
||||
return newConfig;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user