-
Notifications
You must be signed in to change notification settings - Fork 3k
/
index.js
105 lines (95 loc) · 4.35 KB
/
index.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
import _ from 'underscore';
import React, {Component} from 'react';
import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes';
import styles from '../../styles/styles';
import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
import * as StyleUtils from '../../styles/StyleUtils';
import PressableWithFeedback from '../Pressable/PressableWithFeedback';
/**
* This is a special Pressable that calls onSecondaryInteraction when LongPressed, or right-clicked.
*/
class PressableWithSecondaryInteraction extends Component {
constructor(props) {
super(props);
this.executeSecondaryInteraction = this.executeSecondaryInteraction.bind(this);
this.executeSecondaryInteractionOnContextMenu = this.executeSecondaryInteractionOnContextMenu.bind(this);
}
componentDidMount() {
if (this.props.forwardedRef) {
if (_.isFunction(this.props.forwardedRef)) {
this.props.forwardedRef(this.pressableRef);
} else if (_.isObject(this.props.forwardedRef)) {
this.props.forwardedRef.current = this.pressableRef;
}
}
this.pressableRef.addEventListener('contextmenu', this.executeSecondaryInteractionOnContextMenu);
}
componentWillUnmount() {
this.pressableRef.removeEventListener('contextmenu', this.executeSecondaryInteractionOnContextMenu);
}
/**
* @param {Event} e - the secondary interaction event
*/
executeSecondaryInteraction(e) {
if (DeviceCapabilities.hasHoverSupport() && !this.props.enableLongPressWithHover) {
return;
}
if (this.props.withoutFocusOnSecondaryInteraction && this.pressableRef) {
this.pressableRef.blur();
}
this.props.onSecondaryInteraction(e);
}
/**
* @param {contextmenu} e - A right-click MouseEvent.
* https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event
*/
executeSecondaryInteractionOnContextMenu(e) {
if (!this.props.onSecondaryInteraction) {
return;
}
e.stopPropagation();
if (this.props.preventDefaultContextMenu) {
e.preventDefault();
}
this.props.onSecondaryInteraction(e);
/**
* This component prevents the tapped element from capturing focus.
* We need to blur this element when clicked as it opens modal that implements focus-trapping.
* When the modal is closed it focuses back to the last active element.
* Therefore it shifts the element to bring it back to focus.
* https://github.com/Expensify/App/issues/14148
*/
if (this.props.withoutFocusOnSecondaryInteraction && this.pressableRef) {
this.pressableRef.blur();
}
}
render() {
const defaultPressableProps = _.omit(this.props, ['onSecondaryInteraction', 'children', 'onLongPress']);
// On Web, Text does not support LongPress events thus manage inline mode with styling instead of using Text.
return (
<PressableWithFeedback
wrapperStyle={StyleUtils.combineStyles(DeviceCapabilities.canUseTouchScreen() ? [styles.userSelectNone, styles.noSelect] : [])}
onPressIn={this.props.onPressIn}
onLongPress={this.props.onSecondaryInteraction ? this.executeSecondaryInteraction : undefined}
pressDimmingValue={this.props.activeOpacity}
onPressOut={this.props.onPressOut}
onPress={this.props.onPress}
ref={(el) => (this.pressableRef = el)}
// eslint-disable-next-line react/jsx-props-no-spreading
{...defaultPressableProps}
style={(state) => [StyleUtils.parseStyleFromFunction(this.props.style, state), ...[this.props.inline && styles.dInline]]}
>
{this.props.children}
</PressableWithFeedback>
);
}
}
PressableWithSecondaryInteraction.propTypes = pressableWithSecondaryInteractionPropTypes.propTypes;
PressableWithSecondaryInteraction.defaultProps = pressableWithSecondaryInteractionPropTypes.defaultProps;
export default React.forwardRef((props, ref) => (
<PressableWithSecondaryInteraction
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
forwardedRef={ref}
/>
));