Skip to content

Instantly share code, notes, and snippets.

@loopmode
Created April 15, 2020 10:06
Show Gist options
  • Save loopmode/f1760d6562d9fa04ff73b64d0fe25651 to your computer and use it in GitHub Desktop.
Save loopmode/f1760d6562d9fa04ff73b64d0fe25651 to your computer and use it in GitHub Desktop.
use-electron-context-menu
/**
* example of making inspector menu item available on everything from the "root" component
*/
import { hot } from 'react-hot-loader/root';
import React from 'react';
import useContextMenu from './hooks/use-context-menu';
const App: React.FC = React.memo(() => {
useContextMenu('body', { showInspectElement: true });
// return (
// <Router history={appHistory}>
// ...
// </Router>
// );
return null;
});
export default hot(App);
/**
* example of using a custom menu on list items
*/
import React, { useRef, useCallback } from 'react';
import { useDispatch } from 'react-redux';
import {
removeCommand,
cloneCommand
} from 'renderer/model/slices/project/project-slice';
import useContextMenu from 'renderer/hooks/use-context-menu';
export interface CommandListItemProps {
command: Command;
}
export const CommandListItem: React.FC<CommandListItemProps> = ({
command
}) => {
const ref = useRef(null);
const dispatch = useDispatch();
const handleDelete = useCallback(() => {
dispatch(removeCommand(command));
}, [command.id]);
const handleClone = React.useCallback(() => dispatch(cloneCommand(command)), [
command.id
]);
useContextMenu(
ref,
{
showInspectElement: process.env.NODE_ENV !== 'production',
items: [
{
id: 'clone-command',
enabled: true,
label: 'Clone command',
click: handleClone
},
{
id: 'delete-command',
enabled: true,
label: 'Delete command',
click: handleDelete
}
]
},
[command.id]
);
return <div ref={ref}>command list item</div>;
// return (
// <CommandListItemView
// {...props}
// ref={ref}
// className={className}
// command={command}
// showDeleteButton={withDeleteButton}
// showDeleteModal={deleteModalVisible}
// onDeleteShowModal={showConfirmDelete}
// onDeleteCancel={hideConfirmDelete}
// onDeleteConfirm={handleConfirmDelete}
// showProcessButton={withControlButton}
// isProcessRunning={!!processId}
// onProcessClick={handleProcessClick}
// />
// );
};
/**
* example of a hook using context menu
*/
import { remote, MenuItemConstructorOptions } from 'electron';
import React from 'react';
const { Menu, MenuItem, getCurrentWindow } = remote;
export type MenuMode = 'menu' | 'append' | 'prepend';
export type TargetType =
| string
| React.MutableRefObject<HTMLElement | null>
| HTMLElement;
export interface UseContextMenuOptions {
items?: MenuItemConstructorOptions[];
showInspectElement?: boolean;
}
export default function useContextMenu(
targetSelectorOrRef:
| string
| React.MutableRefObject<HTMLElement | null>
| HTMLElement,
options: UseContextMenuOptions,
dependencies: any[] = []
) {
React.useEffect(() => {
const element = getElement(targetSelectorOrRef);
if (!element) return () => null;
const browserWindow = getCurrentWindow();
const handleContextMenu = (event: MouseEvent) => {
if (event.defaultPrevented || !isTargetElement(event, element)) {
return;
}
event.preventDefault();
const menu = new Menu();
if (options.items) {
options.items.forEach(item => menu.append(new MenuItem(item)));
}
if (options.showInspectElement) {
menu.append(createInspectMenuItem(event, browserWindow.webContents));
}
if (menu.items.length > 0) {
menu.popup({ window: browserWindow });
}
};
(element as any).addEventListener('contextmenu', handleContextMenu);
return () =>
(element as any).removeEventListener('contextmenu', handleContextMenu);
}, dependencies);
}
function getElement(target: TargetType): HTMLElement | null {
return typeof target === 'string'
? document.querySelector(target)
: (target instanceof HTMLElement && target) || target.current;
}
function isTargetElement(event: MouseEvent, element: HTMLElement) {
return (
event.target === element || element.contains(event.target as HTMLElement)
);
}
function createInspectMenuItem(
event: MouseEvent,
webContents: Electron.WebContents
) {
return new MenuItem({
id: 'inspect',
label: 'Inspect Element',
enabled: true,
click() {
webContents.inspectElement(event.clientX, event.clientY);
if (webContents.isDevToolsOpened()) {
webContents.devToolsWebContents.focus();
}
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment