import React, { Component } from 'react'; import { StackScreenProps } from '@react-navigation/stack'; import { TouchableHighlight as RNTouchableHighlight, TouchableOpacity as RNTouchableOpacity, TouchableNativeFeedback as RNTouchableNativeFeedback, TouchableWithoutFeedback as RNTouchableWithoutFeedback, View, Text, StyleSheet, FlatList, BackgroundPropType, } from 'react-native'; import { RectButton, TouchableHighlight, TouchableNativeFeedback, TouchableOpacity, TouchableWithoutFeedback, ScrollView, } from 'react-native-gesture-handler'; const BOX_SIZE = 80; const renderSampleBox = (color?: string) => ( ); const toReactNativeTouchable = (touchable: React.ComponentType) => { if (touchable === TouchableOpacity) return RNTouchableOpacity; if (touchable === TouchableWithoutFeedback) return RNTouchableWithoutFeedback; if (touchable === TouchableHighlight) return RNTouchableHighlight; if (touchable === TouchableNativeFeedback) return RNTouchableNativeFeedback; return RNTouchableOpacity; }; type Touchables = { type: React.ComponentType; props?: Record; color?: string; renderChild: (() => null) | ((color?: string) => JSX.Element); text: string; background?: (A: typeof TouchableNativeFeedback) => BackgroundPropType; }; const TOUCHABLES: Touchables[] = [ { type: TouchableWithoutFeedback, props: {}, color: 'mediumseagreen', renderChild: renderSampleBox, text: 'TouchableWithoutFeedback doing nothing', }, { type: TouchableWithoutFeedback, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), }, color: 'papayawhip', renderChild: renderSampleBox, text: 'TouchableWithoutFeedback with callbacks', }, { type: TouchableWithoutFeedback, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), onLongPress: () => console.warn('long press'), }, color: 'powderblue', renderChild: renderSampleBox, text: 'TouchableWithoutFeedback with callbacks (with longPress)', }, { type: TouchableOpacity, props: { hitSlop: { right: 20, }, }, color: 'palegoldenrod', renderChild: renderSampleBox, text: 'TouchableOpacity with hitSlop on right', }, { type: TouchableOpacity, props: {}, color: 'green', renderChild: renderSampleBox, text: 'TouchableOpacity doing nothing', }, { type: TouchableOpacity, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), onLongPress: () => console.warn('long press'), }, color: 'violet', renderChild: renderSampleBox, text: 'TouchableOpacity with callbacks (with longPress)', }, { type: TouchableHighlight, props: {}, color: 'darksalmon', renderChild: renderSampleBox, text: "TouchableHighlight doing nothing (shouldn't be responsive)", }, { type: TouchableHighlight, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), onLongPress: () => console.warn('long press'), }, color: 'goldenrod', renderChild: renderSampleBox, text: 'TouchableHighlight with callbacks (with longPress)', }, { type: TouchableHighlight, props: { underlayColor: 'white', onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), }, color: 'forestgreen', renderChild: renderSampleBox, text: 'TouchableHighlight with callbacks (without longPress), currently GH component differs in the events sent from the RN one', }, { type: TouchableOpacity, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), delayPressIn: 1000, }, color: 'darkturquoise', renderChild: renderSampleBox, text: 'TouchableOpacity with callbacks and delayed pressIn (1000 ms)', }, { type: TouchableOpacity, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), delayPressOut: 1000, }, color: 'darkolivegreen', renderChild: renderSampleBox, text: 'TouchableOpacity with callbacks and delayed pressOut (1000 ms)', }, { type: TouchableOpacity, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), delayPressOut: 1000, delayPressIn: 1000, }, color: 'lightpink', renderChild: renderSampleBox, text: 'TouchableOpacity with callbacks and delayed pressOut and pressIn (1000 ms)', }, { type: TouchableOpacity, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), delayLongPress: 1000, }, color: 'lightsteelblue', renderChild: renderSampleBox, text: 'TouchableOpacity with callbacks and delayed longPress (1000 ms)', }, { type: TouchableOpacity, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), delayPressOut: 1000, }, color: 'lemonchiffon', renderChild: renderSampleBox, text: 'TouchableHighlight with callbacks and delayed pressOut (1000 ms)', }, { type: TouchableOpacity, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), }, renderChild: () => null, text: 'TouchableOpacity with nothing inside', }, { type: TouchableOpacity, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), style: { width: BOX_SIZE, height: BOX_SIZE, backgroundColor: 'ivory', }, }, renderChild: () => null, text: 'TouchableOpacity with nothing inside and style applied', }, { type: TouchableNativeFeedback, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), }, color: 'indigo', renderChild: renderSampleBox, text: 'Simple TouchableNativeFeedback ', }, { type: TouchableNativeFeedback, props: { onPressIn: () => console.warn('press in'), onPressOut: () => console.warn('press out'), onPress: () => console.warn('press'), }, color: 'firebrick', renderChild: renderSampleBox, text: 'Simple TouchableNativeFeedback with callbacks', }, { type: TouchableNativeFeedback, background: (A) => A.SelectableBackground(), color: 'transparent', renderChild: renderSampleBox, text: 'TouchableNativeFeedback (SelectableBackground) tranparent', }, { type: TouchableNativeFeedback, background: (A) => A.SelectableBackgroundBorderless(), color: 'honeydew', renderChild: renderSampleBox, text: 'TouchableNativeFeedback (SelectableBackgroundBorderless)', }, { type: TouchableNativeFeedback, background: (A) => A.Ripple('floralwhite', true), color: 'greenyellow', renderChild: renderSampleBox, text: 'TouchableNativeFeedback (Ripple, borderless: true)', }, { type: TouchableNativeFeedback, background: (A) => A.Ripple('blue', true, 30), color: 'green', renderChild: renderSampleBox, text: 'TouchableNativeFeedback (Ripple, borderless: true, radius: 30)', }, { type: TouchableNativeFeedback, background: (A) => A.Ripple('darkslategrey', false), color: 'dodgerblue', renderChild: renderSampleBox, text: 'TouchableNativeFeedback (Ripple, borderless: false)', }, ]; const screens: Record = TOUCHABLES.reduce( (map: Record, obj) => ((map[obj.text] = obj), map), {} ); const ItemSeparator = () => ; type ItemProps = { onPressItem: () => void; item: { text: string }; }; function Item(props: ItemProps) { const { text } = props.item; return ( props.onPressItem()}> {screens[text].text || text} ); } type TouchableParamList = { TouchableExample: { item: string; }; }; type TouchableExampleProps = StackScreenProps< TouchableParamList, 'TouchableExample' >; type TouchableExampleState = { useScrollView: boolean; }; export class TouchableExample extends Component< TouchableExampleProps, TouchableExampleState > { state = { useScrollView: true, }; private toggleScrollView = () => this.setState((prev) => ({ useScrollView: !prev.useScrollView })); render() { const { type: GHTouchable, background, props, renderChild, text, color, } = screens[this.props.route.params.item]; const RNTouchable = toReactNativeTouchable(GHTouchable); const Component: React.ComponentType = this.state.useScrollView ? ScrollView : View; return ( Use {this.state.useScrollView ? 'View' : 'ScrollView'} as a wrapper {text} {renderChild(color)} {renderChild(color)} ); } } export function TouchablesIndex({ navigation }: TouchableExampleProps) { return ( item.text} ItemSeparatorComponent={ItemSeparator} renderItem={(props) => ( navigation.navigate('TouchableExample', { item: props.item.text, }) } /> )} /> ); } const styles = StyleSheet.create({ list: { backgroundColor: '#EFEFF4', }, separator: { height: 1, backgroundColor: '#DBDBE0', }, button: { flex: 1, height: 60, padding: 10, flexDirection: 'row', alignItems: 'center', backgroundColor: '#fff', }, });