feat: add useLinkBuilder hook to build links

We need to be able to create links from a navigate action to have accessible links in the built-in components such as drawer and tabs.
This commit is contained in:
Satyajit Sahoo
2020-04-15 00:22:25 +02:00
parent 2573b5beaa
commit 2792f438fe
15 changed files with 255 additions and 69 deletions

View File

@@ -4,6 +4,7 @@ import {
StyleProp,
TextStyle,
ViewStyle,
GestureResponderEvent,
} from 'react-native';
import {
NavigationHelpers,
@@ -196,6 +197,13 @@ export type BottomTabBarProps = BottomTabBarOptions & {
navigation: NavigationHelpers<ParamListBase, BottomTabNavigationEventMap>;
};
export type BottomTabBarButtonProps = TouchableWithoutFeedbackProps & {
export type BottomTabBarButtonProps = Omit<
TouchableWithoutFeedbackProps,
'onPress'
> & {
href?: string;
children: React.ReactNode;
onPress?: (
e: React.MouseEvent<HTMLAnchorElement, MouseEvent> | GestureResponderEvent
) => void;
};

View File

@@ -14,6 +14,7 @@ import {
NavigationRouteContext,
CommonActions,
useTheme,
useLinkBuilder,
} from '@react-navigation/native';
import { useSafeArea } from 'react-native-safe-area-context';
@@ -50,6 +51,7 @@ export default function BottomTabBar({
tabStyle,
}: Props) {
const { colors } = useTheme();
const buildLink = useLinkBuilder({ navigation });
const [dimensions, setDimensions] = React.useState(() => {
const { height = 0, width = 0 } = Dimensions.get('window');
@@ -260,6 +262,7 @@ export default function BottomTabBar({
onPress={onPress}
onLongPress={onLongPress}
accessibilityLabel={accessibilityLabel}
href={buildLink(route.name, route.params)}
testID={options.tabBarTestID}
allowFontScaling={allowFontScaling}
activeTintColor={activeTintColor}

View File

@@ -4,11 +4,13 @@ import {
TouchableWithoutFeedback,
Animated,
StyleSheet,
Platform,
StyleProp,
ViewStyle,
TextStyle,
GestureResponderEvent,
} from 'react-native';
import { Route, useTheme } from '@react-navigation/native';
import { Link, Route, useTheme } from '@react-navigation/native';
import Color from 'color';
import TabBarIcon from './TabBarIcon';
@@ -37,6 +39,10 @@ type Props = {
size: number;
color: string;
}) => React.ReactNode;
/**
* URL to use for the link to the tab.
*/
href?: string;
/**
* The button for the tab. Uses a `TouchableWithoutFeedback` by default.
*/
@@ -50,13 +56,16 @@ type Props = {
*/
testID?: string;
/**
* Function to execute on press.
* Function to execute on press in React Native.
* On the web, this will use onClick.
*/
onPress: () => void;
onPress: (
e: React.MouseEvent<HTMLElement, MouseEvent> | GestureResponderEvent
) => void;
/**
* Function to execute on long press.
*/
onLongPress: () => void;
onLongPress: (e: GestureResponderEvent) => void;
/**
* Whether the label should be aligned with the icon horizontally.
*/
@@ -104,11 +113,37 @@ export default function BottomTabBarItem({
route,
label,
icon,
button = ({ children, style, ...rest }: BottomTabBarButtonProps) => (
<TouchableWithoutFeedback {...rest}>
<View style={style}>{children}</View>
</TouchableWithoutFeedback>
),
href,
button = ({
children,
style,
onPress,
href,
...rest
}: BottomTabBarButtonProps) => {
if (Platform.OS === 'web' && href) {
// React Native Web doesn't forward `onClick` if we use `TouchableWithoutFeedback`.
// We need to use `onClick` to be able to prevent default browser handling of links.
return (
<Link
{...rest}
// @ts-ignore
accessibilityRole="link"
onLink={onPress}
to={href}
style={[styles.button, style]}
>
{children}
</Link>
);
} else {
return (
<TouchableWithoutFeedback {...rest} onPress={onPress}>
<View style={style}>{children}</View>
</TouchableWithoutFeedback>
);
}
},
accessibilityLabel,
testID,
onPress,
@@ -196,6 +231,7 @@ export default function BottomTabBarItem({
: inactiveBackgroundColor;
return button({
href,
onPress,
onLongPress,
testID,
@@ -248,4 +284,7 @@ const styles = StyleSheet.create({
fontSize: 12,
marginLeft: 20,
},
button: {
display: 'flex',
},
});