import * as React from 'react'; import { observable, action, runInAction, makeObservable } 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'; import { SettingsManager } from '../util/SettingsManager'; import { ObservableReactComponent } from './ObservableReactComponent'; export interface OriginalMenuProps { description: string; event: (stuff?: any) => void; undoable?: boolean; icon: IconProp | JSX.Element; //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 ObservableReactComponent { @observable private _items: Array = []; @observable private overItem = false; constructor(props: any) { super(props); makeObservable(this); } componentDidMount() { runInAction(() => (this._items.length = 0)); if ((this._props as SubmenuProps)?.subitems) { (this._props as SubmenuProps).subitems?.forEach(i => runInAction(() => this._items.push(i))); } } handleEvent = async (e: React.MouseEvent) => { if ('event' in this._props) { this._props.closeMenu?.(); const batch = this._props.undoable !== false ? UndoManager.StartBatch(`Click Menu item: ${this._props.description}`) : undefined; 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 ); }; isJSXElement(val: any): val is JSX.Element { return React.isValidElement(val); } render() { if ('event' in this._props) { return (
{this._props.icon ? {this.isJSXElement(this._props.icon) ? 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, background: SettingsManager.userBackgroundColor, }}> {this._items.map(prop => ( ))}
); if (!(this._props as SubmenuProps).noexpand) { return (
{this._items.map(prop => ( ))}
); } return (
{this._props.icon ? ( ) : null}
{this._props.description}
{submenu}
); } } }