1import { MenuView } from "@react-native-menu/menu";
2import type { ReactElement } from "react";
3import { Platform, View, type PressableProps, type StyleProp, type ViewStyle } from "react-native";
4
5import type { useMediaActions } from "../state/mediaActions";
6import { SymbolView } from "./AppSymbol";
7import { ControlPillMenu } from "./ControlPill";
8
9export function MediaActionsMenu(props: {
10 readonly media: ReturnType<typeof useMediaActions>;
11 readonly inModal?: boolean;
12 readonly children?: ReactElement<PressableProps>;
13 readonly style?: StyleProp<ViewStyle>;
14}) {
15 if (props.media.actions.length === 0) return props.children ?? null;
16 // Android's normal anchored menu lives in the app-root portal, behind native modals.
17 const nativeAndroidMenu = props.inModal && Platform.OS === "android";
18 const Menu = nativeAndroidMenu ? MenuView : ControlPillMenu;
19 return (
20 <Menu
21 title={props.media.title}
22 style={props.style}
23 shouldOpenOnLongPress={props.children !== undefined}
24 actions={props.media.actions.map(({ id, title, disabled }) => ({
25 id,
26 title,
27 attributes: { disabled: disabled ?? false },
28 }))}
29 onPressAction={({ nativeEvent }) => {
30 props.media.actions.find(({ id }) => id === nativeEvent.event)?.run();
31 }}
32 >
33 {props.children ?? (
34 <View
35 accessible
36 accessibilityRole="button"
37 accessibilityLabel="Media actions"
38 className="min-h-11 min-w-11 items-center justify-center rounded-md bg-black/60"
39 >
40 <SymbolView name="ellipsis" size={20} tintColor="#ffffff" type="monochrome" />
41 </View>
42 )}
43 </Menu>
44 );
45}