Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | 1x 1x 1x 1x 1x | import React, {
JSX,
ReactNode,
useCallback,
useEffect,
useMemo,
useState,
} from "react";
import { MaybePromise } from "shared/types";
import { ContextMenu } from "ui/menu/ContextMenu";
const CLOSE_CONTEXT_MENUS_EVENT = "close-context-menus";
const closeAllContextMenus = () => {
window.dispatchEvent(new Event(CLOSE_CONTEXT_MENUS_EVENT));
};
interface ContextMenuState {
x: number;
y: number;
menu: JSX.Element[];
}
interface UseContextMenuOptions {
enabled?: boolean;
getIsEnabled?: (e: React.MouseEvent) => boolean;
getMenu: (args: {
closeMenu: () => void;
event: React.MouseEvent;
}) => MaybePromise<JSX.Element[] | undefined>;
}
interface UseContextMenuResult {
onContextMenu: (e: React.MouseEvent) => void;
closeMenu: () => void;
contextMenuElement: ReactNode;
isOpen: boolean;
}
export const useContextMenu = ({
enabled = true,
getIsEnabled,
getMenu,
}: UseContextMenuOptions): UseContextMenuResult => {
const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);
const closeMenu = useCallback(() => {
setContextMenu(null);
}, []);
useEffect(() => {
window.addEventListener(CLOSE_CONTEXT_MENUS_EVENT, closeMenu);
return () => {
window.removeEventListener(CLOSE_CONTEXT_MENUS_EVENT, closeMenu);
};
}, [closeMenu]);
const onContextMenu = useCallback(
async (e: React.MouseEvent) => {
if (!enabled || (getIsEnabled !== undefined && !getIsEnabled(e))) {
return;
}
e.preventDefault();
e.stopPropagation();
closeAllContextMenus();
const menu = await getMenu({ closeMenu, event: e });
if (!menu || menu.length === 0) {
return;
}
setContextMenu({
x: e.pageX,
y: e.pageY,
menu,
});
},
[enabled, getIsEnabled, getMenu, closeMenu],
);
const contextMenuElement = useMemo(() => {
if (!contextMenu) {
return null;
}
return (
<ContextMenu x={contextMenu.x} y={contextMenu.y} onClose={closeMenu}>
{contextMenu.menu}
</ContextMenu>
);
}, [contextMenu, closeMenu]);
return {
onContextMenu,
closeMenu,
contextMenuElement,
isOpen: contextMenu !== null,
};
};
|