import React from 'react'; import { StyleSheet, Text, ViewStyle } from 'react-native'; import { TapGestureHandler, TapGestureHandlerStateChangeEvent } from 'react-native-gesture-handler'; import Animated, { interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedStyle, useSharedValue, } from 'react-native-reanimated'; import { MessageAction as MessageActionType, MessageOverlayData, useMessageOverlayContext, } from '../../contexts/messageOverlayContext/MessageOverlayContext'; import { useTheme } from '../../contexts/themeContext/ThemeContext'; import { vw } from '../../utils/utils'; import type { DefaultAttachmentType, DefaultChannelType, DefaultCommandType, DefaultEventType, DefaultMessageType, DefaultReactionType, DefaultUserType, UnknownType, } from '../../types/types'; const styles = StyleSheet.create({ bottomBorder: { borderBottomWidth: 1, }, container: { borderRadius: 16, marginTop: 8, maxWidth: 275, }, row: { alignItems: 'center', flexDirection: 'row', justifyContent: 'flex-start', minWidth: vw(65), paddingHorizontal: 20, paddingVertical: 10, }, titleStyle: { paddingLeft: 20, }, }); type MessageActionProps = MessageActionType & { index: number; length: number; }; const MessageAction: React.FC = (props) => { const { action, icon, index, length, title, titleStyle } = props; const { theme: { colors: { black, border }, }, } = useTheme(); const opacity = useSharedValue(1); const onTap = useAnimatedGestureHandler( { onEnd: () => { runOnJS(action)(); }, onFinish: () => { opacity.value = 1; }, onStart: () => { opacity.value = 0.2; }, }, [action], ); const animatedStyle = useAnimatedStyle(() => ({ opacity: opacity.value, })); return ( {icon} {title} ); }; const messageActionIsEqual = (prevProps: MessageActionProps, nextProps: MessageActionProps) => prevProps.length === nextProps.length; const MemoizedMessageAction = React.memo( MessageAction, messageActionIsEqual, ) as typeof MessageAction; export type MessageActionsPropsWithContext< At extends UnknownType = DefaultAttachmentType, Ch extends UnknownType = DefaultChannelType, Co extends string = DefaultCommandType, Ev extends UnknownType = DefaultEventType, Me extends UnknownType = DefaultMessageType, Re extends UnknownType = DefaultReactionType, Us extends UnknownType = DefaultUserType, > = Pick, 'alignment' | 'messageActions'> & { showScreen: Animated.SharedValue; }; const MessageActionsWithContext = < At extends UnknownType = DefaultAttachmentType, Ch extends UnknownType = DefaultChannelType, Co extends string = DefaultCommandType, Ev extends UnknownType = DefaultEventType, Me extends UnknownType = DefaultMessageType, Re extends UnknownType = DefaultReactionType, Us extends UnknownType = DefaultUserType, >( props: MessageActionsPropsWithContext, ) => { const { alignment, messageActions, showScreen } = props; const { theme: { colors: { white_snow }, }, } = useTheme(); const height = useSharedValue(0); const width = useSharedValue(0); const showScreenStyle = useAnimatedStyle( () => ({ transform: [ { translateY: interpolate(showScreen.value, [0, 1], [-height.value / 2, 0]), }, { translateX: interpolate( showScreen.value, [0, 1], [alignment === 'left' ? -width.value / 2 : width.value / 2, 0], ), }, { scale: showScreen.value, }, ], }), [alignment], ); return ( { width.value = layout.width; height.value = layout.height; }} style={[styles.container, { backgroundColor: white_snow }, showScreenStyle]} > {messageActions?.map((messageAction, index) => ( ))} ); }; const areEqual = < At extends UnknownType = DefaultAttachmentType, Ch extends UnknownType = DefaultChannelType, Co extends string = DefaultCommandType, Ev extends UnknownType = DefaultEventType, Me extends UnknownType = DefaultMessageType, Re extends UnknownType = DefaultReactionType, Us extends UnknownType = DefaultUserType, >( prevProps: MessageActionsPropsWithContext, nextProps: MessageActionsPropsWithContext, ) => { const { alignment: prevAlignment, messageActions: prevMessageActions } = prevProps; const { alignment: nextAlignment, messageActions: nextMessageActions } = nextProps; const messageActionsEqual = prevMessageActions?.length === nextMessageActions?.length; if (!messageActionsEqual) return false; const alignmentEqual = prevAlignment === nextAlignment; if (!alignmentEqual) return false; return true; }; const MemoizedMessageActions = React.memo( MessageActionsWithContext, areEqual, ) as typeof MessageActionsWithContext; export type MessageActionsProps< At extends UnknownType = DefaultAttachmentType, Ch extends UnknownType = DefaultChannelType, Co extends string = DefaultCommandType, Ev extends UnknownType = DefaultEventType, Me extends UnknownType = DefaultMessageType, Re extends UnknownType = DefaultReactionType, Us extends UnknownType = DefaultUserType, > = Partial, 'showScreen'>> & Pick, 'showScreen'>; /** * MessageActions - A high level component which implements all the logic required for MessageActions */ export const MessageActions = < At extends UnknownType = DefaultAttachmentType, Ch extends UnknownType = DefaultChannelType, Co extends string = DefaultCommandType, Ev extends UnknownType = DefaultEventType, Me extends UnknownType = DefaultMessageType, Re extends UnknownType = DefaultReactionType, Us extends UnknownType = DefaultUserType, >( props: MessageActionsProps, ) => { const { data } = useMessageOverlayContext(); const { alignment, messageActions } = data || {}; return ; };