From eeb6719a1ff1defff3b91a2f1455d0b7daaa252d Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 15 Mar 2023 16:17:18 +0800 Subject: [PATCH] feat: optimize outline tree performance and ts definition --- packages/designer/src/project/project.ts | 5 ++-- .../src/controllers/pane-controller.ts | 2 +- .../plugin-outline-pane/src/views/filter.tsx | 4 +-- .../plugin-outline-pane/src/views/pane.tsx | 4 +-- .../src/views/tree-branches.tsx | 23 ++++++++++------ .../src/views/tree-node.tsx | 8 +++--- .../src/views/tree-title.tsx | 15 +++++------ .../plugin-outline-pane/src/views/tree.tsx | 27 +++++++++++-------- packages/types/src/shell/api/common.ts | 10 ++++--- packages/types/src/shell/api/project.ts | 6 +++-- 10 files changed, 60 insertions(+), 44 deletions(-) diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 55ac584fb..51db678ad 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -5,14 +5,13 @@ import { IPublicTypeProjectSchema, IPublicTypeRootSchema, IPublicTypeComponentsMap, - IPublicApiProject, - IPublicModelDocumentModel, IPublicEnumTransformStage, + IBaseApiProject, } from '@alilc/lowcode-types'; import { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils'; import { ISimulatorHost } from '../simulator'; -export interface IProject extends Omit< IPublicApiProject< +export interface IProject extends Omit< IBaseApiProject< IDocumentModel >, 'simulatorHost' | diff --git a/packages/plugin-outline-pane/src/controllers/pane-controller.ts b/packages/plugin-outline-pane/src/controllers/pane-controller.ts index d3187687a..a02844ad1 100644 --- a/packages/plugin-outline-pane/src/controllers/pane-controller.ts +++ b/packages/plugin-outline-pane/src/controllers/pane-controller.ts @@ -444,7 +444,7 @@ export class PaneController implements IPublicModelSensor, ITreeBoard, IPublicTy event: e, detail: { type: IPublicTypeLocationDetailType.Children, - index: index + 1, + index: (index || 0) + 1, valid: document?.checkNesting(node.parent!, dragObject as any), near: { node, pos: 'after' }, focus: checkRecursion(focusNode, dragObject) ? { type: 'node', node: focusNode } : undefined, diff --git a/packages/plugin-outline-pane/src/views/filter.tsx b/packages/plugin-outline-pane/src/views/filter.tsx index d4fa792ae..166a5c8e2 100644 --- a/packages/plugin-outline-pane/src/views/filter.tsx +++ b/packages/plugin-outline-pane/src/views/filter.tsx @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React, { PureComponent } from 'react'; import './style.less'; import { IconFilter } from '../icons/filter'; 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 { IPublicModelPluginContext } from '@alilc/lowcode-types'; -export default class Filter extends Component<{ +export default class Filter extends PureComponent<{ tree: Tree; pluginContext: IPublicModelPluginContext; }, { diff --git a/packages/plugin-outline-pane/src/views/pane.tsx b/packages/plugin-outline-pane/src/views/pane.tsx index 4cee54a51..adaada786 100644 --- a/packages/plugin-outline-pane/src/views/pane.tsx +++ b/packages/plugin-outline-pane/src/views/pane.tsx @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React, { PureComponent } from 'react'; import { PaneController } from '../controllers/pane-controller'; import TreeView from './tree'; import './style.less'; @@ -6,7 +6,7 @@ import { IPublicModelPluginContext } from '@alilc/lowcode-types'; import Filter from './filter'; import { TreeMaster } from '../controllers/tree-master'; -export class Pane extends Component<{ +export class Pane extends PureComponent<{ config: any; pluginContext: IPublicModelPluginContext; treeMaster: TreeMaster; diff --git a/packages/plugin-outline-pane/src/views/tree-branches.tsx b/packages/plugin-outline-pane/src/views/tree-branches.tsx index d9b0f83a8..abbc5a840 100644 --- a/packages/plugin-outline-pane/src/views/tree-branches.tsx +++ b/packages/plugin-outline-pane/src/views/tree-branches.tsx @@ -1,10 +1,10 @@ -import { Component } from 'react'; +import { PureComponent } from 'react'; import classNames from 'classnames'; import TreeNode from '../controllers/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; isModal?: boolean; 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; isModal?: boolean; pluginContext: IPublicModelPluginContext; - }> { - state = { + }, ITreeNodeChildrenState> { + state: ITreeNodeChildrenState = { filterWorking: false, matchSelf: false, keywords: null, @@ -144,7 +151,7 @@ class TreeNodeChildren extends Component<{ /> ); treeNode.children?.forEach((child, index) => { - const childIsModal = child.node.componentMeta.isModal || false; + const childIsModal = child.node.componentMeta?.isModal || false; if (isModal != childIsModal) { return; } @@ -180,7 +187,7 @@ class TreeNodeChildren extends Component<{ } } -class TreeNodeSlots extends Component<{ +class TreeNodeSlots extends PureComponent<{ treeNode: TreeNode; pluginContext: IPublicModelPluginContext; }> { diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx index 213418fb9..1531eaf63 100644 --- a/packages/plugin-outline-pane/src/views/tree-node.tsx +++ b/packages/plugin-outline-pane/src/views/tree-node.tsx @@ -1,4 +1,4 @@ -import { Component } from 'react'; +import { PureComponent } from 'react'; import classNames from 'classnames'; import TreeNode from '../controllers/tree-node'; import TreeTitle from './tree-title'; @@ -6,7 +6,7 @@ import TreeBranches from './tree-branches'; import { IconEyeClose } from '../icons/eye-close'; import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicModelDocumentModel, IPublicTypeDisposable } from '@alilc/lowcode-types'; -class ModalTreeNodeView extends Component<{ +class ModalTreeNodeView extends PureComponent<{ treeNode: TreeNode; pluginContext: IPublicModelPluginContext; }> { @@ -59,11 +59,11 @@ class ModalTreeNodeView extends Component<{ } } -export default class TreeNodeView extends Component<{ +export default class TreeNodeView extends PureComponent<{ treeNode: TreeNode; isModal?: boolean; pluginContext: IPublicModelPluginContext; - isRootNode: boolean; + isRootNode?: boolean; }> { state = { expanded: false, diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 51d0fcf80..6e1b14a46 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -1,5 +1,4 @@ -/* eslint-disable max-len */ -import { Component, KeyboardEvent, FocusEvent, Fragment } from 'react'; +import { KeyboardEvent, FocusEvent, Fragment, PureComponent } from 'react'; import classNames from 'classnames'; import { createIcon } from '@alilc/lowcode-utils'; 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; isModal?: boolean; expanded: boolean; @@ -36,7 +35,7 @@ export default class TreeTitle extends Component<{ private lastInput?: HTMLInputElement; - private enableEdit = (e) => { + private enableEdit = (e: MouseEvent) => { e.preventDefault(); this.setState({ editing: true, @@ -205,7 +204,7 @@ export default class TreeTitle extends Component<{ } } -class RenameBtn extends Component<{ +class RenameBtn extends PureComponent<{ treeNode: TreeNode; pluginContext: IPublicModelPluginContext; onClick: (e: any) => void; @@ -225,7 +224,7 @@ class RenameBtn extends Component<{ } } -class LockBtn extends Component<{ +class LockBtn extends PureComponent<{ treeNode: TreeNode; pluginContext: IPublicModelPluginContext; locked: boolean; @@ -249,7 +248,7 @@ class LockBtn extends Component<{ } } -class HideBtn extends Component<{ +class HideBtn extends PureComponent<{ treeNode: TreeNode; hidden: boolean; pluginContext: IPublicModelPluginContext; @@ -276,7 +275,7 @@ class HideBtn extends Component<{ } } -class ExpandBtn extends Component<{ +class ExpandBtn extends PureComponent<{ treeNode: TreeNode; pluginContext: IPublicModelPluginContext; expanded: boolean; diff --git a/packages/plugin-outline-pane/src/views/tree.tsx b/packages/plugin-outline-pane/src/views/tree.tsx index 4eb1dbfee..930c65cce 100644 --- a/packages/plugin-outline-pane/src/views/tree.tsx +++ b/packages/plugin-outline-pane/src/views/tree.tsx @@ -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 { Tree } from '../controllers/tree'; import TreeNodeView from './tree-node'; import { IPublicEnumDragObjectType, IPublicModelPluginContext, IPublicModelNode } from '@alilc/lowcode-types'; +import TreeNode from '../controllers/tree-node'; function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string { 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; } -export default class TreeView extends Component<{ +export default class TreeView extends PureComponent<{ tree: Tree; pluginContext: IPublicModelPluginContext; }> { @@ -60,12 +61,12 @@ export default class TreeView extends Component<{ const { id } = node; const isMulti = e.metaKey || e.ctrlKey || e.shiftKey; 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)) { selection.remove(id); } } else { - selection.select(id); + selection?.select(id); const selectedNode = selection?.getNodes()?.[0]; const npm = selectedNode?.componentMeta?.npm; const selected = @@ -134,21 +135,23 @@ export default class TreeView extends Component<{ const isMulti = e.metaKey || e.ctrlKey || e.shiftKey; const isLeftButton = e.button === 0; - if (isLeftButton && !node.contains(focusNode)) { + if (isLeftButton && focusNode && !node.contains(focusNode)) { let nodes: IPublicModelNode[] = [node]; this.ignoreUpSelected = false; if (isMulti) { // multi select mode, directily add - if (!selection.has(node.id)) { + if (!selection?.has(node.id)) { canvas.activeTracker?.track(node); - selection.add(node.id); + selection?.add(node.id); this.ignoreUpSelected = true; } // todo: remove rootNodes id - selection.remove(focusNode.id); + selection?.remove(focusNode.id); // 获得顶层 nodes - nodes = selection.getTopNodes(); - } else if (selection.has(node.id)) { + if (selection) { + nodes = selection.getTopNodes(); + } + } else if (selection?.has(node.id)) { nodes = selection.getTopNodes(); } this.boostEvent = e.nativeEvent; @@ -169,7 +172,9 @@ export default class TreeView extends Component<{ doc?.detecting.leave(); }; - state = { + state: { + root: TreeNode | null + } = { root: null, }; diff --git a/packages/types/src/shell/api/common.ts b/packages/types/src/shell/api/common.ts index ceb85067f..d00a2468b 100644 --- a/packages/types/src/shell/api/common.ts +++ b/packages/types/src/shell/api/common.ts @@ -1,6 +1,6 @@ import { Component, ReactNode } from 'react'; -import { IPublicTypeNodeSchema } from '../type'; +import { IPublicTypeNodeSchema, IPublicTypeTitleContent } from '../type'; import { IPublicEnumTransitionType } from '../enum'; export interface IPublicApiCommonUtils { @@ -82,12 +82,16 @@ export interface IPublicApiCommonEditorCabin { * Title 组件 * @experimental unstable API, pay extra caution when trying to use this */ - get Tip(): Component; + get Tip(): React.FC<{}>; /** * Tip 组件 * @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 { diff --git a/packages/types/src/shell/api/project.ts b/packages/types/src/shell/api/project.ts index ead415e54..baea41b94 100644 --- a/packages/types/src/shell/api/project.ts +++ b/packages/types/src/shell/api/project.ts @@ -3,8 +3,8 @@ import { IPublicEnumTransformStage } from '../enum'; import { IPublicApiSimulatorHost } from './'; import { IPublicModelDocumentModel } from '../model'; -export interface IPublicApiProject< - DocumentModel = IPublicModelDocumentModel +export interface IBaseApiProject< + DocumentModel > { /** @@ -133,3 +133,5 @@ export interface IPublicApiProject< */ setI18n(value: object): void; } + +export interface IPublicApiProject extends IBaseApiProject {} \ No newline at end of file