1import React, { Component } from 'react';
2import { StyleSheet, View, StyleProp, ViewStyle } from 'react-native';
3import {
4  LongPressGestureHandler,
5  State,
6  TapGestureHandler,
7  LongPressGestureHandlerStateChangeEvent,
8  TapGestureHandlerStateChangeEvent,
9} from 'react-native-gesture-handler';
10
11interface FBState {
12  singleTap?: State;
13  longPress?: State;
14}
15
16export default class FancyButton extends Component<
17  {
18    style?: StyleProp<ViewStyle>;
19    onLongPress?: () => void;
20    onSingleTap?: () => void;
21    onDoubleTap?: () => void;
22  },
23  FBState
24> {
25  doubleTapRef = React.createRef<TapGestureHandler>();
26
27  readonly state: FBState = {};
28
29  render() {
30    return (
31      <LongPressGestureHandler minDurationMs={800} onHandlerStateChange={this._onLongPressEvent}>
32        <TapGestureHandler
33          numberOfTaps={1}
34          waitFor={this.doubleTapRef}
35          onHandlerStateChange={this._onSingleTapEvent}
36        >
37          <TapGestureHandler
38            numberOfTaps={2}
39            ref={this.doubleTapRef}
40            onHandlerStateChange={this._onDoubleTapEvent}
41          >
42            <View style={[styles.button, this.props.style, { opacity: this._isPressed() ? 0.5 : 1 }]}>
43              {this.props.children}
44            </View>
45          </TapGestureHandler>
46        </TapGestureHandler>
47      </LongPressGestureHandler>
48    );
49  }
50
51  _isPressed = () => {
52    const { longPress, singleTap } = this.state;
53
54    // Intentionally leave out double tap
55    if (longPress === State.BEGAN || singleTap === State.BEGAN) {
56      return true;
57    } else {
58      return false;
59    }
60  }
61
62  _onLongPressEvent = (event: LongPressGestureHandlerStateChangeEvent) => {
63    const { state } = event.nativeEvent;
64    this.setState({ longPress: state });
65
66    if (state === State.ACTIVE) {
67      this.props.onLongPress && this.props.onLongPress();
68    }
69  }
70
71  _onSingleTapEvent = (event: TapGestureHandlerStateChangeEvent) => {
72    const { state } = event.nativeEvent;
73    this.setState({ singleTap: state });
74
75    if (state === State.ACTIVE) {
76      this.props.onSingleTap && this.props.onSingleTap();
77    }
78  }
79
80  _onDoubleTapEvent = (event: TapGestureHandlerStateChangeEvent) => {
81    const { state } = event.nativeEvent;
82
83    if (state === State.ACTIVE) {
84      this.props.onDoubleTap && this.props.onDoubleTap();
85    }
86  }
87}
88
89const styles = StyleSheet.create({
90  button: {
91    paddingHorizontal: 30,
92    paddingVertical: 20,
93    backgroundColor: '#cacaca',
94    borderRadius: 5,
95    alignItems: 'center',
96  },
97});
98