-
Notifications
You must be signed in to change notification settings - Fork 45.5k
/
ContextMenu.js
126 lines (112 loc) · 3.24 KB
/
ContextMenu.js
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
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import type {
ReactDOMResponderEvent,
ReactDOMResponderContext,
PointerType,
} from 'react-dom/src/shared/ReactDOMTypes';
import type {ReactEventResponderListener} from 'shared/ReactTypes';
import * as React from 'react';
import {DiscreteEvent} from 'shared/ReactTypes';
type ContextMenuProps = {|
disabled: boolean,
onContextMenu: (e: ContextMenuEvent) => void,
preventDefault: boolean,
|};
type ContextMenuState = {pointerType: PointerType, ...};
type ContextMenuEvent = {|
altKey: boolean,
buttons: 0 | 1 | 2,
ctrlKey: boolean,
metaKey: boolean,
pageX: null | number,
pageY: null | number,
pointerType: PointerType,
shiftKey: boolean,
target: Element | Document,
timeStamp: number,
type: 'contextmenu',
x: null | number,
y: null | number,
|};
const hasPointerEvents =
typeof window !== 'undefined' && window.PointerEvent != null;
function dispatchContextMenuEvent(
event: ReactDOMResponderEvent,
context: ReactDOMResponderContext,
props: ContextMenuProps,
state: ContextMenuState,
): void {
const nativeEvent: any = event.nativeEvent;
const target = event.target;
const timeStamp = context.getTimeStamp();
const pointerType = state.pointerType;
const gestureState = {
altKey: nativeEvent.altKey,
buttons: nativeEvent.buttons != null ? nativeEvent.buttons : 0,
ctrlKey: nativeEvent.ctrlKey,
metaKey: nativeEvent.metaKey,
pageX: nativeEvent.pageX,
pageY: nativeEvent.pageY,
pointerType,
shiftKey: nativeEvent.shiftKey,
target,
timeStamp,
type: 'contextmenu',
x: nativeEvent.clientX,
y: nativeEvent.clientY,
};
context.dispatchEvent(gestureState, props.onContextMenu, DiscreteEvent);
}
const contextMenuImpl = {
targetEventTypes: hasPointerEvents
? ['contextmenu_active', 'pointerdown']
: ['contextmenu_active', 'touchstart', 'mousedown'],
getInitialState(): ContextMenuState {
return {
pointerType: '',
};
},
onEvent(
event: ReactDOMResponderEvent,
context: ReactDOMResponderContext,
props: ContextMenuProps,
state: ContextMenuState,
): void {
const nativeEvent: any = event.nativeEvent;
const pointerType = event.pointerType;
const type = event.type;
if (props.disabled) {
return;
}
if (type === 'contextmenu') {
const onContextMenu = props.onContextMenu;
const preventDefault = props.preventDefault;
if (preventDefault !== false && !nativeEvent.defaultPrevented) {
nativeEvent.preventDefault();
}
if (typeof onContextMenu === 'function') {
dispatchContextMenuEvent(event, context, props, state);
}
state.pointerType = '';
} else {
state.pointerType = pointerType;
}
},
};
// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
export const ContextMenuResponder = React.DEPRECATED_createResponder(
'ContextMenu',
contextMenuImpl,
);
export function useContextMenu(
props: ContextMenuProps,
): ?ReactEventResponderListener<any, any> {
return React.DEPRECATED_useResponder(ContextMenuResponder, props);
}