import { Component, MouseEvent as ReactMouseEvent } from 'react'; import { observer, Editor, globalContext } from '@ali/lowcode-editor-core'; import { isRootNode, Node, DragObjectType, isShaken } from '@ali/lowcode-designer'; import { isFormEvent } from '@ali/lowcode-utils'; import { Tree } from '../tree'; import RootTreeNodeView from './root-tree-node'; function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string { let target: Element | null = e.target as Element; if (!target || !stop.contains(target)) { return null; } target = target.closest('[data-id]'); if (!target || !stop.contains(target)) { return null; } return (target as HTMLDivElement).dataset.id || null; } @observer export default class TreeView extends Component<{ tree: Tree }> { private shell: HTMLDivElement | null = null; private hover(e: ReactMouseEvent) { const { tree } = this.props; const doc = tree.document; const { detecting } = doc.designer; if (!detecting.enable) { return; } const node = this.getTreeNodeFromEvent(e)?.node; detecting.capture(node || null); } private onClick = (e: ReactMouseEvent) => { if (this.ignoreUpSelected) { this.boostEvent = undefined; return; } if (this.boostEvent && isShaken(this.boostEvent, e.nativeEvent)) { this.boostEvent = undefined; return; } this.boostEvent = undefined; const treeNode = this.getTreeNodeFromEvent(e); if (!treeNode) { return; } const { node } = treeNode; const { designer } = treeNode; const doc = node.document; const { selection } = doc; const { id } = node; const isMulti = e.metaKey || e.ctrlKey || e.shiftKey; designer.activeTracker.track(node); if (isMulti && !isRootNode(node) && selection.has(id)) { if (!isFormEvent(e.nativeEvent)) { selection.remove(id); } } else { selection.select(id); const editor = globalContext.get(Editor); const selectedNode = designer.currentSelection?.getNodes()?.[0]; const npm = selectedNode?.componentMeta?.npm; const selected = [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || selectedNode?.componentMeta?.componentName || ''; editor?.emit('outlinePane.select', { selected, }); } }; private onMouseOver = (e: ReactMouseEvent) => { this.hover(e); }; private getTreeNodeFromEvent(e: ReactMouseEvent) { if (!this.shell) { return; } const id = getTreeNodeIdByEvent(e, this.shell); if (!id) { return; } const { tree } = this.props; return tree.getTreeNodeById(id); } private ignoreUpSelected = false; private boostEvent?: MouseEvent; private onMouseDown = (e: ReactMouseEvent) => { if (isFormEvent(e.nativeEvent)) { return; } const treeNode = this.getTreeNodeFromEvent(e); if (!treeNode) { return; } const { node } = treeNode; const { designer } = treeNode; const doc = node.document; const { selection } = doc; // TODO: shift selection const isMulti = e.metaKey || e.ctrlKey || e.shiftKey; const isLeftButton = e.button === 0; if (isLeftButton && !isRootNode(node)) { let nodes: Node[] = [node]; this.ignoreUpSelected = false; if (isMulti) { // multi select mode, directily add if (!selection.has(node.id)) { designer.activeTracker.track(node); selection.add(node.id); this.ignoreUpSelected = true; } selection.remove(doc.rootNode.id); // 获得顶层 nodes nodes = selection.getTopNodes(); } else if (selection.has(node.id)) { nodes = selection.getTopNodes(); } this.boostEvent = e.nativeEvent; designer.dragon.boost( { type: DragObjectType.Node, nodes, }, this.boostEvent, ); } }; private onMouseLeave = () => { const { tree } = this.props; const doc = tree.document; doc.designer.detecting.leave(doc); }; render() { const { tree } = this.props; const { root } = tree; return (