refactor: migrate to Pressable

This commit is contained in:
Satyajit Sahoo
2021-02-22 00:47:04 +01:00
parent 205f297d07
commit f49b0d3a3b
8 changed files with 53 additions and 75 deletions

View File

@@ -24,10 +24,10 @@ const getTabBarIcon = (name: string) => ({
}) => <MaterialCommunityIcons name={name} color={color} size={size} />;
type BottomTabParams = {
Article: NavigatorScreenParams<SimpleStackParams>;
Albums: undefined;
Contacts: undefined;
Chat: undefined;
TabStack: NavigatorScreenParams<SimpleStackParams>;
TabAlbums: undefined;
TabContacts: undefined;
TabChat: undefined;
};
const BottomTabs = createBottomTabNavigator<BottomTabParams>();
@@ -58,7 +58,7 @@ export default function BottomTabsScreen({
}}
>
<BottomTabs.Screen
name="Article"
name="TabStack"
component={SimpleStackScreen}
options={{
title: 'Article',
@@ -66,7 +66,7 @@ export default function BottomTabsScreen({
}}
/>
<BottomTabs.Screen
name="Chat"
name="TabChat"
component={Chat}
options={{
tabBarLabel: 'Chat',
@@ -75,7 +75,7 @@ export default function BottomTabsScreen({
}}
/>
<BottomTabs.Screen
name="Contacts"
name="TabContacts"
component={Contacts}
options={{
title: 'Contacts',
@@ -83,7 +83,7 @@ export default function BottomTabsScreen({
}}
/>
<BottomTabs.Screen
name="Albums"
name="TabAlbums"
component={Albums}
options={{
title: 'Albums',

View File

@@ -8,10 +8,10 @@ import Chat from '../Shared/Chat';
import SimpleStackScreen, { SimpleStackParams } from './SimpleStack';
type MaterialBottomTabParams = {
Article: NavigatorScreenParams<SimpleStackParams>;
Albums: undefined;
Contacts: undefined;
Chat: undefined;
TabStack: NavigatorScreenParams<SimpleStackParams>;
TabAlbums: undefined;
TabContacts: undefined;
TabChat: undefined;
};
const MaterialBottomTabs = createMaterialBottomTabNavigator<MaterialBottomTabParams>();
@@ -20,7 +20,7 @@ export default function MaterialBottomTabsScreen() {
return (
<MaterialBottomTabs.Navigator barStyle={styles.tabBar}>
<MaterialBottomTabs.Screen
name="Article"
name="TabStack"
options={{
tabBarLabel: 'Article',
tabBarIcon: 'file-document',
@@ -35,7 +35,7 @@ export default function MaterialBottomTabsScreen() {
)}
</MaterialBottomTabs.Screen>
<MaterialBottomTabs.Screen
name="Chat"
name="TabChat"
component={Chat}
options={{
tabBarLabel: 'Chat',
@@ -45,7 +45,7 @@ export default function MaterialBottomTabsScreen() {
}}
/>
<MaterialBottomTabs.Screen
name="Contacts"
name="TabContacts"
component={Contacts}
options={{
tabBarLabel: 'Contacts',
@@ -54,7 +54,7 @@ export default function MaterialBottomTabsScreen() {
}}
/>
<MaterialBottomTabs.Screen
name="Albums"
name="TabAlbums"
component={Albums}
options={{
tabBarLabel: 'Albums',

View File

@@ -1,8 +1,7 @@
import React from 'react';
import {
View,
Text,
TouchableWithoutFeedback,
Pressable,
StyleSheet,
Platform,
StyleProp,
@@ -159,13 +158,14 @@ export default function BottomTabBarItem({
);
} else {
return (
<TouchableWithoutFeedback
<Pressable
{...rest}
accessibilityRole={accessibilityRole}
onPress={onPress}
style={style}
>
<View style={style}>{children}</View>
</TouchableWithoutFeedback>
{children}
</Pressable>
);
}
},

View File

@@ -10,7 +10,7 @@ import {
StyleProp,
View,
InteractionManager,
TouchableWithoutFeedback,
Pressable,
} from 'react-native';
import Animated from 'react-native-reanimated';
import {
@@ -661,13 +661,13 @@ export default class DrawerView extends React.Component<Props> {
drawerType === 'permanent' ? null : Platform.OS === 'web' ||
Platform.OS === 'windows' ||
Platform.OS === 'macos' ? (
<TouchableWithoutFeedback
<Pressable
onPress={
gestureEnabled ? () => this.toggleDrawer(false) : undefined
}
>
<Overlay progress={progress} style={overlayStyle as any} />
</TouchableWithoutFeedback>
</Pressable>
) : (
<TapGestureHandler
enabled={gestureEnabled}

View File

@@ -79,15 +79,17 @@ type Props = {
style?: StyleProp<ViewStyle>;
};
const Touchable = ({
const LinkPressable = ({
children,
style,
onPress,
onLongPress,
to,
accessibilityRole,
delayPressIn,
...rest
}: React.ComponentProps<typeof PlatformPressable> & {
}: Omit<React.ComponentProps<typeof PlatformPressable>, 'style'> & {
style: StyleProp<ViewStyle>;
} & {
to?: string;
children: React.ReactNode;
onPress?: () => void;
@@ -109,6 +111,7 @@ const Touchable = ({
onPress?.(e);
}
}}
onLongPress={onLongPress ?? undefined}
>
{children}
</Link>
@@ -118,7 +121,6 @@ const Touchable = ({
<PlatformPressable
{...rest}
accessibilityRole={accessibilityRole}
delayPressIn={delayPressIn}
onPress={onPress}
>
<View style={style}>{children}</View>
@@ -164,8 +166,7 @@ export default function DrawerItem(props: Props) {
{...rest}
style={[styles.container, { borderRadius, backgroundColor }, style]}
>
<Touchable
delayPressIn={0}
<LinkPressable
onPress={onPress}
style={[styles.wrapper, { borderRadius }]}
accessibilityRole="button"
@@ -200,7 +201,7 @@ export default function DrawerItem(props: Props) {
)}
</View>
</React.Fragment>
</Touchable>
</LinkPressable>
</View>
);
}

View File

@@ -23,14 +23,13 @@ export default function DrawerToggleButton({ tintColor, ...rest }: Props) {
{...rest}
accessible
accessibilityRole="button"
delayPressIn={0}
android_ripple={{ borderless: true }}
onPress={() => navigation.dispatch(DrawerActions.toggleDrawer())}
style={styles.touchable}
hitSlop={Platform.select({
ios: undefined,
default: { top: 16, right: 16, bottom: 16, left: 16 },
})}
borderless
>
<Image
style={[styles.icon, tintColor ? { tintColor } : null]}

View File

@@ -155,15 +155,14 @@ export default function HeaderBackButton({
accessibilityRole="button"
accessibilityLabel={accessibilityLabel}
testID={testID}
delayPressIn={0}
onPress={disabled ? undefined : handlePress}
pressColor={pressColorAndroid}
android_ripple={{ borderless: true }}
style={[styles.container, disabled && styles.disabled, style]}
hitSlop={Platform.select({
ios: undefined,
default: { top: 16, right: 16, bottom: 16, left: 16 },
})}
borderless
>
<React.Fragment>
{renderBackImage()}

View File

@@ -1,21 +1,15 @@
import * as React from 'react';
import {
Platform,
TouchableNativeFeedback,
TouchableOpacity,
View,
TouchableWithoutFeedbackProps,
} from 'react-native';
import { Platform, Pressable, PressableProps } from 'react-native';
export type Props = TouchableWithoutFeedbackProps & {
export type Props = PressableProps & {
pressColor?: string;
pressOpacity?: number;
disabled?: boolean | null;
borderless?: boolean;
children: React.ReactNode;
};
const ANDROID_VERSION_LOLLIPOP = 21;
const ANDROID_SUPPORTS_RIPPLE =
Platform.OS === 'android' && Platform.Version >= ANDROID_VERSION_LOLLIPOP;
/**
* PlatformPressable provides an abstraction on top of TouchableNativeFeedback and
@@ -25,39 +19,24 @@ const ANDROID_VERSION_LOLLIPOP = 21;
* On other platforms, you can pass the props of TouchableOpacity.
*/
export default function PlatformPressable({
borderless = false,
android_ripple,
pressColor = 'rgba(0, 0, 0, .32)',
pressOpacity,
style,
children,
...rest
}: Props) {
/*
* TouchableNativeFeedback.Ripple causes a crash on old Android versions,
* therefore only enable it on Android Lollipop and above.
*
* All touchables on Android should have the ripple effect according to
* platform design guidelines.
* We need to pass the background prop to specify a borderless ripple effect.
*/
if (
Platform.OS === 'android' &&
Platform.Version >= ANDROID_VERSION_LOLLIPOP
) {
return (
<TouchableNativeFeedback
{...rest}
useForeground={TouchableNativeFeedback.canUseNativeForeground()}
background={TouchableNativeFeedback.Ripple(pressColor, borderless)}
>
<View style={style}>{React.Children.only(children)}</View>
</TouchableNativeFeedback>
);
} else {
return (
<TouchableOpacity style={style} activeOpacity={pressOpacity} {...rest}>
{children}
</TouchableOpacity>
);
}
return (
<Pressable
android_ripple={
ANDROID_SUPPORTS_RIPPLE
? { color: pressColor, ...android_ripple }
: undefined
}
style={({ pressed }) => [
{ opacity: pressed && !ANDROID_SUPPORTS_RIPPLE ? pressOpacity : 1 },
typeof style === 'function' ? style({ pressed }) : style,
]}
{...rest}
/>
);
}