UNPKG

2.36 kBTypeScriptView Raw
1import {
2 NavigationAction,
3 NavigationContainerRefContext,
4 NavigationHelpersContext,
5} from '@react-navigation/core';
6import * as React from 'react';
7import { GestureResponderEvent, Platform } from 'react-native';
8
9import useLinkTo, { To } from './useLinkTo';
10
11type Props<ParamList extends ReactNavigation.RootParamList> = {
12 to: To<ParamList>;
13 action?: NavigationAction;
14};
15
16/**
17 * Hook to get props for an anchor tag so it can work with in page navigation.
18 *
19 * @param props.to Absolute path to screen (e.g. `/feeds/hot`).
20 * @param props.action Optional action to use for in-page navigation. By default, the path is parsed to an action based on linking config.
21 */
22export default function useLinkProps<
23 ParamList extends ReactNavigation.RootParamList
24>({ to, action }: Props<ParamList>) {
25 const root = React.useContext(NavigationContainerRefContext);
26 const navigation = React.useContext(NavigationHelpersContext);
27 const linkTo = useLinkTo<ParamList>();
28
29 const onPress = (
30 e?: React.MouseEvent<HTMLAnchorElement, MouseEvent> | GestureResponderEvent
31 ) => {
32 let shouldHandle = false;
33
34 if (Platform.OS !== 'web' || !e) {
35 shouldHandle = e ? !e.defaultPrevented : true;
36 } else if (
37 !e.defaultPrevented && // onPress prevented default
38 // @ts-expect-error: these properties exist on web, but not in React Native
39 !(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) && // ignore clicks with modifier keys
40 // @ts-expect-error: these properties exist on web, but not in React Native
41 (e.button == null || e.button === 0) && // ignore everything but left clicks
42 // @ts-expect-error: these properties exist on web, but not in React Native
43 [undefined, null, '', 'self'].includes(e.currentTarget?.target) // let browser handle "target=_blank" etc.
44 ) {
45 e.preventDefault();
46 shouldHandle = true;
47 }
48
49 if (shouldHandle) {
50 if (action) {
51 if (navigation) {
52 navigation.dispatch(action);
53 } else if (root) {
54 root.dispatch(action);
55 } else {
56 throw new Error(
57 "Couldn't find a navigation object. Is your component inside NavigationContainer?"
58 );
59 }
60 } else {
61 linkTo(to);
62 }
63 }
64 };
65
66 return {
67 href: to,
68 accessibilityRole: 'link' as const,
69 onPress,
70 };
71}