diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx index e3e9089dc..fd3e8d6dd 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx @@ -80,6 +80,26 @@ export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> { if (!canHover || !current || host.viewport.scrolling || host.liveEditing.editing) { return null; } + + // rootNode, hover whole viewport + const focusNode = current.document.focusNode; + + if (current.contains(focusNode)) { + const bounds = host.viewport.bounds; + return ( + + ); + } else if (!focusNode.contains(current)) { + return null; + } + const instances = host.getComponentInstances(current); if (!instances || instances.length < 1) { return null; diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index efe00d474..1f002bcb4 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -540,7 +540,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost { - const parentNodes = []; + const parentNodes: any[] = []; + const focusNode = node.document.focusNode; + + if (node.contains(focusNode) || !focusNode.contains(node)) { + return parentNodes; + } + let currentNode: UnionNode = node; while (currentNode && parentNodes.length < 5) { @@ -39,6 +45,9 @@ export default class InstanceNodeSelector extends React.Component { - const nodes = this.state.parentNodes || []; + const nodes = this.state.parentNodes; + if (!nodes || nodes.length < 1) { + return null; + } const children = nodes.map((node, key) => { return (
Node; onMount?: (designer: Designer) => void; onDragstart?: (e: LocateEvent) => void; onDrag?: (e: LocateEvent) => void; @@ -328,19 +322,20 @@ export class Designer { target: activedDoc.rootNode as ParentalNode, }; } + const focusNode = activedDoc.focusNode; const nodes = activedDoc.selection.getNodes(); + const refNode = nodes.find(item => focusNode.contains(item)); let target; let index: number | undefined; - if (!nodes || nodes.length < 1) { - target = activedDoc.rootNode; + if (!refNode || refNode === focusNode) { + target = focusNode; } else { - const node = nodes[0]; - if (isRootNode(node) || node.componentMeta.isContainer) { - target = node; + if (refNode.componentMeta.isContainer) { + target = refNode; } else { // FIXME!!, parent maybe null - target = node.parent!; - index = node.index + 1; + target = refNode.parent!; + index = refNode.index + 1; } } diff --git a/packages/designer/src/designer/offset-observer.ts b/packages/designer/src/designer/offset-observer.ts index 7b4b8bebf..85dfca9db 100644 --- a/packages/designer/src/designer/offset-observer.ts +++ b/packages/designer/src/designer/offset-observer.ts @@ -105,7 +105,8 @@ export class OffsetObserver { this.node = node; const doc = node.document; const host = doc.simulator!; - this.isRoot = isRootNode(node); + const focusNode = doc.focusNode; + this.isRoot = node.contains(focusNode); this.viewport = host.viewport; if (this.isRoot) { this.hasOffset = true; diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 342e4d9db..0462952ea 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -93,6 +93,23 @@ export class DocumentModel { this.rootNode?.getExtraProp('fileName', true)?.setValue(fileName); } + @computed get focusNode() { + if (this._drillDownNode) { + return this._drillDownNode; + } + const selector = this.designer.get('focusNodeSelector'); + if (typeof selector === 'function') { + return selector(this.rootNode); + } + return this.rootNode; + } + + @obx.ref private _drillDownNode: Node | null = null; + + drillDown(node: Node | null) { + this._drillDownNode = node; + } + private _modalNode?: ParentalNode; private _blank?: boolean; @@ -151,7 +168,7 @@ export class DocumentModel { } get currentRoot() { - return this.modalNode || this.rootNode; + return this.modalNode || this.focusNode; } addWillPurge(node: Node) { @@ -346,6 +363,7 @@ export class DocumentModel { } import(schema: RootSchema, checkId = false) { + const drillDownNodeId = this._drillDownNode?.id; // TODO: 暂时用饱和式删除,原因是 Slot 节点并不是树节点,无法正常递归删除 this.nodes.forEach(node => { if (node.isRoot()) return; @@ -363,6 +381,9 @@ export class DocumentModel { } // todo: select added and active track added + if (drillDownNodeId) { + this.drillDown(this.getNode(drillDownNodeId)); + } } export(stage: TransformStage = TransformStage.Serilize) { diff --git a/packages/designer/src/document/selection.ts b/packages/designer/src/document/selection.ts index c62f4be08..3a1a416f8 100644 --- a/packages/designer/src/document/selection.ts +++ b/packages/designer/src/document/selection.ts @@ -102,7 +102,7 @@ export class Selection { containsNode(node: Node, excludeRoot = false) { for (const id of this._selected) { const parent = this.doc.getNode(id); - if (excludeRoot && parent === this.doc.rootNode) { + if (excludeRoot && parent?.contains(this.doc.focusNode)) { continue; } if (parent?.contains(node)) { @@ -134,7 +134,7 @@ export class Selection { for (const id of this._selected) { const node = this.doc.getNode(id); // 排除根节点 - if (!node || (!includeRoot && node === this.doc.rootNode)) { + if (!node || (!includeRoot && node.contains(this.doc.focusNode))) { continue; } let i = nodes.length; diff --git a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx index ec3aed989..5a8015d0b 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -64,13 +64,18 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor; config: any const designer = editor.get(Designer); const current = designer?.currentSelection?.getNodes()?.[0]; let node: Node | null = settings.first; + const focusNode = node.document.focusNode; + const items = []; let l = 3; while (l-- > 0 && node) { const _node = node; + // dirty code: should remove if (shouldIgnoreRoot && node.isRoot()) { - node = null; - continue; + break; + } + if (node.contains(focusNode)) { + l = 0; } const props = l === 2 diff --git a/packages/plugin-outline-pane/src/main.ts b/packages/plugin-outline-pane/src/main.ts index 6f2c74cef..383b3f7ad 100644 --- a/packages/plugin-outline-pane/src/main.ts +++ b/packages/plugin-outline-pane/src/main.ts @@ -164,7 +164,7 @@ export class OutlineMain implements ISensor, ITreeBoard, IScrollable { const componentMeta = e.dragObject.nodes ? e.dragObject.nodes[0].componentMeta : null; if (e.dragObject.type === 'node' && componentMeta && componentMeta.isModal) { return designer.createLocation({ - target: document.rootNode, + target: document.focusNode, detail: { type: LocationDetailType.Children, index: 0, @@ -229,7 +229,7 @@ export class OutlineMain implements ISensor, ITreeBoard, IScrollable { } } if (p !== node) { - node = p || document.rootNode; + node = p || document.focusNode; treeNode = tree.getTreeNode(node); focusSlots = false; } diff --git a/packages/plugin-outline-pane/src/tree.ts b/packages/plugin-outline-pane/src/tree.ts index a34bdfd21..bef37699d 100644 --- a/packages/plugin-outline-pane/src/tree.ts +++ b/packages/plugin-outline-pane/src/tree.ts @@ -1,18 +1,17 @@ import { DocumentModel, Node } from '@ali/lowcode-designer'; +import { computed } from '@ali/lowcode-editor-core'; import TreeNode from './tree-node'; export class Tree { private treeNodesMap = new Map(); - readonly root: TreeNode; - readonly id: string; - readonly document: DocumentModel; + @computed get root(): TreeNode { + return this.getTreeNode(this.document.focusNode); + } - constructor(document: DocumentModel) { - this.document = document; - this.root = this.getTreeNode(document.rootNode); + constructor(readonly document: DocumentModel) { this.id = document.id; } diff --git a/packages/plugin-outline-pane/src/views/tree.tsx b/packages/plugin-outline-pane/src/views/tree.tsx index 4f7871e96..f1b2c5c9b 100644 --- a/packages/plugin-outline-pane/src/views/tree.tsx +++ b/packages/plugin-outline-pane/src/views/tree.tsx @@ -51,11 +51,11 @@ export default class TreeView extends Component<{ tree: Tree }> { const { node } = treeNode; const { designer } = treeNode; const doc = node.document; - const { selection } = doc; + const { selection, focusNode } = doc; const { id } = node; const isMulti = e.metaKey || e.ctrlKey || e.shiftKey; designer.activeTracker.track(node); - if (isMulti && !isRootNode(node) && selection.has(id)) { + if (isMulti && !node.contains(focusNode) && selection.has(id)) { if (!isFormEvent(e.nativeEvent)) { selection.remove(id); } @@ -107,13 +107,13 @@ export default class TreeView extends Component<{ tree: Tree }> { const { node } = treeNode; const { designer } = treeNode; const doc = node.document; - const { selection } = doc; + const { selection, focusNode } = doc; // TODO: shift selection const isMulti = e.metaKey || e.ctrlKey || e.shiftKey; const isLeftButton = e.button === 0; - if (isLeftButton && !isRootNode(node)) { + if (isLeftButton && !node.contains(focusNode)) { let nodes: Node[] = [node]; this.ignoreUpSelected = false; if (isMulti) { @@ -123,7 +123,8 @@ export default class TreeView extends Component<{ tree: Tree }> { selection.add(node.id); this.ignoreUpSelected = true; } - selection.remove(doc.rootNode.id); + // todo: remove rootNodes id + selection.remove(focusNode.id); // 获得顶层 nodes nodes = selection.getTopNodes(); } else if (selection.has(node.id)) {