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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
import React = require("react");
import { observer } from "mobx-react";
import { observable, action } from "mobx";
import "./AntimodeMenu.scss";
/**
* This is an abstract class that serves as the base for a PDF-style or Marquee-style
* menu. To use this class, look at PDFMenu.tsx or MarqueeOptionsMenu.tsx for an example.
*/
export default abstract class AntimodeMenu extends React.Component {
protected _offsetY: number = 0;
protected _offsetX: number = 0;
protected _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
protected _dragging: boolean = false;
@observable protected _top: number = -300;
@observable protected _left: number = -300;
@observable protected _opacity: number = 1;
@observable protected _transition: string = "opacity 0.5s";
@observable protected _transitionDelay: string = "";
@observable public Pinned: boolean = false;
@action
/**
* @param x
* @param y
* @param forceJump: If the menu is pinned down, do you want to force it to jump to the new location?
* Called when you want the menu to show up at a location
*/
public jumpTo = (x: number, y: number, forceJump: boolean = false) => {
if (!this.Pinned || forceJump) {
this._transition = this._transitionDelay = "";
this._opacity = 1;
this._left = x;
this._top = y;
}
}
@action
/**
* @param forceOut: Do you want the menu to disappear immediately or to slowly fadeout?
* Called when you want the menu to disappear
*/
public fadeOut = (forceOut: boolean) => {
if (!this.Pinned) {
if (this._opacity === 0.2) {
this._transition = "opacity 0.1s";
this._transitionDelay = "";
this._opacity = 0;
this._left = this._top = -300;
}
if (forceOut) {
this._transition = "";
this._transitionDelay = "";
this._opacity = 0;
this._left = this._top = -300;
}
}
}
@action
protected pointerLeave = (e: React.PointerEvent) => {
if (!this.Pinned) {
this._transition = "opacity 0.5s";
this._transitionDelay = "1s";
this._opacity = 0.2;
setTimeout(() => this.fadeOut(false), 3000);
}
}
@action
protected pointerEntered = (e: React.PointerEvent) => {
this._transition = "opacity 0.1s";
this._transitionDelay = "";
this._opacity = 1;
}
@action
protected togglePin = (e: React.MouseEvent) => {
this.Pinned = !this.Pinned;
}
protected dragStart = (e: React.PointerEvent) => {
document.removeEventListener("pointermove", this.dragging);
document.addEventListener("pointermove", this.dragging);
document.removeEventListener("pointerup", this.dragEnd);
document.addEventListener("pointerup", this.dragEnd);
this._offsetX = this._mainCont.current!.getBoundingClientRect().width - e.nativeEvent.offsetX;
this._offsetY = e.nativeEvent.offsetY;
e.stopPropagation();
e.preventDefault();
}
@action
protected dragging = (e: PointerEvent) => {
this._left = e.pageX - this._offsetX;
this._top = e.pageY - this._offsetY;
e.stopPropagation();
e.preventDefault();
}
protected dragEnd = (e: PointerEvent) => {
document.removeEventListener("pointermove", this.dragging);
document.removeEventListener("pointerup", this.dragEnd);
e.stopPropagation();
e.preventDefault();
}
protected handleContextMenu = (e: React.MouseEvent) => {
e.stopPropagation();
e.preventDefault();
}
protected getElement(buttons: JSX.Element[]) {
return (
<div className="antimodeMenu-cont" onPointerLeave={this.pointerLeave} onPointerEnter={this.pointerEntered} ref={this._mainCont} onContextMenu={this.handleContextMenu}
style={{ left: this._left, top: this._top, opacity: this._opacity, transition: this._transition, transitionDelay: this._transitionDelay }}>
{buttons}
<div className="antimodeMenu-dragger" onPointerDown={this.dragStart} style={{ width: this.Pinned ? "20px" : "0px" }} />
</div>
);
}
}
|