import { Box, Icon, IconButton, Icons, Line, Menu, MenuItem, PopOut, RectCords, Text } from 'folds'; import React, { MouseEventHandler, useEffect } 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 './message/styles.css'; import { MessageAllReactionItem, MessageCopyLinkItem, MessageDeleteItem, MessagePinItem, MessageQuickReactions, MessageReadReceiptItem, MessageReportItem, MessageSourceCodeItem, } from './message/Message'; 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 function MessageDropdownMenu({ mEvent, room, mx, relations, canSendReaction, canEdit, canDelete, canPinEvent, hideReadReceipts, onReactionToggle, onReplyClick, onEditId, handleAddReactions, closeMenu, }: BaseOptionProps) { return ( {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 && } {/* Redact and Report actions */} {((!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>; }; 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, }: ExtendedOptionsProps) { useEffect(() => { onActiveStateChange?.(!!menuAnchor || !!emojiBoardAnchor); }, [emojiBoardAnchor, menuAnchor, onActiveStateChange]); const eventId = mEvent.getId(); if (!eventId) return null; 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, }} > } >
); } export function BottomSheetMenu({ isOpen, onClose, children, }: { isOpen: boolean; onClose: () => void; children: React.ReactNode; }) { return (
); } export function MenuItemButton({ label, onClick, destructive = false, }: { label: string; onClick: () => void; destructive?: boolean; }) { return ( {label} ); }