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',
},
});