mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-29 04:45:19 +08:00
feat: add a useLinkProps hook
This commit is contained in:
@@ -1,10 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { Text, TextProps, Platform, GestureResponderEvent } from 'react-native';
|
||||
import {
|
||||
NavigationAction,
|
||||
NavigationHelpersContext,
|
||||
} from '@react-navigation/core';
|
||||
import useLinkTo from './useLinkTo';
|
||||
import { Text, TextProps, GestureResponderEvent } from 'react-native';
|
||||
import { NavigationAction } from '@react-navigation/core';
|
||||
import useLinkProps from './useLinkProps';
|
||||
|
||||
type Props = {
|
||||
to: string;
|
||||
@@ -20,9 +17,8 @@ type Props = {
|
||||
* @param props.action Optional action to use for in-page navigation. By default, the path is parsed to an action based on linking config.
|
||||
* @param props.children Child elements to render the content.
|
||||
*/
|
||||
export default function Link({ to, action, children, ...rest }: Props) {
|
||||
const navigation = React.useContext(NavigationHelpersContext);
|
||||
const linkTo = useLinkTo();
|
||||
export default function Link({ to, action, ...rest }: Props) {
|
||||
const props = useLinkProps({ to, action });
|
||||
|
||||
const onPress = (
|
||||
e: React.MouseEvent<HTMLAnchorElement, MouseEvent> | GestureResponderEvent
|
||||
@@ -32,44 +28,16 @@ export default function Link({ to, action, children, ...rest }: Props) {
|
||||
rest.onPress?.(e);
|
||||
}
|
||||
|
||||
let shouldHandle = false;
|
||||
|
||||
if (Platform.OS !== 'web' || !event) {
|
||||
shouldHandle = event ? !e.defaultPrevented : true;
|
||||
} else if (
|
||||
!e.defaultPrevented && // onPress prevented default
|
||||
// @ts-ignore
|
||||
!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) && // ignore clicks with modifier keys
|
||||
// @ts-ignore
|
||||
(e.button == null || e.button === 0) && // ignore everything but left clicks
|
||||
(rest.target == null || rest.target === '_self') // let browser handle "target=_blank" etc.
|
||||
) {
|
||||
event.preventDefault();
|
||||
shouldHandle = true;
|
||||
}
|
||||
|
||||
if (shouldHandle) {
|
||||
if (action) {
|
||||
if (navigation) {
|
||||
navigation.dispatch(action);
|
||||
} else {
|
||||
throw new Error("Couldn't find a navigation object.");
|
||||
}
|
||||
} else {
|
||||
linkTo(to);
|
||||
}
|
||||
if (props.onClick) {
|
||||
props.onClick(e);
|
||||
} else {
|
||||
props.onPress(e);
|
||||
}
|
||||
};
|
||||
|
||||
const props = {
|
||||
href: to,
|
||||
accessibilityRole: 'link' as const,
|
||||
...Platform.select({
|
||||
web: { onClick: onPress } as any,
|
||||
default: { onPress },
|
||||
}),
|
||||
return React.createElement(Text, {
|
||||
...props,
|
||||
...rest,
|
||||
};
|
||||
|
||||
return <Text {...props}>{children}</Text>;
|
||||
...(props.onClick ? { onClick: onPress } : { onPress }),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,4 +13,5 @@ export { default as useTheme } from './theming/useTheme';
|
||||
export { default as Link } from './Link';
|
||||
export { default as useLinking } from './useLinking';
|
||||
export { default as useLinkTo } from './useLinkTo';
|
||||
export { default as useLinkProps } from './useLinkProps';
|
||||
export { default as useLinkBuilder } from './useLinkBuilder';
|
||||
|
||||
65
packages/native/src/useLinkProps.tsx
Normal file
65
packages/native/src/useLinkProps.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import * as React from 'react';
|
||||
import { Platform, GestureResponderEvent } from 'react-native';
|
||||
import {
|
||||
NavigationAction,
|
||||
NavigationHelpersContext,
|
||||
} from '@react-navigation/core';
|
||||
import useLinkTo from './useLinkTo';
|
||||
|
||||
type Props = {
|
||||
to: string;
|
||||
action?: NavigationAction;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to get props for an anchor tag so it can work with in page navigation.
|
||||
*
|
||||
* @param props.to Absolute path to screen (e.g. `/feeds/hot`).
|
||||
* @param props.action Optional action to use for in-page navigation. By default, the path is parsed to an action based on linking config.
|
||||
*/
|
||||
export default function useLinkProps({ to, action }: Props) {
|
||||
const navigation = React.useContext(NavigationHelpersContext);
|
||||
const linkTo = useLinkTo();
|
||||
|
||||
const onPress = (
|
||||
e: React.MouseEvent<HTMLAnchorElement, MouseEvent> | GestureResponderEvent
|
||||
) => {
|
||||
let shouldHandle = false;
|
||||
|
||||
if (Platform.OS !== 'web' || !e) {
|
||||
shouldHandle = e ? !e.defaultPrevented : true;
|
||||
} else if (
|
||||
!e.defaultPrevented && // onPress prevented default
|
||||
// @ts-ignore
|
||||
!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) && // ignore clicks with modifier keys
|
||||
// @ts-ignore
|
||||
(e.button == null || e.button === 0) && // ignore everything but left clicks
|
||||
// @ts-ignore
|
||||
[undefined, null, '', 'self'].includes(e.currentTarget?.target) // let browser handle "target=_blank" etc.
|
||||
) {
|
||||
e.preventDefault();
|
||||
shouldHandle = true;
|
||||
}
|
||||
|
||||
if (shouldHandle) {
|
||||
if (action) {
|
||||
if (navigation) {
|
||||
navigation.dispatch(action);
|
||||
} else {
|
||||
throw new Error("Couldn't find a navigation object.");
|
||||
}
|
||||
} else {
|
||||
linkTo(to);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
href: to,
|
||||
accessibilityRole: 'link' as const,
|
||||
...Platform.select({
|
||||
web: { onClick: onPress } as any,
|
||||
default: { onPress },
|
||||
}),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user