feat: optimize outline tree performance and ts definition

This commit is contained in:
liujuping 2023-03-15 16:17:18 +08:00 committed by 林熠
parent 95a1137b46
commit eeb6719a1f
10 changed files with 60 additions and 44 deletions

View File

@ -5,14 +5,13 @@ import {
IPublicTypeProjectSchema, IPublicTypeProjectSchema,
IPublicTypeRootSchema, IPublicTypeRootSchema,
IPublicTypeComponentsMap, IPublicTypeComponentsMap,
IPublicApiProject,
IPublicModelDocumentModel,
IPublicEnumTransformStage, IPublicEnumTransformStage,
IBaseApiProject,
} from '@alilc/lowcode-types'; } from '@alilc/lowcode-types';
import { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils'; import { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils';
import { ISimulatorHost } from '../simulator'; import { ISimulatorHost } from '../simulator';
export interface IProject extends Omit< IPublicApiProject< export interface IProject extends Omit< IBaseApiProject<
IDocumentModel IDocumentModel
>, >,
'simulatorHost' | 'simulatorHost' |

View File

@ -444,7 +444,7 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTy
event: e, event: e,
detail: { detail: {
type: IPublicTypeLocationDetailType.Children, type: IPublicTypeLocationDetailType.Children,
index: index + 1, index: (index || 0) + 1,
valid: document?.checkNesting(node.parent!, dragObject as any), valid: document?.checkNesting(node.parent!, dragObject as any),
near: { node, pos: 'after' }, near: { node, pos: 'after' },
focus: checkRecursion(focusNode, dragObject) ? { type: 'node', node: focusNode } : undefined, focus: checkRecursion(focusNode, dragObject) ? { type: 'node', node: focusNode } : undefined,

View File

@ -1,4 +1,4 @@
import React, { Component } from 'react'; import React, { PureComponent } from 'react';
import './style.less'; import './style.less';
import { IconFilter } from '../icons/filter'; import { IconFilter } from '../icons/filter';
import { Search, Checkbox, Balloon, Divider } from '@alifd/next'; import { Search, Checkbox, Balloon, Divider } from '@alifd/next';
@ -7,7 +7,7 @@ import { Tree } from '../controllers/tree';
import { matchTreeNode, FILTER_OPTIONS } from './filter-tree'; import { matchTreeNode, FILTER_OPTIONS } from './filter-tree';
import { IPublicModelPluginContext } from '@alilc/lowcode-types'; import { IPublicModelPluginContext } from '@alilc/lowcode-types';
export default class Filter extends Component<{ export default class Filter extends PureComponent<{
tree: Tree; tree: Tree;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
}, { }, {

View File

@ -1,4 +1,4 @@
import React, { Component } from 'react'; import React, { PureComponent } from 'react';
import { PaneController } from '../controllers/pane-controller'; import { PaneController } from '../controllers/pane-controller';
import TreeView from './tree'; import TreeView from './tree';
import './style.less'; import './style.less';
@ -6,7 +6,7 @@ import { IPublicModelPluginContext } from '@alilc/lowcode-types';
import Filter from './filter'; import Filter from './filter';
import { TreeMaster } from '../controllers/tree-master'; import { TreeMaster } from '../controllers/tree-master';
export class Pane extends Component<{ export class Pane extends PureComponent<{
config: any; config: any;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
treeMaster: TreeMaster; treeMaster: TreeMaster;

View File

@ -1,10 +1,10 @@
import { Component } from 'react'; import { PureComponent } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import TreeNode from '../controllers/tree-node'; import TreeNode from '../controllers/tree-node';
import TreeNodeView from './tree-node'; import TreeNodeView from './tree-node';
import { IPublicModelPluginContext, IPublicModelExclusiveGroup, IPublicTypeDisposable } from '@alilc/lowcode-types'; import { IPublicModelPluginContext, IPublicModelExclusiveGroup, IPublicTypeDisposable, IPublicTypeLocationChildrenDetail } from '@alilc/lowcode-types';
export default class TreeBranches extends Component<{ export default class TreeBranches extends PureComponent<{
treeNode: TreeNode; treeNode: TreeNode;
isModal?: boolean; isModal?: boolean;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
@ -62,12 +62,19 @@ export default class TreeBranches extends Component<{
} }
} }
class TreeNodeChildren extends Component<{
interface ITreeNodeChildrenState {
filterWorking: boolean;
matchSelf: boolean;
keywords: string | null;
dropDetail: IPublicTypeLocationChildrenDetail | undefined | null;
}
class TreeNodeChildren extends PureComponent<{
treeNode: TreeNode; treeNode: TreeNode;
isModal?: boolean; isModal?: boolean;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
}> { }, ITreeNodeChildrenState> {
state = { state: ITreeNodeChildrenState = {
filterWorking: false, filterWorking: false,
matchSelf: false, matchSelf: false,
keywords: null, keywords: null,
@ -144,7 +151,7 @@ class TreeNodeChildren extends Component<{
/> />
); );
treeNode.children?.forEach((child, index) => { treeNode.children?.forEach((child, index) => {
const childIsModal = child.node.componentMeta.isModal || false; const childIsModal = child.node.componentMeta?.isModal || false;
if (isModal != childIsModal) { if (isModal != childIsModal) {
return; return;
} }
@ -180,7 +187,7 @@ class TreeNodeChildren extends Component<{
} }
} }
class TreeNodeSlots extends Component<{ class TreeNodeSlots extends PureComponent<{
treeNode: TreeNode; treeNode: TreeNode;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
}> { }> {

View File

@ -1,4 +1,4 @@
import { Component } from 'react'; import { PureComponent } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import TreeNode from '../controllers/tree-node'; import TreeNode from '../controllers/tree-node';
import TreeTitle from './tree-title'; import TreeTitle from './tree-title';
@ -6,7 +6,7 @@ import TreeBranches from './tree-branches';
import { IconEyeClose } from '../icons/eye-close'; import { IconEyeClose } from '../icons/eye-close';
import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicModelDocumentModel, IPublicTypeDisposable } from '@alilc/lowcode-types'; import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicModelDocumentModel, IPublicTypeDisposable } from '@alilc/lowcode-types';
class ModalTreeNodeView extends Component<{ class ModalTreeNodeView extends PureComponent<{
treeNode: TreeNode; treeNode: TreeNode;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
}> { }> {
@ -59,11 +59,11 @@ class ModalTreeNodeView extends Component<{
} }
} }
export default class TreeNodeView extends Component<{ export default class TreeNodeView extends PureComponent<{
treeNode: TreeNode; treeNode: TreeNode;
isModal?: boolean; isModal?: boolean;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
isRootNode: boolean; isRootNode?: boolean;
}> { }> {
state = { state = {
expanded: false, expanded: false,

View File

@ -1,5 +1,4 @@
/* eslint-disable max-len */ import { KeyboardEvent, FocusEvent, Fragment, PureComponent } from 'react';
import { Component, KeyboardEvent, FocusEvent, Fragment } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { createIcon } from '@alilc/lowcode-utils'; import { createIcon } from '@alilc/lowcode-utils';
import { IPublicModelPluginContext, IPublicApiEvent } from '@alilc/lowcode-types'; import { IPublicModelPluginContext, IPublicApiEvent } from '@alilc/lowcode-types';
@ -17,7 +16,7 @@ function emitOutlineEvent(event: IPublicApiEvent, type: string, treeNode: TreeNo
}); });
} }
export default class TreeTitle extends Component<{ export default class TreeTitle extends PureComponent<{
treeNode: TreeNode; treeNode: TreeNode;
isModal?: boolean; isModal?: boolean;
expanded: boolean; expanded: boolean;
@ -36,7 +35,7 @@ export default class TreeTitle extends Component<{
private lastInput?: HTMLInputElement; private lastInput?: HTMLInputElement;
private enableEdit = (e) => { private enableEdit = (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
this.setState({ this.setState({
editing: true, editing: true,
@ -205,7 +204,7 @@ export default class TreeTitle extends Component<{
} }
} }
class RenameBtn extends Component<{ class RenameBtn extends PureComponent<{
treeNode: TreeNode; treeNode: TreeNode;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
onClick: (e: any) => void; onClick: (e: any) => void;
@ -225,7 +224,7 @@ class RenameBtn extends Component<{
} }
} }
class LockBtn extends Component<{ class LockBtn extends PureComponent<{
treeNode: TreeNode; treeNode: TreeNode;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
locked: boolean; locked: boolean;
@ -249,7 +248,7 @@ class LockBtn extends Component<{
} }
} }
class HideBtn extends Component<{ class HideBtn extends PureComponent<{
treeNode: TreeNode; treeNode: TreeNode;
hidden: boolean; hidden: boolean;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
@ -276,7 +275,7 @@ class HideBtn extends Component<{
} }
} }
class ExpandBtn extends Component<{ class ExpandBtn extends PureComponent<{
treeNode: TreeNode; treeNode: TreeNode;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
expanded: boolean; expanded: boolean;

View File

@ -1,8 +1,9 @@
import { Component, MouseEvent as ReactMouseEvent } from 'react'; import { MouseEvent as ReactMouseEvent, PureComponent } from 'react';
import { isFormEvent, canClickNode, isShaken } from '@alilc/lowcode-utils'; import { isFormEvent, canClickNode, isShaken } from '@alilc/lowcode-utils';
import { Tree } from '../controllers/tree'; import { Tree } from '../controllers/tree';
import TreeNodeView from './tree-node'; import TreeNodeView from './tree-node';
import { IPublicEnumDragObjectType, IPublicModelPluginContext, IPublicModelNode } from '@alilc/lowcode-types'; import { IPublicEnumDragObjectType, IPublicModelPluginContext, IPublicModelNode } from '@alilc/lowcode-types';
import TreeNode from '../controllers/tree-node';
function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string { function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string {
let target: Element | null = e.target as Element; let target: Element | null = e.target as Element;
@ -17,7 +18,7 @@ function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string
return (target as HTMLDivElement).dataset.id || null; return (target as HTMLDivElement).dataset.id || null;
} }
export default class TreeView extends Component<{ export default class TreeView extends PureComponent<{
tree: Tree; tree: Tree;
pluginContext: IPublicModelPluginContext; pluginContext: IPublicModelPluginContext;
}> { }> {
@ -60,12 +61,12 @@ export default class TreeView extends Component<{
const { id } = node; const { id } = node;
const isMulti = e.metaKey || e.ctrlKey || e.shiftKey; const isMulti = e.metaKey || e.ctrlKey || e.shiftKey;
canvas.activeTracker?.track(node); canvas.activeTracker?.track(node);
if (isMulti && !node.contains(focusNode) && selection.has(id)) { if (isMulti && focusNode && !node.contains(focusNode) && selection?.has(id)) {
if (!isFormEvent(e.nativeEvent)) { if (!isFormEvent(e.nativeEvent)) {
selection.remove(id); selection.remove(id);
} }
} else { } else {
selection.select(id); selection?.select(id);
const selectedNode = selection?.getNodes()?.[0]; const selectedNode = selection?.getNodes()?.[0];
const npm = selectedNode?.componentMeta?.npm; const npm = selectedNode?.componentMeta?.npm;
const selected = const selected =
@ -134,21 +135,23 @@ export default class TreeView extends Component<{
const isMulti = e.metaKey || e.ctrlKey || e.shiftKey; const isMulti = e.metaKey || e.ctrlKey || e.shiftKey;
const isLeftButton = e.button === 0; const isLeftButton = e.button === 0;
if (isLeftButton && !node.contains(focusNode)) { if (isLeftButton && focusNode && !node.contains(focusNode)) {
let nodes: IPublicModelNode[] = [node]; let nodes: IPublicModelNode[] = [node];
this.ignoreUpSelected = false; this.ignoreUpSelected = false;
if (isMulti) { if (isMulti) {
// multi select mode, directily add // multi select mode, directily add
if (!selection.has(node.id)) { if (!selection?.has(node.id)) {
canvas.activeTracker?.track(node); canvas.activeTracker?.track(node);
selection.add(node.id); selection?.add(node.id);
this.ignoreUpSelected = true; this.ignoreUpSelected = true;
} }
// todo: remove rootNodes id // todo: remove rootNodes id
selection.remove(focusNode.id); selection?.remove(focusNode.id);
// 获得顶层 nodes // 获得顶层 nodes
nodes = selection.getTopNodes(); if (selection) {
} else if (selection.has(node.id)) { nodes = selection.getTopNodes();
}
} else if (selection?.has(node.id)) {
nodes = selection.getTopNodes(); nodes = selection.getTopNodes();
} }
this.boostEvent = e.nativeEvent; this.boostEvent = e.nativeEvent;
@ -169,7 +172,9 @@ export default class TreeView extends Component<{
doc?.detecting.leave(); doc?.detecting.leave();
}; };
state = { state: {
root: TreeNode | null
} = {
root: null, root: null,
}; };

View File

@ -1,6 +1,6 @@
import { Component, ReactNode } from 'react'; import { Component, ReactNode } from 'react';
import { IPublicTypeNodeSchema } from '../type'; import { IPublicTypeNodeSchema, IPublicTypeTitleContent } from '../type';
import { IPublicEnumTransitionType } from '../enum'; import { IPublicEnumTransitionType } from '../enum';
export interface IPublicApiCommonUtils { export interface IPublicApiCommonUtils {
@ -82,12 +82,16 @@ export interface IPublicApiCommonEditorCabin {
* Title * Title
* @experimental unstable API, pay extra caution when trying to use this * @experimental unstable API, pay extra caution when trying to use this
*/ */
get Tip(): Component; get Tip(): React.FC<{}>;
/** /**
* Tip * Tip
* @experimental unstable API, pay extra caution when trying to use this * @experimental unstable API, pay extra caution when trying to use this
*/ */
get Title(): Component; get Title(): React.FC<{
title: IPublicTypeTitleContent | undefined;
match?: boolean;
keywords?: string | null;
}>;
} }
export interface IPublicApiCommonDesignerCabin { export interface IPublicApiCommonDesignerCabin {

View File

@ -3,8 +3,8 @@ import { IPublicEnumTransformStage } from '../enum';
import { IPublicApiSimulatorHost } from './'; import { IPublicApiSimulatorHost } from './';
import { IPublicModelDocumentModel } from '../model'; import { IPublicModelDocumentModel } from '../model';
export interface IPublicApiProject< export interface IBaseApiProject<
DocumentModel = IPublicModelDocumentModel DocumentModel
> { > {
/** /**
@ -133,3 +133,5 @@ export interface IPublicApiProject<
*/ */
setI18n(value: object): void; setI18n(value: object): void;
} }
export interface IPublicApiProject extends IBaseApiProject<IPublicModelDocumentModel> {}