diff --git a/apps/mobile/src/components/ui/MenuPopup.android.tsx b/apps/mobile/src/components/ui/MenuPopup.android.tsx
index 0237e3edf17aa..66a398bc21a81 100644
--- a/apps/mobile/src/components/ui/MenuPopup.android.tsx
+++ b/apps/mobile/src/components/ui/MenuPopup.android.tsx
@@ -8,7 +8,7 @@ import {
Text,
} from "@expo/ui/jetpack-compose";
import { defaultMinSize, padding, size, width } from "@expo/ui/jetpack-compose/modifiers";
-import { View } from "react-native";
+import { Pressable } from "react-native";
import { resolveScaledTextRole } from "../../lib/appearancePreferences";
import { useAndroidControlSizing } from "./useAndroidControlSizing";
@@ -16,15 +16,23 @@ import { useAppearancePreferences } from "../../features/settings/appearance/App
import type { MenuPopupProps } from "./MenuPopup";
import { isAppSymbolName, SymbolView, type AppSymbolName } from "./AppSymbol";
+// The glyph is a React Native view hosted in the Compose row, and its native host consumes
+// every touch over it, so the row's onClick never sees a tap on the icon. The glyph runs the
+// row's action itself; the row stays the accessible element.
function MenuIcon(props: {
readonly name: AppSymbolName;
+ readonly onPress: () => void;
readonly destructive?: boolean;
readonly disabled?: boolean;
}) {
const { iconSize } = useAndroidControlSizing();
return (
-
@@ -40,7 +48,7 @@ function MenuIcon(props: {
: "accent-foreground"
}
/>
-
+
);
}
@@ -60,7 +68,7 @@ export function MenuPopup(props: MenuPopupProps) {
{props.parent ? (
-
+
@@ -88,6 +96,7 @@ export function MenuPopup(props: MenuPopupProps) {
props.onPress(action)}
destructive={action.attributes?.destructive}
disabled={action.attributes?.disabled}
/>
@@ -116,11 +125,19 @@ export function MenuPopup(props: MenuPopupProps) {
{(action.subactions?.length ?? 0) > 0 ? (
-
+ props.onPress(action)}
+ disabled={action.attributes?.disabled}
+ />
) : action.state === "on" ? (
-
+ props.onPress(action)}
+ disabled={action.attributes?.disabled}
+ />
) : null}