Hold To Open Menu
A button which changes it’s appearance if tapped
import { Text, SafeAreaView, StyleSheet, View, TouchableOpacity,Alert } from 'react-native';import HoldMenu from '../components/holdMenu';
//or if you're using npm package//import HoldMenu from '@cascadeui/hold-menu'
const menuItems = [ { id: '1', label: 'Edit', onPress: () => Alert.alert('Edit pressed'), }, { id: '2', label: 'Delete', onPress: () => Alert.alert('Delete pressed'), }, { id: '3', label: 'Share', onPress: () => Alert.alert('Share pressed'), }, ];
const App = () => { return ( <View style={styles.container}>
<HoldMenu items={menuItems}> <View style={{ padding: 20, borderRadius: 8 ,backgroundColor:'#f2f2f2'}}> <Text>Hold me to open menu</Text> </View> </HoldMenu>
</View> );}
export default AppInstallation
npm install @cascadeui/hold-menu- Copy core component
src/components/animatedTabs.tsximport React, { useState, useRef } from 'react';import {View,Modal,StyleSheet,Pressable,Animated,TouchableWithoutFeedback,Text,ViewStyle,TextStyle,PressableProps,} from 'react-native';interface MenuItem {id: string | number;label: string;onPress?: () => void;}interface HoldMenuProps {children: React.ReactNode;items: MenuItem[];holdDuration?: number;menuStyle?: ViewStyle;menuItemStyle?: ViewStyle;menuItemTextStyle?: TextStyle;overlayColor?: string;triggerStyle?: ViewStyle;onOpen?: () => void;onClose?: () => void;}interface MenuItemComponentProps extends PressableProps {item: MenuItem;textStyle?: any;style?: any;onItemPress: (item: MenuItem) => void;}const MenuItemComponent: React.FC<MenuItemComponentProps> = ({item,textStyle,style,onItemPress,...pressableProps}) => (<Pressablestyle={style}onPress={() => onItemPress(item)}{...pressableProps}><Text style={textStyle}>{item.label}</Text></Pressable>);const HoldMenu: React.FC<HoldMenuProps> = ({children,items,holdDuration = 500,menuStyle,menuItemStyle,menuItemTextStyle,overlayColor = 'rgba(0, 0, 0, 0.5)',triggerStyle,onOpen,onClose,}) => {const [menuVisible, setMenuVisible] = useState<boolean>(false);const timeoutRef = useRef<NodeJS.Timeout | null>(null);const scaleAnim = useRef(new Animated.Value(0)).current;const handlePressIn = () => {timeoutRef.current = setTimeout(() => {setMenuVisible(true);onOpen?.();Animated.spring(scaleAnim, {toValue: 1,useNativeDriver: true,tension: 65,friction: 7,}).start();}, holdDuration);};const handlePressOut = () => {if (timeoutRef.current) {clearTimeout(timeoutRef.current);}};const closeMenu = () => {Animated.timing(scaleAnim, {toValue: 0,duration: 200,useNativeDriver: true,}).start(() => {setMenuVisible(false);onClose?.();});};const handleMenuItemPress = (item: MenuItem) => {item.onPress?.();closeMenu();};return (<View><PressableonPressIn={handlePressIn}onPressOut={handlePressOut}style={[styles.trigger, triggerStyle]}>{children}</Pressable><Modalvisible={menuVisible}transparentanimationType="none"onRequestClose={closeMenu}><TouchableWithoutFeedback onPress={closeMenu}><View style={[styles.modalOverlay, { backgroundColor: overlayColor }]}><TouchableWithoutFeedback><Animated.Viewstyle={[styles.menuContainer,menuStyle,{transform: [{ scale: scaleAnim }],},]}>{items.map((item) => (<MenuItemComponentkey={item.id}item={item}style={[styles.menuItem, menuItemStyle]}textStyle={[styles.menuItemText, menuItemTextStyle]}onItemPress={handleMenuItemPress}/>))}</Animated.View></TouchableWithoutFeedback></View></TouchableWithoutFeedback></Modal></View>);};const styles = StyleSheet.create({trigger: {// Base trigger styles},modalOverlay: {flex: 1,justifyContent: 'center',alignItems: 'center',},menuContainer: {backgroundColor: 'white',borderRadius: 8,padding: 8,minWidth: 200,shadowColor: '#000',shadowOffset: {width: 0,height: 2,},shadowOpacity: 0.25,shadowRadius: 3.84,elevation: 5,},menuItem: {padding: 12,borderBottomWidth: 1,borderBottomColor: '#eee',},menuItemText: {fontSize: 16,color: '#333',},});export default HoldMenu;
Props
| Prop | Type | Description |
|---|---|---|
items | menuItem[] | Array of objects containing 3 properties: id(string), label(string) and onPress(callback function). |
holdDuration | number | how much longer user should hold to open the menu. |
menuStyle | Viewstyle | Style of the menu container. |
menuItemStyle | Viewstyle | Style of the menu Item. |
menuItemTextStyle | Viewstyle | Style of the menu Text. |
overlayColor | string | color of the menu overlay. |
onOpen | callback | function to be called when menu opens |
onClose | callback | function to be called when menu closes |