Fix 3-dot menu not losing focus after clicking outside (Windows). Related to MM-46424 (#2242) (#2454)
(cherry picked from commit 9f7a96e794
)
Co-authored-by: Tasos Boulis <tboulis@hotmail.com>
This commit is contained in:
parent
3fd29cec87
commit
8422f1d250
|
@ -24,6 +24,9 @@ export const GET_DARK_MODE = 'get-dark-mode';
|
||||||
export const USER_ACTIVITY_UPDATE = 'user-activity-update';
|
export const USER_ACTIVITY_UPDATE = 'user-activity-update';
|
||||||
export const UPDATE_SHORTCUT_MENU = 'update-shortcut-menu';
|
export const UPDATE_SHORTCUT_MENU = 'update-shortcut-menu';
|
||||||
|
|
||||||
|
export const OPEN_APP_MENU = 'open-app-menu';
|
||||||
|
export const APP_MENU_WILL_CLOSE = 'app-menu-will-close';
|
||||||
|
|
||||||
export const LOAD_RETRY = 'load_retry';
|
export const LOAD_RETRY = 'load_retry';
|
||||||
export const LOAD_SUCCESS = 'load_success';
|
export const LOAD_SUCCESS = 'load_success';
|
||||||
export const LOAD_FAILED = 'load_fail';
|
export const LOAD_FAILED = 'load_fail';
|
||||||
|
|
|
@ -35,6 +35,7 @@ import {
|
||||||
START_UPDATE_DOWNLOAD,
|
START_UPDATE_DOWNLOAD,
|
||||||
PING_DOMAIN,
|
PING_DOMAIN,
|
||||||
MAIN_WINDOW_SHOWN,
|
MAIN_WINDOW_SHOWN,
|
||||||
|
OPEN_APP_MENU,
|
||||||
} from 'common/communication';
|
} from 'common/communication';
|
||||||
import Config from 'common/config';
|
import Config from 'common/config';
|
||||||
import urlUtils from 'common/utils/url';
|
import urlUtils from 'common/utils/url';
|
||||||
|
@ -236,7 +237,7 @@ function initializeInterCommunicationEventListeners() {
|
||||||
ipcMain.on(UPDATE_LAST_ACTIVE, handleUpdateLastActive);
|
ipcMain.on(UPDATE_LAST_ACTIVE, handleUpdateLastActive);
|
||||||
|
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
ipcMain.on('open-app-menu', handleOpenAppMenu);
|
ipcMain.on(OPEN_APP_MENU, handleOpenAppMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.on(SWITCH_SERVER, handleSwitchServer);
|
ipcMain.on(SWITCH_SERVER, handleSwitchServer);
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {MattermostServer} from 'common/servers/MattermostServer';
|
||||||
import {TAB_FOCALBOARD, TAB_MESSAGING, TAB_PLAYBOOKS} from 'common/tabs/TabView';
|
import {TAB_FOCALBOARD, TAB_MESSAGING, TAB_PLAYBOOKS} from 'common/tabs/TabView';
|
||||||
import urlUtils from 'common/utils/url';
|
import urlUtils from 'common/utils/url';
|
||||||
import Utils from 'common/utils/util';
|
import Utils from 'common/utils/util';
|
||||||
|
import {APP_MENU_WILL_CLOSE} from 'common/communication';
|
||||||
|
|
||||||
import updateManager from 'main/autoUpdater';
|
import updateManager from 'main/autoUpdater';
|
||||||
import {migrationInfoPath, updatePaths} from 'main/constants';
|
import {migrationInfoPath, updatePaths} from 'main/constants';
|
||||||
|
@ -96,7 +97,10 @@ export function handleUpdateMenuEvent() {
|
||||||
|
|
||||||
const aMenu = createAppMenu(Config, updateManager);
|
const aMenu = createAppMenu(Config, updateManager);
|
||||||
Menu.setApplicationMenu(aMenu);
|
Menu.setApplicationMenu(aMenu);
|
||||||
aMenu.addListener('menu-will-close', WindowManager.focusBrowserView);
|
aMenu.addListener('menu-will-close', () => {
|
||||||
|
WindowManager.focusBrowserView();
|
||||||
|
WindowManager.sendToRenderer(APP_MENU_WILL_CLOSE);
|
||||||
|
});
|
||||||
|
|
||||||
// set up context menu for tray icon
|
// set up context menu for tray icon
|
||||||
if (shouldShowTrayIcon()) {
|
if (shouldShowTrayIcon()) {
|
||||||
|
|
|
@ -49,6 +49,7 @@ import {
|
||||||
UPDATE_DOWNLOADS_DROPDOWN,
|
UPDATE_DOWNLOADS_DROPDOWN,
|
||||||
REQUEST_HAS_DOWNLOADS,
|
REQUEST_HAS_DOWNLOADS,
|
||||||
CLOSE_DOWNLOADS_DROPDOWN_MENU,
|
CLOSE_DOWNLOADS_DROPDOWN_MENU,
|
||||||
|
APP_MENU_WILL_CLOSE,
|
||||||
} from 'common/communication';
|
} from 'common/communication';
|
||||||
|
|
||||||
import restoreButton from '../../assets/titlebar/chrome-restore.svg';
|
import restoreButton from '../../assets/titlebar/chrome-restore.svg';
|
||||||
|
@ -101,6 +102,7 @@ type State = {
|
||||||
isDownloadsDropdownOpen: boolean;
|
isDownloadsDropdownOpen: boolean;
|
||||||
showDownloadsBadge: boolean;
|
showDownloadsBadge: boolean;
|
||||||
hasDownloads: boolean;
|
hasDownloads: boolean;
|
||||||
|
threeDotsIsFocused: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type TabViewStatus = {
|
type TabViewStatus = {
|
||||||
|
@ -113,13 +115,11 @@ type TabViewStatus = {
|
||||||
|
|
||||||
class MainPage extends React.PureComponent<Props, State> {
|
class MainPage extends React.PureComponent<Props, State> {
|
||||||
topBar: React.RefObject<HTMLDivElement>;
|
topBar: React.RefObject<HTMLDivElement>;
|
||||||
threeDotMenu: React.RefObject<HTMLButtonElement>;
|
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.topBar = React.createRef();
|
this.topBar = React.createRef();
|
||||||
this.threeDotMenu = React.createRef();
|
|
||||||
|
|
||||||
const firstServer = this.props.teams.find((team) => team.order === this.props.lastActiveTeam) || this.props.teams.find((team) => team.order === 0);
|
const firstServer = this.props.teams.find((team) => team.order === this.props.lastActiveTeam) || this.props.teams.find((team) => team.order === 0);
|
||||||
let firstTab = firstServer?.tabs.find((tab) => tab.order === firstServer.lastActiveTab) || firstServer?.tabs.find((tab) => tab.order === 0);
|
let firstTab = firstServer?.tabs.find((tab) => tab.order === firstServer.lastActiveTab) || firstServer?.tabs.find((tab) => tab.order === 0);
|
||||||
|
@ -141,6 +141,7 @@ class MainPage extends React.PureComponent<Props, State> {
|
||||||
isDownloadsDropdownOpen: false,
|
isDownloadsDropdownOpen: false,
|
||||||
showDownloadsBadge: false,
|
showDownloadsBadge: false,
|
||||||
hasDownloads: false,
|
hasDownloads: false,
|
||||||
|
threeDotsIsFocused: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,12 +280,10 @@ class MainPage extends React.PureComponent<Props, State> {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.ipcRenderer.on(APP_MENU_WILL_CLOSE, this.unFocusThreeDotsButton);
|
||||||
|
|
||||||
if (window.process.platform !== 'darwin') {
|
if (window.process.platform !== 'darwin') {
|
||||||
window.ipcRenderer.on(FOCUS_THREE_DOT_MENU, () => {
|
window.ipcRenderer.on(FOCUS_THREE_DOT_MENU, this.focusThreeDotsButton);
|
||||||
if (this.threeDotMenu.current) {
|
|
||||||
this.threeDotMenu.current.focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('click', this.handleCloseDropdowns);
|
window.addEventListener('click', this.handleCloseDropdowns);
|
||||||
|
@ -357,9 +356,6 @@ class MainPage extends React.PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
openMenu = () => {
|
openMenu = () => {
|
||||||
if (window.process.platform !== 'darwin') {
|
|
||||||
this.threeDotMenu.current?.blur();
|
|
||||||
}
|
|
||||||
this.props.openMenu();
|
this.props.openMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,6 +385,18 @@ class MainPage extends React.PureComponent<Props, State> {
|
||||||
window.ipcRenderer.send(OPEN_DOWNLOADS_DROPDOWN);
|
window.ipcRenderer.send(OPEN_DOWNLOADS_DROPDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
focusThreeDotsButton = () => {
|
||||||
|
this.setState({
|
||||||
|
threeDotsIsFocused: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
unFocusThreeDotsButton = () => {
|
||||||
|
this.setState({
|
||||||
|
threeDotsIsFocused: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {intl} = this.props;
|
const {intl} = this.props;
|
||||||
const currentTabs = this.props.teams.find((team) => team.name === this.state.activeServerName)?.tabs || [];
|
const currentTabs = this.props.teams.find((team) => team.name === this.state.activeServerName)?.tabs || [];
|
||||||
|
@ -512,11 +520,16 @@ class MainPage extends React.PureComponent<Props, State> {
|
||||||
<button
|
<button
|
||||||
className='three-dot-menu'
|
className='three-dot-menu'
|
||||||
onClick={this.openMenu}
|
onClick={this.openMenu}
|
||||||
|
onMouseOver={this.focusThreeDotsButton}
|
||||||
|
onMouseOut={this.unFocusThreeDotsButton}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
ref={this.threeDotMenu}
|
|
||||||
aria-label={intl.formatMessage({id: 'renderer.components.mainPage.contextMenu.ariaLabel', defaultMessage: 'Context menu'})}
|
aria-label={intl.formatMessage({id: 'renderer.components.mainPage.contextMenu.ariaLabel', defaultMessage: 'Context menu'})}
|
||||||
>
|
>
|
||||||
<i className='icon-dots-vertical'/>
|
<i
|
||||||
|
className={classNames('icon-dots-vertical', {
|
||||||
|
isFocused: this.state.threeDotsIsFocused,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
{this.props.teams.length !== 0 && (
|
{this.props.teams.length !== 0 && (
|
||||||
<TeamDropdownButton
|
<TeamDropdownButton
|
||||||
|
|
|
@ -83,16 +83,16 @@ body {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topBar .three-dot-menu:hover i.icon-dots-vertical, .topBar .three-dot-menu:focus i.icon-dots-vertical, .topBar .three-dot-menu:active i.icon-dots-vertical {
|
.topBar .three-dot-menu i.icon-dots-vertical.isFocused {
|
||||||
outline: none;
|
outline: none;
|
||||||
background-color: #c8c8c8;
|
background-color: #c8c8c8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topBar.darkMode .three-dot-menu:hover i.icon-dots-vertical, .topBar.darkMode .three-dot-menu:focus i.icon-dots-vertical, .topBar.darkMode .three-dot-menu:active i.icon-dots-vertical {
|
.topBar.darkMode .three-dot-menu i.icon-dots-vertical.isFocused {
|
||||||
background-color: #383A3F;
|
background-color: #383A3F;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topBar.macOS .three-dot-menu:hover i.icon-dots-vertical, .topBar.macOS .three-dot-menu:focus i.icon-dots-vertical, .topBar.macOS .three-dot-menu:active i.icon-dots-vertical {
|
.topBar.macOS .three-dot-menu i.icon-dots-vertical.isFocused {
|
||||||
background: none !important;
|
background: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
import {CombinedConfig, Team} from 'types/config';
|
import {CombinedConfig, Team} from 'types/config';
|
||||||
|
|
||||||
import {GET_CONFIGURATION, UPDATE_TEAMS, QUIT, RELOAD_CONFIGURATION} from 'common/communication';
|
import {GET_CONFIGURATION, UPDATE_TEAMS, QUIT, RELOAD_CONFIGURATION, OPEN_APP_MENU} from 'common/communication';
|
||||||
|
|
||||||
import MainPage from './components/MainPage';
|
import MainPage from './components/MainPage';
|
||||||
import IntlProvider from './intl_provider';
|
import IntlProvider from './intl_provider';
|
||||||
|
@ -110,7 +110,7 @@ class Root extends React.PureComponent<Record<string, never>, State> {
|
||||||
|
|
||||||
openMenu = () => {
|
openMenu = () => {
|
||||||
if (window.process.platform !== 'darwin') {
|
if (window.process.platform !== 'darwin') {
|
||||||
window.ipcRenderer.send('open-app-menu');
|
window.ipcRenderer.send(OPEN_APP_MENU);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue