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    children?: React.ReactNode;
23  },
24  FBState
25> {
26  doubleTapRef = React.createRef<TapGestureHandler>();
27
28  readonly state: FBState = {};
29
30  render() {
31    return (
32      <LongPressGestureHandler minDurationMs={800} onHandlerStateChange={this._onLongPressEvent}>
33        <TapGestureHandler
34          numberOfTaps={1}
35          waitFor={this.doubleTapRef}
36          onHandlerStateChange={this._onSingleTapEvent}>
37          <TapGestureHandler
38            numberOfTaps={2}
39            ref={this.doubleTapRef}
40            onHandlerStateChange={this._onDoubleTapEvent}>
41            <View
42              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