import styled from "@emotion/styled" import * as Portal from "@radix-ui/react-portal" import { FC, ReactNode, useEffect } from "react" import { IPoint } from "../common/geometry" export const ContextMenuHotKey = styled.div` font-size: 0.9em; flex-grow: 1; text-align: right; color: ${({ theme }) => theme.secondaryTextColor}; margin-left: 2em; ` const Wrapper = styled.div` position: fixed; left: 0; top: 0; right: 0; bottom: 0; ` const Content = styled.div` position: absolute; background: ${({ theme }) => theme.secondaryBackgroundColor}; border-radius: 0.5rem; box-shadow: 0 1rem 3rem ${({ theme }) => theme.shadowColor}; border: 1px solid ${({ theme }) => theme.backgroundColor}; padding: 0.5rem 0; ` const List = styled.ul` list-style: none; padding: 0; margin: 0; ` export interface ContextMenuProps { isOpen: boolean position: IPoint handleClose: () => void children?: ReactNode } const estimatedWidth = 200 export const ContextMenu: FC = ({ isOpen, handleClose, position, children, }) => { // Menu cannot handle keydown while disabling focus, so we deal with global keydown event useEffect(() => { const onKeyDown = (e: KeyboardEvent) => { if (isOpen && e.key === "Escape") { handleClose() } } document.addEventListener("keydown", onKeyDown) return () => { document.removeEventListener("keydown", onKeyDown) } }, [isOpen]) if (!isOpen) { return <> } // fix position to avoid placing menu outside of the screen const fixedX = Math.min(position.x, window.innerWidth - estimatedWidth) return ( e.stopPropagation()} > {children} ) }