import React = require("react"); import { observable, action } from "mobx"; import { observer } from "mobx-react"; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { UndoManager } from "../util/UndoManager"; export interface OriginalMenuProps { description: string; event: (stuff?: any) => void; undoable?: boolean; icon: IconProp; //maybe should be optional (icon?) closeMenu?: () => void; } export interface SubmenuProps { description: string; subitems: ContextMenuProps[]; noexpand?: boolean; addDivider?: boolean; icon: IconProp; //maybe should be optional (icon?) closeMenu?: () => void; } export type ContextMenuProps = OriginalMenuProps | SubmenuProps; @observer export class ContextMenuItem extends React.Component { @observable private _items: Array = []; @observable private overItem = false; componentDidMount() { this._items.length = 0; if ((this.props as SubmenuProps)?.subitems) { (this.props as SubmenuProps).subitems?.forEach(i => this._items.push(i)); } } handleEvent = async (e: React.MouseEvent) => { if ("event" in this.props) { this.props.closeMenu?.(); let batch: UndoManager.Batch | undefined; if (this.props.undoable !== false) { batch = UndoManager.StartBatch(`Context menu event: ${this.props.description}`); } await this.props.event({ x: e.clientX, y: e.clientY }); batch?.end(); } } currentTimeout?: any; static readonly timeout = 300; _overPosY = 0; _overPosX = 0; onPointerEnter = (e: React.MouseEvent) => { if (this.currentTimeout) { clearTimeout(this.currentTimeout); this.currentTimeout = undefined; } if (this.overItem) { return; } this._overPosY = e.clientY; this._overPosX = e.clientX; this.currentTimeout = setTimeout(action(() => this.overItem = true), ContextMenuItem.timeout); } onPointerLeave = () => { if (this.currentTimeout) { clearTimeout(this.currentTimeout); this.currentTimeout = undefined; } if (!this.overItem) { return; } this.currentTimeout = setTimeout(action(() => this.overItem = false), ContextMenuItem.timeout); } render() { if ("event" in this.props) { return (
{this.props.icon ? ( ) : null}
{this.props.description.replace(":", "")}
); } else if ("subitems" in this.props) { const where = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "flex-start" : this._overPosY > window.innerHeight * 2 / 3 ? "flex-end" : "center"; const marginTop = !this.overItem ? "" : this._overPosY < window.innerHeight / 3 ? "20px" : this._overPosY > window.innerHeight * 2 / 3 ? "-20px" : ""; // here const submenu = !this.overItem ? (null) :
0 ? "90%" : "20%", marginTop }}> {this._items.map(prop => )}
; if (!(this.props as SubmenuProps).noexpand) { return
{this._items.map(prop => )}
; } return (
{this.props.icon ? ( ) : null}
{this.props.description}
{submenu}
); } } }