Skip to content

Instantly share code, notes, and snippets.

@lyahdav
Created November 19, 2020 22:09
Show Gist options
  • Save lyahdav/8c9064aadc2a5d868097ca27a1c6207b to your computer and use it in GitHub Desktop.
Save lyahdav/8c9064aadc2a5d868097ca27a1c6207b to your computer and use it in GitHub Desktop.
import {
Image,
View,
NativeModules,
findNodeHandle,
ImageSourcePropType,
} from 'react-native';
export type MenuPlacement =
| 'top-left'
| 'top-right'
| 'bottom-left'
| 'bottom-right';
export type NativeContextMenuItemWithoutSubmenu =
| {type: 'separator'}
| {
disabled?: boolean;
icon?: ImageSourcePropType | null;
label: string;
onPress?: () => void;
checked?: boolean;
type?: 'item';
};
export type NativeContextMenuItem =
| NativeContextMenuItemWithoutSubmenu
| {
icon?: ImageSourcePropType | null;
label: string;
submenu: ReadonlyArray<NativeContextMenuItem | null | undefined>;
type?: 'submenu';
};
export type NativeContextMenuProps<T> = {
items: ReadonlyArray<NativeContextMenuItem>;
target?: View | null;
onHide?: () => void;
placement?: MenuPlacement;
};
export function notEmpty<TValue>(
value: TValue | null | undefined,
): value is TValue {
return value != null;
}
export function showNativeContextMenu<T>({
items,
target,
onHide,
placement,
}: NativeContextMenuProps<T>) {
const targetHandle = target != null ? findNodeHandle(target) : null;
const flattenedItems: Array<NativeContextMenuItem> = [];
const wrapItems = (
itemsToWrap: ReadonlyArray<NativeContextMenuItem>,
): ReadonlyArray<NativeContextMenuItem> => {
return itemsToWrap.map((item) => {
if (item.type === 'separator') {
return item;
}
const index = flattenedItems.length;
flattenedItems.push(item);
return {
...item,
index,
...('submenu' in item && {
submenu: wrapItems(item.submenu.filter(notEmpty)),
}),
icon: item.icon
? typeof item.icon === 'number'
? Image.resolveAssetSource(item.icon)
: item.icon
: null,
};
});
};
const wrappedItems = wrapItems(items);
const onPress = (error: Error, index: number) => {
const item = flattenedItems[index];
if ('onPress' in item) {
item.onPress?.();
}
onHide?.();
};
NativeModules.ContextMenuNativeModule.showMenu(
targetHandle ?? 0,
placement,
wrappedItems,
onPress,
onHide ?? (() => {}),
);
}
export function hideNativeContextMenu() {
NativeModules.ContextMenuNativeModule.hideMenu();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment