mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-10-16 01:05:42 -04:00
fix(native): let Android menus open from their trigger
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
5 files changed
+56
-17
No files matched your search
@@ -46,6 +46,7 @@ import { SettingsRow } from "@/components/settings/settings-row";
|
|||||||
import { SettingsSection } from "@/components/settings/settings-section";
|
import { SettingsSection } from "@/components/settings/settings-section";
|
||||||
import { TmdbLogo } from "@/components/tmdb-logo";
|
import { TmdbLogo } from "@/components/tmdb-logo";
|
||||||
import { Image } from "@/components/ui/image";
|
import { Image } from "@/components/ui/image";
|
||||||
|
import { MenuTrigger } from "@/components/ui/menu-trigger";
|
||||||
import { ScaledIcon } from "@/components/ui/scaled-icon";
|
import { ScaledIcon } from "@/components/ui/scaled-icon";
|
||||||
import { Spinner } from "@/components/ui/spinner";
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
@@ -285,8 +286,7 @@ export default function SettingsScreen() {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Pressable
|
<MenuTrigger
|
||||||
accessibilityRole="button"
|
|
||||||
accessibilityLabel={t`Edit profile photo`}
|
accessibilityLabel={t`Edit profile photo`}
|
||||||
accessibilityHint={t`Opens options to change or remove your photo`}
|
accessibilityHint={t`Opens options to change or remove your photo`}
|
||||||
className="mr-3"
|
className="mr-3"
|
||||||
@@ -308,7 +308,7 @@ export default function SettingsScreen() {
|
|||||||
<View className="bg-primary absolute right-0 bottom-0 size-[18px] items-center justify-center rounded-full">
|
<View className="bg-primary absolute right-0 bottom-0 size-[18px] items-center justify-center rounded-full">
|
||||||
<IconCamera size={10} color={primaryFgColor} />
|
<IconCamera size={10} color={primaryFgColor} />
|
||||||
</View>
|
</View>
|
||||||
</Pressable>
|
</MenuTrigger>
|
||||||
</MenuView>
|
</MenuView>
|
||||||
) : (
|
) : (
|
||||||
<Pressable
|
<Pressable
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { MenuView } from "@expo/ui/community/menu";
|
import { MenuView } from "@expo/ui/community/menu";
|
||||||
import { useLingui } from "@lingui/react/macro";
|
import { useLingui } from "@lingui/react/macro";
|
||||||
import type { Icon } from "@tabler/icons-react-native";
|
import type { Icon } from "@tabler/icons-react-native";
|
||||||
import { Pressable, View } from "react-native";
|
import { View } from "react-native";
|
||||||
|
|
||||||
|
import { MenuTrigger } from "@/components/ui/menu-trigger";
|
||||||
import { ScaledIcon } from "@/components/ui/scaled-icon";
|
import { ScaledIcon } from "@/components/ui/scaled-icon";
|
||||||
import { Sparkline } from "@/components/ui/sparkline";
|
import { Sparkline } from "@/components/ui/sparkline";
|
||||||
import { Text } from "@/components/ui/text";
|
import { Text } from "@/components/ui/text";
|
||||||
@@ -96,13 +97,11 @@ export function StatsCard(props: StatsCardProps) {
|
|||||||
const nextPeriod = periods.find((value) => value === nativeEvent.event);
|
const nextPeriod = periods.find((value) => value === nativeEvent.event);
|
||||||
if (nextPeriod) onPeriodChange(nextPeriod);
|
if (nextPeriod) onPeriodChange(nextPeriod);
|
||||||
}}
|
}}
|
||||||
|
onOpenMenu={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)}
|
||||||
>
|
>
|
||||||
<Pressable
|
<MenuTrigger onPress={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)}>
|
||||||
onPress={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)}
|
|
||||||
accessibilityRole="button"
|
|
||||||
>
|
|
||||||
<CardInner {...props} />
|
<CardInner {...props} />
|
||||||
</Pressable>
|
</MenuTrigger>
|
||||||
</MenuView>
|
</MenuView>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ import { Icon } from "@expo/ui";
|
|||||||
import { MenuView } from "@expo/ui/community/menu";
|
import { MenuView } from "@expo/ui/community/menu";
|
||||||
import { useLingui } from "@lingui/react/macro";
|
import { useLingui } from "@lingui/react/macro";
|
||||||
import { useRouter } from "expo-router";
|
import { useRouter } from "expo-router";
|
||||||
import { Alert, Pressable, View } from "react-native";
|
import { Alert, View } from "react-native";
|
||||||
|
|
||||||
import { Image } from "@/components/ui/image";
|
import { Image } from "@/components/ui/image";
|
||||||
|
import { MenuTrigger } from "@/components/ui/menu-trigger";
|
||||||
import { Text } from "@/components/ui/text";
|
import { Text } from "@/components/ui/text";
|
||||||
import { queryClient } from "@/lib/query-client";
|
import { queryClient } from "@/lib/query-client";
|
||||||
import { authClient } from "@/lib/server";
|
import { authClient } from "@/lib/server";
|
||||||
@@ -58,10 +59,10 @@ export function HeaderAvatar() {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
onOpenMenu={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)}
|
||||||
>
|
>
|
||||||
<Pressable
|
<MenuTrigger
|
||||||
onPress={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)}
|
onPress={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)}
|
||||||
accessibilityRole="button"
|
|
||||||
accessibilityLabel={t`User menu`}
|
accessibilityLabel={t`User menu`}
|
||||||
hitSlop={8}
|
hitSlop={8}
|
||||||
>
|
>
|
||||||
@@ -84,7 +85,7 @@ export function HeaderAvatar() {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</Pressable>
|
</MenuTrigger>
|
||||||
</MenuView>
|
</MenuView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { MenuView } from "@expo/ui/community/menu";
|
import { MenuView } from "@expo/ui/community/menu";
|
||||||
import { useLingui } from "@lingui/react/macro";
|
import { useLingui } from "@lingui/react/macro";
|
||||||
import { IconArrowsSort } from "@tabler/icons-react-native";
|
import { IconArrowsSort } from "@tabler/icons-react-native";
|
||||||
import { Pressable } from "react-native";
|
|
||||||
import { useCSSVariable } from "uniwind";
|
import { useCSSVariable } from "uniwind";
|
||||||
|
|
||||||
|
import { MenuTrigger } from "@/components/ui/menu-trigger";
|
||||||
import { ScaledIcon } from "@/components/ui/scaled-icon";
|
import { ScaledIcon } from "@/components/ui/scaled-icon";
|
||||||
import * as Haptics from "@/utils/haptics";
|
import * as Haptics from "@/utils/haptics";
|
||||||
|
|
||||||
@@ -49,15 +49,15 @@ export function SortMenu({ sortBy, sortDirection, onSortChange }: SortMenuProps)
|
|||||||
);
|
);
|
||||||
if (option) onSortChange(option.sortBy, option.sortDirection);
|
if (option) onSortChange(option.sortBy, option.sortDirection);
|
||||||
}}
|
}}
|
||||||
|
onOpenMenu={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)}
|
||||||
>
|
>
|
||||||
<Pressable
|
<MenuTrigger
|
||||||
onPress={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)}
|
onPress={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)}
|
||||||
accessibilityRole="button"
|
|
||||||
accessibilityLabel={t`Sort`}
|
accessibilityLabel={t`Sort`}
|
||||||
hitSlop={8}
|
hitSlop={8}
|
||||||
>
|
>
|
||||||
<ScaledIcon icon={IconArrowsSort} size={22} color={foregroundColor} />
|
<ScaledIcon icon={IconArrowsSort} size={22} color={foregroundColor} />
|
||||||
</Pressable>
|
</MenuTrigger>
|
||||||
</MenuView>
|
</MenuView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import type { ReactNode } from "react";
|
||||||
|
import { Pressable, type PressableProps, View } from "react-native";
|
||||||
|
|
||||||
|
type MenuTriggerProps = Pick<
|
||||||
|
PressableProps,
|
||||||
|
| "onPress"
|
||||||
|
| "hitSlop"
|
||||||
|
| "accessibilityLabel"
|
||||||
|
| "accessibilityHint"
|
||||||
|
| "accessibilityRole"
|
||||||
|
| "className"
|
||||||
|
> & {
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Child for `MenuView`. On Android, MenuView opens from its own wrapping Pressable, so the
|
||||||
|
* trigger must not be touchable (an inner Pressable would swallow the tap). On iOS the SwiftUI
|
||||||
|
* Menu handles the tap natively, so keep a Pressable for press feedback.
|
||||||
|
*/
|
||||||
|
export function MenuTrigger({ children, onPress, hitSlop, ...a11y }: MenuTriggerProps) {
|
||||||
|
if (process.env.EXPO_OS === "android") {
|
||||||
|
return (
|
||||||
|
<View accessible {...a11y} accessibilityRole={a11y.accessibilityRole ?? "button"}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
onPress={onPress}
|
||||||
|
hitSlop={hitSlop}
|
||||||
|
{...a11y}
|
||||||
|
accessibilityRole={a11y.accessibilityRole ?? "button"}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Pressable>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user