Skip to content

Commit 20c191d

Browse files
authored
fix: improve activity context menu behavior (#206)
1 parent c8aca25 commit 20c191d

File tree

4 files changed

+99
-64
lines changed

4 files changed

+99
-64
lines changed

src/controller/activityBar.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,17 @@ export class ActivityBarController
9595
// activityBar contextMenu
9696
case CONTEXT_MENU_MENU: {
9797
this.menuBarController.updateMenuBar!();
98+
this.activityBarService.toggleContextMenuCheckStatus(
99+
contextMenuId
100+
);
98101
break;
99102
}
100-
case CONTEXT_MENU_EXPLORER: {
101-
this.activityBarService.toggleBar(contextMenuId);
102-
break;
103-
}
103+
case CONTEXT_MENU_EXPLORER:
104104
case CONTEXT_MENU_SEARCH: {
105105
this.activityBarService.toggleBar(contextMenuId);
106+
this.activityBarService.toggleContextMenuCheckStatus(
107+
contextMenuId
108+
);
106109
break;
107110
}
108111
case CONTEXT_MENU_HIDE: {

src/model/workbench/activityBar.ts

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface IActivityBarItem {
2424
id: string;
2525
name?: ReactNode;
2626
title?: string;
27+
hidden?: boolean;
2728
data?: any;
2829
iconName?: string;
2930
checked?: boolean;

src/services/workbench/activityBarService.ts

+32-33
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import {
77
IActivityBar,
88
IActivityBarItem,
99
} from 'mo/model/workbench/activityBar';
10-
import { builtInExplorerActivityItem } from 'mo/model/workbench/explorer/explorer';
11-
import { builtInSearchActivityItem } from 'mo/model/workbench/search';
1210
import { searchById } from '../helper';
1311
import { IMenuItemProps } from 'mo/components/menu';
12+
import logger from 'mo/common/logger';
13+
import { ISidebarService, SidebarService } from './sidebarService';
1414

1515
export interface IActivityBarService extends Component<IActivityBar> {
1616
reset(): void;
@@ -27,8 +27,8 @@ export interface IActivityBarService extends Component<IActivityBar> {
2727
*/
2828
setActive(id?: string): void;
2929
remove(id: string): void;
30-
toggleBar(id?: string): void;
31-
updateContextMenuCheckStatus(id?: string): void;
30+
toggleBar(id: string): void;
31+
toggleContextMenuCheckStatus(id: string): void;
3232
addContextMenu(contextMenu: IMenuItemProps | IMenuItemProps[]): void;
3333
removeContextMenu(id: string): void;
3434
/**
@@ -49,10 +49,12 @@ export class ActivityBarService
4949
extends Component<IActivityBar>
5050
implements IActivityBarService {
5151
protected state: IActivityBar;
52+
private sidebarService: ISidebarService;
5253

5354
constructor() {
5455
super();
5556
this.state = container.resolve(ActivityBarModel);
57+
this.sidebarService = container.resolve(SidebarService);
5658
}
5759
public setActive(id?: string) {
5860
this.setState({
@@ -98,40 +100,37 @@ export class ActivityBarService
98100
}
99101

100102
public toggleBar(id: string) {
101-
const { data } = this.state;
102-
const next = [...data!];
103+
const { data = [], selected } = this.state;
104+
const next = data.concat();
103105
const index = next.findIndex(searchById(id));
104-
if (index > -1) {
105-
this.remove(id);
106+
const target = next[index];
107+
if (target) {
108+
target.hidden = !target.hidden;
109+
if (id === selected) {
110+
const nextIndex = (index + 1) % next.length;
111+
this.setActive(next[nextIndex].id);
112+
this.sidebarService.setActive(next[nextIndex].id);
113+
}
114+
this.setState({
115+
data: next,
116+
});
106117
} else {
107-
// TODO 这个existBar 逻辑应该有问题
108-
const existBar = [
109-
builtInExplorerActivityItem(),
110-
builtInSearchActivityItem(),
111-
].find(searchById(id));
112-
if (!existBar) return;
113-
this.addBar(existBar);
118+
logger.error('Toggle activity bar failed, please check your id');
114119
}
115-
this.updateContextMenuCheckStatus(id);
116120
}
117121

118-
public updateContextMenuCheckStatus(id: string) {
119-
const { contextMenu, data } = this.state;
120-
const existBar = data?.find(searchById(id));
121-
const newActions = contextMenu?.map((item) => {
122-
return {
123-
...item,
124-
icon:
125-
item.id === id
126-
? Boolean(existBar)
127-
? 'check'
128-
: ''
129-
: item.icon,
130-
};
131-
});
132-
this.setState({
133-
contextMenu: newActions,
134-
});
122+
public toggleContextMenuCheckStatus(id: string) {
123+
const { contextMenu = [] } = this.state;
124+
const newActions = contextMenu.concat();
125+
const target = newActions.find(searchById(id));
126+
if (target) {
127+
target.icon = target.icon === 'check' ? '' : 'check';
128+
this.setState({
129+
contextMenu: newActions,
130+
});
131+
} else {
132+
logger.error('toggle context menu failed, please check your id');
133+
}
135134
}
136135

137136
public addContextMenu(contextMenu: IMenuItemProps | IMenuItemProps[]) {

src/workbench/activityBar/activityBar.tsx

+59-27
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import * as React from 'react';
2-
import { useCallback, useEffect } from 'react';
3-
import { useContextMenu } from 'mo/components/contextMenu';
4-
import { select } from 'mo/common/dom';
2+
import { useCallback } from 'react';
53
import { IMenuItemProps, Menu } from 'mo/components/menu';
64
import { ID_ACTIVITY_BAR } from 'mo/common/id';
75
import { IActivityBar, IActivityBarItem } from 'mo/model/workbench/activityBar';
@@ -14,8 +12,10 @@ import {
1412
containerClassName,
1513
defaultClassName,
1614
globalItemsClassName,
15+
itemClassName,
1716
normalItemsClassName,
1817
} from './base';
18+
import { useContextView } from 'mo/components';
1919

2020
export function ActivityBar(props: IActivityBar & IActivityBarController) {
2121
const {
@@ -37,14 +37,12 @@ export function ActivityBar(props: IActivityBar & IActivityBarController) {
3737
}
3838
};
3939

40-
const normalBarItems =
41-
data?.filter(
42-
(item: IActivityBarItem) => !item.type || item.type === 'normal'
43-
) || [];
44-
const globalBarItems =
45-
data?.filter(
46-
(item: IActivityBarItem) => item.type && item.type === 'global'
47-
) || [];
40+
const normalBarItems = data.filter(
41+
(item) => item.type !== 'global' && !item.hidden
42+
);
43+
const globalBarItems = data.filter(
44+
(item) => item.type === 'global' && !item.hidden
45+
);
4846

4947
const renderItems = (item: IActivityBarItem, index: number) => {
5048
return (
@@ -59,32 +57,66 @@ export function ActivityBar(props: IActivityBar & IActivityBarController) {
5957
);
6058
};
6159

62-
let contextViewMenu;
60+
const renderContextMenu = () => (
61+
<Menu onClick={onClickMenuItem} data={contextMenu} />
62+
);
63+
64+
const contextView = useContextView({
65+
render: renderContextMenu,
66+
});
67+
6368
const onClickMenuItem = useCallback(
6469
(e: React.MouseEvent, item: IMenuItemProps | undefined) => {
6570
onContextMenuClick?.(e, item);
66-
contextViewMenu?.dispose();
71+
contextView?.hide();
6772
},
6873
[contextMenu]
6974
);
70-
const renderContextMenu = () => (
71-
<Menu onClick={onClickMenuItem} data={contextMenu} />
72-
);
7375

74-
useEffect(() => {
75-
if (contextMenu.length > 0) {
76-
contextViewMenu = useContextMenu({
77-
anchor: select(`#${ID_ACTIVITY_BAR}`),
78-
render: renderContextMenu,
79-
});
76+
const handleRightClick = (e) => {
77+
e.preventDefault();
78+
e.stopPropagation();
79+
const doms = document.elementsFromPoint(e.pageX, e.pageY);
80+
const itemDom = doms.find((dom) =>
81+
dom.classList.contains(itemClassName)
82+
);
83+
if (itemDom) {
84+
const rect = itemDom.getBoundingClientRect();
85+
const extraContextMenu = contextMenu.concat();
86+
const targetContextMenu = contextMenu.find(
87+
(menu) => menu.id === itemDom?.id
88+
);
89+
targetContextMenu &&
90+
extraContextMenu.unshift(
91+
...([
92+
{
93+
id: itemDom.id,
94+
icon: 'check',
95+
name: targetContextMenu.name,
96+
},
97+
{
98+
type: 'divider',
99+
},
100+
] as IMenuItemProps[])
101+
);
102+
contextView.show(
103+
{
104+
x: rect.x + rect.width / 2,
105+
y: rect.y + rect.height,
106+
},
107+
() => <Menu onClick={onClickMenuItem} data={extraContextMenu} />
108+
);
109+
} else {
110+
contextView.show({ x: e.pageX, y: e.pageY });
80111
}
81-
return function cleanup() {
82-
contextViewMenu?.dispose();
83-
};
84-
});
112+
};
85113

86114
return (
87-
<div className={defaultClassName} id={ID_ACTIVITY_BAR}>
115+
<div
116+
className={defaultClassName}
117+
onContextMenu={handleRightClick}
118+
id={ID_ACTIVITY_BAR}
119+
>
88120
<div className={containerClassName}>
89121
<Scrollable className={normalItemsClassName}>
90122
<ul>{normalBarItems.map(renderItems)}</ul>

0 commit comments

Comments
 (0)