import { Box, Header, Icon, IconButton, Icons, Line, Menu, MenuItem, PopOut, RectCords, Text, } from 'folds'; import React, { forwardRef, MouseEventHandler, useEffect, useState } from 'react'; import FocusTrap from 'focus-trap-react'; import classNames from 'classnames'; import { MatrixClient, MatrixEvent, Relations, Room } from 'matrix-js-sdk'; import { EmojiBoard } from '../../../components/emoji-board'; import { stopPropagation } from '../../../utils/keyboard'; import * as css from './styles.css'; import { MessageAllReactionItem, MessageCopyLinkItem, MessageDeleteItem, MessagePinItem, MessageQuickReactions, MessageReadReceiptItem, MessageReportItem, MessageSourceCodeItem, } from './Message'; import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; import { BottomSheetMenu } from './MobileContextMenu'; type BaseOptionProps = { mEvent: MatrixEvent; room: Room; mx: MatrixClient; relations: Relations | undefined; canSendReaction: boolean | undefined; canEdit: boolean | undefined; canDelete: boolean | undefined; canPinEvent: boolean | undefined; hideReadReceipts: boolean | undefined; onReactionToggle: (targetEventId: string, key: string, shortcode?: string | undefined) => void; onReplyClick: MouseEventHandler; onEditId: ((eventId?: string | undefined) => void) | undefined; handleAddReactions: MouseEventHandler; closeMenu: () => void; }; export const MessageDropdownMenu = forwardRef( ( { mEvent, room, mx, relations, canSendReaction, canEdit, canDelete, canPinEvent, hideReadReceipts, onReactionToggle, onReplyClick, onEditId, handleAddReactions, closeMenu, }, ref ) => ( {canSendReaction && ( { onReactionToggle(mEvent.getId() ?? '', key, shortcode); closeMenu(); }} /> )} {canSendReaction && ( } radii="300" onClick={handleAddReactions} > Add Reaction )} {relations && ( )} } radii="300" data-event-id={mEvent.getId()} onClick={(evt) => { onReplyClick(evt); closeMenu(); }} > Reply {canEdit && onEditId && ( } radii="300" data-event-id={mEvent.getId()} onClick={() => { onEditId(mEvent.getId()); closeMenu(); }} > Edit Message )} {!hideReadReceipts && ( )} {canPinEvent && } {((!mEvent.isRedacted() && canDelete) || mEvent.getSender() !== mx.getUserId()) && ( <> {!mEvent.isRedacted() && canDelete && ( )} {mEvent.getSender() !== mx.getUserId() && ( )} )} ) ); type ExtendedOptionsProps = BaseOptionProps & { imagePackRooms: Room[] | undefined; onActiveStateChange: React.Dispatch>; menuAnchor: RectCords | undefined; emojiBoardAnchor: RectCords | undefined; handleOpenEmojiBoard: MouseEventHandler; handleOpenMenu: MouseEventHandler; setMenuAnchor: React.Dispatch>; setEmojiBoardAnchor: React.Dispatch>; isMobileSheetOpen; setMobileSheetOpen; }; export function MessageOptionsMenu({ mEvent, room, mx, relations, imagePackRooms, canSendReaction, canEdit, canDelete, canPinEvent, hideReadReceipts, onReactionToggle, onReplyClick, onEditId, onActiveStateChange, closeMenu, menuAnchor, emojiBoardAnchor, handleOpenEmojiBoard, handleOpenMenu, handleAddReactions, setMenuAnchor, setEmojiBoardAnchor, isMobileSheetOpen, setMobileSheetOpen, }: ExtendedOptionsProps) { useEffect(() => { onActiveStateChange?.(!!menuAnchor || !!emojiBoardAnchor); }, [emojiBoardAnchor, menuAnchor, onActiveStateChange]); const screenSize = useScreenSizeContext(); const isMobile = screenSize === ScreenSize.Mobile; const [view, setView] = useState('options'); const eventId = mEvent.getId(); if (!eventId) return null; const optionProps: BaseOptionProps = { mEvent, room, mx, relations, canSendReaction, canEdit, canDelete, canPinEvent, hideReadReceipts, onReactionToggle, onReplyClick, onEditId, handleAddReactions, closeMenu, }; if (isMobile) { return ( setMobileSheetOpen(false)} isOpen={isMobileSheetOpen}> {view === 'options' ? ( { closeMenu(); setMobileSheetOpen(false); }} handleAddReactions={() => setView('emoji')} /> ) : (
setView('options')}> Add Reaction
{ onReactionToggle(mEvent.getId(), key); setEmojiBoardAnchor(undefined); closeMenu(); setMobileSheetOpen(false); }} onCustomEmojiSelect={(mxc, shortcode) => { onReactionToggle(mEvent.getId(), mxc, shortcode); setEmojiBoardAnchor(undefined); closeMenu(); setMobileSheetOpen(false); }} requestClose={() => setEmojiBoardAnchor(undefined)} />
)}
); } return (
{canSendReaction && ( { onReactionToggle(eventId, key); setEmojiBoardAnchor(undefined); }} onCustomEmojiSelect={(mxc, shortcode) => { onReactionToggle(eventId, mxc, shortcode); setEmojiBoardAnchor(undefined); }} requestClose={() => setEmojiBoardAnchor(undefined)} /> } > )} {canEdit && onEditId && ( onEditId(eventId)} variant="SurfaceVariant" size="300" radii="300" > )} setMenuAnchor(undefined), clickOutsideDeactivates: true, isKeyForward: (evt) => evt.key === 'ArrowDown', isKeyBackward: (evt) => evt.key === 'ArrowUp', escapeDeactivates: stopPropagation, }} > } >
); }