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 1f1735801..f86b00482 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-detecting.tsx @@ -76,6 +76,26 @@ export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> { if (!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 afea40812..166faa9d5 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -326,7 +326,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost detecting.leave(this.project.currentDocument); @@ -497,7 +507,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; @@ -209,6 +210,7 @@ export class Designer { } const currentSelection = this.currentSelection; // TODO: 避免选中 Page 组件,默认选中第一个子节点;新增规则 或 判断 Live 模式 + // dirty code, should remove if (currentSelection && currentSelection.selected.length === 0 && this.simulatorProps?.designMode === 'live') { const rootNodeChildrens = this.currentDocument.getRoot().getChildren().children; if (rootNodeChildrens.length > 0) { @@ -300,19 +302,20 @@ export class Designer { if (!activedDoc) { return null; } + 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 2346ecf25..bbcff7266 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -94,6 +94,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; @@ -143,7 +160,7 @@ export class DocumentModel { } get currentRoot() { - return this.modalNode || this.rootNode; + return this.modalNode || this.focusNode; } addWillPurge(node: Node) { @@ -338,6 +355,7 @@ export class DocumentModel { } import(schema: RootSchema, checkId = false) { + const drillDownNodeId = this._drillDownNode?.id; // TODO: 暂时用饱和式删除,原因是 Slot 节点并不是树节点,无法正常递归删除 this.nodes.forEach(node => { this.internalRemoveAndPurgeNode(node, true); @@ -347,6 +365,9 @@ export class DocumentModel { // }); this.rootNode?.import(schema as any, checkId); // 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 d9f9c0651..e47597892 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -58,13 +58,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 e4339ff9f..0a25667d9 100644 --- a/packages/plugin-outline-pane/src/main.ts +++ b/packages/plugin-outline-pane/src/main.ts @@ -161,7 +161,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, @@ -226,7 +226,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)) {