import React from 'react'; import { StyleSheet } from 'react-native'; import Animated, { runOnJS, useAnimatedProps, useAnimatedReaction, useAnimatedStyle, useDerivedValue, useSharedValue, withSpring, withTiming, } from 'react-native-reanimated'; import { calculateMenuHeight, menuAnimationAnchor, } from '../../utils/calculations'; import { BlurView } from 'expo-blur'; import MenuItems from './MenuItems'; import { SPRING_CONFIGURATION_MENU, HOLD_ITEM_TRANSFORM_DURATION, IS_IOS, CONTEXT_MENU_STATE, } from '../../constants'; import styles from './styles'; import { MenuItemProps } from './types'; import { useInternal } from '../../hooks'; import { deepEqual } from '../../utils/validations'; import { leftOrRight } from './calculations'; const AnimatedView = Animated.createAnimatedComponent(BlurView); const MenuListComponent = () => { const { state, theme, menuProps } = useInternal(); const [itemList, setItemList] = React.useState([]); const menuHeight = useDerivedValue(() => { const itemsWithSeparator = menuProps.value.items.filter( item => item.withSeparator ); return calculateMenuHeight( menuProps.value.items.length, itemsWithSeparator.length ); }, [menuProps]); const prevList = useSharedValue([]); const messageStyles = useAnimatedStyle(() => { const itemsWithSeparator = menuProps.value.items.filter( item => item.withSeparator ); const translate = menuAnimationAnchor( menuProps.value.anchorPosition, menuProps.value.itemWidth, menuProps.value.items.length, itemsWithSeparator.length ); const _leftPosition = leftOrRight(menuProps); const menuScaleAnimation = () => state.value === CONTEXT_MENU_STATE.ACTIVE ? withSpring(1, SPRING_CONFIGURATION_MENU) : withTiming(0, { duration: HOLD_ITEM_TRANSFORM_DURATION, }); const opacityAnimation = () => withTiming(state.value === CONTEXT_MENU_STATE.ACTIVE ? 1 : 0, { duration: HOLD_ITEM_TRANSFORM_DURATION, }); return { left: _leftPosition, height: menuHeight.value, opacity: opacityAnimation(), transform: [ { translateX: translate.beginningTransformations.translateX }, { translateY: translate.beginningTransformations.translateY }, { scale: menuScaleAnimation(), }, { translateX: translate.endingTransformations.translateX }, { translateY: translate.endingTransformations.translateY }, ], }; }); const animatedInnerContainerStyle = useAnimatedStyle(() => { return { backgroundColor: theme.value === 'light' ? IS_IOS ? 'rgba(255, 255, 255, .75)' : 'rgba(255, 255, 255, .95)' : IS_IOS ? 'rgba(0,0,0,0.5)' : 'rgba(39, 39, 39, .8)', }; }, [theme]); const animatedProps = useAnimatedProps(() => { return { tint: theme.value }; }, [theme]); const setter = (items: MenuItemProps[]) => { setItemList(items); prevList.value = items; }; useAnimatedReaction( () => menuProps.value.items, _items => { if (!deepEqual(_items, prevList.value)) { runOnJS(setter)(_items); } }, [menuProps] ); return ( ); }; const MenuList = React.memo(MenuListComponent); export default MenuList;