Skip to content

Commit

Permalink
Merge branch 'main' into fix/md-styles-update
Browse files Browse the repository at this point in the history
  • Loading branch information
satya164 committed Mar 7, 2024
2 parents 1b9e06f + c3459e1 commit a7cc45e
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 5 deletions.
35 changes: 35 additions & 0 deletions packages/core/src/__tests__/getStateFromPath.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2384,6 +2384,41 @@ it('uses nearest parent wildcard match for unmatched paths', () => {
).toEqual(changePath(state, '/404'));
});

it('matches screen with overlapping initial path and wildcard', () => {
const path = '/bar/42/baz/test/whatever';
const config = {
screens: {
Foo: {
screens: {
Bar: {
path: '/bar/:id/',
screens: {
Baz: 'baz',
},
},
Baz: '/bar/:id/*',
},
},
},
};

const state = {
routes: [
{
name: 'Foo',
state: {
routes: [{ name: 'Baz', params: { id: '42' }, path }],
},
},
],
};

expect(getStateFromPath<object>(path, config)).toEqual(state);
expect(
getStateFromPath<object>(getPathFromState<object>(state, config), config)
).toEqual(changePath(state, '/bar/42/Baz'));
});

it('throws if two screens map to the same pattern', () => {
const path = '/bar/42/baz/test';

Expand Down
12 changes: 9 additions & 3 deletions packages/core/src/getStateFromPath.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -300,16 +300,22 @@ const matchAgainstConfigs = (remaining: string, configs: RouteConfig[]) => {
);

routes = config.routeNames.map((name) => {
const config = configs.find((c) => c.screen === name);
const params = config?.path
const routeConfig = configs.find((c) => {
// Check matching name AND pattern in case same screen is used at different levels in config
return c.screen === name && config.pattern.startsWith(c.pattern);
});

const params = routeConfig?.path
?.split('/')
.filter((p) => p.startsWith(':'))
.reduce<Record<string, any>>((acc, p) => {
const value = matchedParams[p];

if (value) {
const key = p.replace(/^:/, '').replace(/\?$/, '');
acc[key] = config.parse?.[key] ? config.parse[key](value) : value;
acc[key] = routeConfig.parse?.[key]
? routeConfig.parse[key](value)
: value;
}

return acc;
Expand Down
3 changes: 3 additions & 0 deletions packages/material-top-tabs/src/views/MaterialTopTabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Text } from '@react-navigation/elements';
import {
type ParamListBase,
type TabNavigationState,
useLinkBuilder,
useLocale,
useTheme,
} from '@react-navigation/native';
Expand Down Expand Up @@ -47,6 +48,7 @@ export function MaterialTopTabBar({
}: MaterialTopTabBarProps) {
const { colors } = useTheme();
const { direction } = useLocale();
const { buildHref } = useLinkBuilder();

const focusedOptions = descriptors[state.routes[state.index].key].options;

Expand All @@ -62,6 +64,7 @@ export function MaterialTopTabBar({
return [
route.key,
{
href: buildHref(route.name, route.params),
testID: options.tabBarButtonTestID,
accessibilityLabel: options.tabBarAccessibilityLabel,
badge: options.tabBarBadge,
Expand Down
33 changes: 31 additions & 2 deletions packages/react-native-tab-view/src/PlatformPressable.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import * as React from 'react';
import { Platform, Pressable, type PressableProps } from 'react-native';
import {
type GestureResponderEvent,
Platform,
Pressable,
type PressableProps,
} from 'react-native';

export type Props = PressableProps & {
children: React.ReactNode;
pressColor?: string;
pressOpacity?: number;
children: React.ReactNode;
href?: string;
};

const ANDROID_VERSION_LOLLIPOP = 21;
Expand All @@ -19,12 +25,34 @@ const ANDROID_SUPPORTS_RIPPLE =
* On other platforms, you can pass the props of TouchableOpacity.
*/
export function PlatformPressable({
disabled,
android_ripple,
pressColor = 'rgba(0, 0, 0, .32)',
pressOpacity,
style,
onPress,
...rest
}: Props) {
const handlePress = (e: GestureResponderEvent) => {
// @ts-expect-error: these properties exist on web, but not in React Native
const hasModifierKey = e.metaKey || e.altKey || e.ctrlKey || e.shiftKey; // ignore clicks with modifier keys
// @ts-expect-error: these properties exist on web, but not in React Native
const isLeftClick = e.button == null || e.button === 0; // only handle left clicks
const isSelfTarget = [undefined, null, '', 'self'].includes(
// @ts-expect-error: these properties exist on web, but not in React Native
e.currentTarget?.target
); // let browser handle "target=_blank" etc.

if (Platform.OS === 'web' && rest.href != null) {
if (!hasModifierKey && isLeftClick && isSelfTarget) {
e.preventDefault();
onPress?.(e);
}
} else {
onPress?.(e);
}
};

return (
<Pressable
android_ripple={
Expand All @@ -36,6 +64,7 @@ export function PlatformPressable({
{ opacity: pressed && !ANDROID_SUPPORTS_RIPPLE ? pressOpacity : 1 },
typeof style === 'function' ? style({ pressed }) : style,
]}
onPress={disabled ? undefined : handlePress}
{...rest}
/>
);
Expand Down
2 changes: 2 additions & 0 deletions packages/react-native-tab-view/src/TabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ export function TabBar<T extends Route>({
labelText = getLabelTextDefault({ route }),
accessible = getAccessibleDefault({ route }),
accessibilityLabel = getAccessibilityLabelDefault({ route }),
href,
} = {
...commonOptions,
...options?.[route.key],
Expand Down Expand Up @@ -518,6 +519,7 @@ export function TabBar<T extends Route>({
: undefined;

const props = {
href,
key: route.key,
position,
route,
Expand Down
2 changes: 2 additions & 0 deletions packages/react-native-tab-view/src/TabBarItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ const TabBarItemInternal = <T extends Route>({
defaultTabWidth,
icon: customIcon,
badge: customBadge,
href,
labelText,
routesLength,
android_ripple = { borderless: true },
Expand Down Expand Up @@ -223,6 +224,7 @@ const TabBarItemInternal = <T extends Route>({
onLayout={onLayout}
onPress={onPress}
onLongPress={onLongPress}
href={href}
style={[styles.pressable, tabContainerStyle]}
>
<View pointerEvents="none" style={[styles.item, tabStyle]}>
Expand Down
1 change: 1 addition & 0 deletions packages/react-native-tab-view/src/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type TabDescriptor<T extends Route> = {
testID?: string;
labelText?: string;
labelAllowFontScaling?: boolean;
href?: string;
label?: (props: {
focused: boolean;
color: string;
Expand Down

0 comments on commit a7cc45e

Please sign in to comment.