diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 784ebf57b..c72641d4c 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -288,6 +288,10 @@ export class Designer implements IDesigner { this.selectionDispose = currentSelection.onSelectionChange(() => { this.postEvent('selection.change', currentSelection); }); + + currentSelection.onSelectionPropsTabChange((tabKey) => { + this.postEvent('selection.changePropsTab', currentSelection, tabKey); + }); } }; diff --git a/packages/designer/src/document/selection.ts b/packages/designer/src/document/selection.ts index 6147e188d..958c6398c 100644 --- a/packages/designer/src/document/selection.ts +++ b/packages/designer/src/document/selection.ts @@ -42,6 +42,14 @@ export class Selection implements ISelection { this.emitter.emit('selectionchange', this._selected); } + /** + * 选中元素属性的指定tab + * @param tabKey + */ + selectPropsTab(tabKey: string) { + this.emitter.emit('selectionPropsTabChange', tabKey); + } + /** * 批量选中 */ @@ -187,4 +195,11 @@ export class Selection implements ISelection { this.emitter.removeListener('selectionchange', fn); }; } + + onSelectionPropsTabChange(fn: (tabKey: string) => void): () => void { + this.emitter.on('selectionPropsTabChange', fn); + return () => { + this.emitter.removeListener('selectionPropsTabChange', fn); + }; + } } 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 a68647ed0..fa54b76fc 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -39,6 +39,10 @@ export class SettingsPrimaryPane extends Component { + this._activeKey = tabKey; + }); } async setShouldIgnoreRoot() { diff --git a/packages/plugin-outline-pane/src/views/tree-branches.tsx b/packages/plugin-outline-pane/src/views/tree-branches.tsx index 41bd69481..db7a9fd57 100644 --- a/packages/plugin-outline-pane/src/views/tree-branches.tsx +++ b/packages/plugin-outline-pane/src/views/tree-branches.tsx @@ -1,4 +1,4 @@ -import { PureComponent } from 'react'; +import { MouseEvent as ReactMouseEvent, PureComponent } from 'react'; import classNames from 'classnames'; import TreeNode from '../controllers/tree-node'; import TreeNodeView from './tree-node'; @@ -9,6 +9,7 @@ export default class TreeBranches extends PureComponent<{ isModal?: boolean; expanded: boolean; treeChildren: TreeNode[] | null; + treeNodeClick?: (e: ReactMouseEvent, type?: string) => void; }> { state = { filterWorking: false, @@ -38,11 +39,10 @@ export default class TreeBranches extends PureComponent<{ } render() { - const { treeNode, isModal, expanded } = this.props; + const { treeNode, isModal, expanded, treeNodeClick } = this.props; const { filterWorking, matchChild } = this.state; // 条件过滤生效时,如果命中了子节点,需要将该节点展开 const expandInFilterResult = filterWorking && matchChild; - if (!expandInFilterResult && !expanded) { return null; } @@ -50,12 +50,13 @@ export default class TreeBranches extends PureComponent<{ return (
{ - !isModal && + !isModal && }
); @@ -72,6 +73,7 @@ class TreeNodeChildren extends PureComponent<{ treeNode: TreeNode; isModal?: boolean; treeChildren: TreeNode[] | null; + treeNodeClick?: (e: ReactMouseEvent, type?: string) => void; }, ITreeNodeChildrenState> { state: ITreeNodeChildrenState = { filterWorking: false, @@ -114,7 +116,7 @@ class TreeNodeChildren extends PureComponent<{ } render() { - const { isModal } = this.props; + const { isModal, treeNodeClick } = this.props; const children: any = []; let groupContents: any[] = []; let currentGrp: IPublicModelExclusiveGroup; @@ -169,12 +171,12 @@ class TreeNodeChildren extends PureComponent<{ children.push(insertion); } } - groupContents.push(); + groupContents.push(); } else { if (index === dropIndex) { children.push(insertion); } - children.push(); + children.push(); } }); endGroup(); @@ -189,9 +191,10 @@ class TreeNodeChildren extends PureComponent<{ class TreeNodeSlots extends PureComponent<{ treeNode: TreeNode; + treeNodeClick?: (e: ReactMouseEvent, type?: string) => void; }> { render() { - const { treeNode } = this.props; + const { treeNode, treeNodeClick } = this.props; if (!treeNode.hasSlots()) { return null; } @@ -208,7 +211,7 @@ class TreeNodeSlots extends PureComponent<{ </div> {treeNode.slots.map(tnode => ( - <TreeNodeView key={tnode.nodeId} treeNode={tnode} /> + <TreeNodeView key={tnode.nodeId} treeNode={tnode} treeNodeClick={treeNodeClick} /> ))} </div> ); diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx index be6e6ae2c..43c9b27e3 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 { PureComponent } from 'react'; +import { MouseEvent as ReactMouseEvent, PureComponent } from 'react'; import classNames from 'classnames'; import TreeNode from '../controllers/tree-node'; import TreeTitle from './tree-title'; @@ -9,6 +9,7 @@ import { IOutlinePanelPluginContext } from '../controllers/tree-master'; class ModalTreeNodeView extends PureComponent<{ treeNode: TreeNode; + treeNodeClick?: (e: ReactMouseEvent, type?: string) => void; }, { treeChildren: TreeNode[] | null; }> { @@ -55,6 +56,7 @@ class ModalTreeNodeView extends PureComponent<{ render() { const rootTreeNode = this.rootTreeNode; const { expanded } = rootTreeNode; + const { treeNodeClick } = this.props; const hasVisibleModalNode = !!this.modalNodesManager?.getVisibleModalNode(); return ( @@ -74,6 +76,7 @@ class ModalTreeNodeView extends PureComponent<{ treeChildren={this.state.treeChildren} expanded={expanded} isModal + treeNodeClick={treeNodeClick} /> </div> </div> @@ -85,6 +88,7 @@ export default class TreeNodeView extends PureComponent<{ treeNode: TreeNode; isModal?: boolean; isRootNode?: boolean; + treeNodeClick?: (e: ReactMouseEvent, type?: string) => void; }> { state: { expanded: boolean; @@ -195,7 +199,7 @@ export default class TreeNodeView extends PureComponent<{ } render() { - const { treeNode, isModal, isRootNode } = this.props; + const { treeNode, isModal, isRootNode, treeNodeClick } = this.props; const className = classNames('tree-node', { // 是否展开 expanded: this.state.expanded, @@ -234,10 +238,12 @@ export default class TreeNodeView extends PureComponent<{ hidden={this.state.hidden} locked={this.state.locked} expandable={this.state.expandable} + treeNodeClick={treeNodeClick} /> {shouldShowModalTreeNode && <ModalTreeNodeView treeNode={treeNode} + treeNodeClick={treeNodeClick} /> } <TreeBranches @@ -245,6 +251,7 @@ export default class TreeNodeView extends PureComponent<{ isModal={false} expanded={this.state.expanded} treeChildren={this.state.treeChildren} + treeNodeClick={treeNodeClick} /> </div> ); diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index c8c0e75b0..0a3bbccef 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -1,4 +1,4 @@ -import { KeyboardEvent, FocusEvent, Fragment, PureComponent } from 'react'; +import { MouseEvent as ReactMouseEvent, KeyboardEvent, FocusEvent, Fragment, PureComponent } from 'react'; import classNames from 'classnames'; import { createIcon } from '@alilc/lowcode-utils'; import { IPublicApiEvent } from '@alilc/lowcode-types'; @@ -23,6 +23,7 @@ export default class TreeTitle extends PureComponent<{ hidden: boolean; locked: boolean; expandable: boolean; + treeNodeClick: (e: ReactMouseEvent, type?: string) => void; }> { state: { editing: boolean; @@ -106,6 +107,13 @@ export default class TreeTitle extends PureComponent<{ const { node } = treeNode; treeNode.deleteNode(node); }; + + treeTitleClick = (e: any, type: string) => { + const { treeNodeClick } = this.props; + treeNodeClick?.(e, type); + e.stopPropagation(); + }; + render() { const { treeNode, isModal } = this.props; const { pluginContext } = treeNode; @@ -200,7 +208,7 @@ export default class TreeTitle extends PureComponent<{ </a> )} {node.hasLoop() && ( - <a className="tree-node-tag loop"> + <a className="tree-node-tag loop" onClick={(e) => { this.treeTitleClick(e, 'loop'); }}> {/* todo: click todo something */} <IconLoop /> {/* @ts-ignore */} @@ -208,7 +216,7 @@ export default class TreeTitle extends PureComponent<{ </a> )} {this.state.condition && ( - <a className="tree-node-tag cond"> + <a className="tree-node-tag cond" onClick={(e) => { this.treeTitleClick(e, 'condition'); }}> {/* todo: click todo something */} <IconCond /> {/* @ts-ignore */} diff --git a/packages/plugin-outline-pane/src/views/tree.tsx b/packages/plugin-outline-pane/src/views/tree.tsx index 675f70c2b..d639c1b00 100644 --- a/packages/plugin-outline-pane/src/views/tree.tsx +++ b/packages/plugin-outline-pane/src/views/tree.tsx @@ -43,7 +43,7 @@ export default class TreeView extends PureComponent<{ detecting?.capture(node as any); } - private onClick = (e: ReactMouseEvent) => { + private onClick = (e: ReactMouseEvent, type?: string) => { if (this.ignoreUpSelected) { this.boostEvent = undefined; return; @@ -76,6 +76,12 @@ export default class TreeView extends PureComponent<{ } } else { selection?.select(id); + let tabKey; + // 点击条件渲染和循环图标,默认选中属性的高级面板 + if (type === 'condition' || type === 'loop') { + tabKey = '#advanced'; + } + tabKey && selection?.selectPropsTab(tabKey); const selectedNode = selection?.getNodes()?.[0]; const npm = selectedNode?.componentMeta?.npm; const selected = @@ -213,6 +219,7 @@ export default class TreeView extends PureComponent<{ key={this.state.root?.id} treeNode={this.state.root} isRootNode + treeNodeClick={this.onClick} /> </div> ); diff --git a/packages/shell/src/model/selection.ts b/packages/shell/src/model/selection.ts index 073083a65..f98397ad9 100644 --- a/packages/shell/src/model/selection.ts +++ b/packages/shell/src/model/selection.ts @@ -37,6 +37,15 @@ export class Selection implements IPublicModelSelection { this[selectionSymbol].select(id); } + /** + * 选中指定属性Tab + * select tab of props with tabKey + * @param tabKey + */ + selectPropsTab(tabKey: string): void { + this[selectionSymbol].selectPropsTab(tabKey); + } + /** * 批量选中指定节点们 * @param ids @@ -115,4 +124,8 @@ export class Selection implements IPublicModelSelection { onSelectionChange(fn: (ids: string[]) => void): IPublicTypeDisposable { return this[selectionSymbol].onSelectionChange(fn); } + + onSelectionPropsTabChange(fn: (tabKey: string) => void): IPublicTypeDisposable { + return this[selectionSymbol].onSelectionPropsTabChange(fn); + } } diff --git a/packages/types/src/shell/model/selection.ts b/packages/types/src/shell/model/selection.ts index 317a49837..16f5f1147 100644 --- a/packages/types/src/shell/model/selection.ts +++ b/packages/types/src/shell/model/selection.ts @@ -25,6 +25,13 @@ export interface IPublicModelSelection< */ select(id: string): void; + /** + * 选中指定属性Tab + * select tab of props with tabKey + * @param tabKey + */ + selectPropsTab(tabKey: string): void; + /** * 批量选中指定节点们 * select node with ids, this will override current selection @@ -82,4 +89,11 @@ export interface IPublicModelSelection< * @since v1.1.0 */ onSelectionChange(fn: (ids: string[]) => void): IPublicTypeDisposable; + + /** + * 注册 selection 选中属性tab的事件回调 + * set callback which will be called when selection is changed + * @since v1.1.0 + */ + onSelectionPropsTabChange(fn: (tabKey: string) => void): IPublicTypeDisposable; }