fix: fix save as menu item + bump react-contexify to 6.0.0

This commit is contained in:
Audric Ackermann 2023-09-06 11:51:37 +10:00
parent eb4631ff99
commit 9199c7b529
10 changed files with 102 additions and 750 deletions

View File

@ -109,7 +109,7 @@
"protobufjs": "^7.2.4",
"rc-slider": "^10.2.1",
"react": "^17.0.2",
"react-contexify": "5.0.0",
"react-contexify": "^6.0.0",
"react-dom": "^17.0.2",
"react-draggable": "^4.4.4",
"react-h5-audio-player": "^3.2.0",

View File

@ -1,6 +1,6 @@
// Modules
@import 'react-h5-audio-player/lib/styles.css';
@import 'react-contexify/dist/ReactContexify.min.css';
@import 'react-contexify/dist/ReactContexify.css'; // the .css is actually referencing the .min.css in the 6.0.0
@import 'react-toastify/dist/ReactToastify.css';
@import 'sanitize.css/sanitize.css';

View File

@ -3,36 +3,35 @@ import styled from 'styled-components';
export const SessionContextMenuContainer = styled.div.attrs({
// custom props
})`
.react-contexify {
.contexify {
// be sure it is more than the one set for the More Information screen of messages
z-index: 30;
min-width: 200px;
box-shadow: 0px 0px 10px var(--context-menu-shadow-color) !important;
background-color: var(--context-menu-background-color);
&.react-contexify__theme--dark {
&.contexify_theme-dark {
background-color: var(--context-menu-background-color);
}
.react-contexify__item {
.contexify_item {
background: var(--context-menu-background-color);
}
.react-contexify__item:not(.react-contexify__item--disabled):hover
> .react-contexify__item__content {
.contexify_item:not(.react-contexify_item-disabled):hover > .contexify_itemContent {
background: var(--context-menu-background-hover-color);
color: var(--context-menu-text-hover-color);
}
.react-contexify__item__content {
.contexify_itemContent {
transition: var(--default-duration);
color: var(--context-menu-text-color);
}
&.react-contexify__submenu {
&.contexify_submenu {
top: -28px !important; // height of an item element
}
.react-contexify__submenu-arrow {
.contexify_submenu-arrow {
line-height: 16px; // center the arrow for submenu
}
}

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { animation, contextMenu, Item, Menu } from 'react-contexify';
import { contextMenu, Item, Menu } from 'react-contexify';
import { useDispatch, useSelector } from 'react-redux';
import styled from 'styled-components';
@ -20,7 +20,7 @@ const VideoInputMenu = ({
}) => {
return (
<SessionContextMenuContainer>
<Menu id={triggerId} animation={animation.fade}>
<Menu id={triggerId} animation="fade">
{camerasList.map(m => {
return (
<Item
@ -93,7 +93,7 @@ const AudioInputMenu = ({
}) => {
return (
<SessionContextMenuContainer>
<Menu id={triggerId} animation={animation.fade}>
<Menu id={triggerId} animation="fade">
{audioInputsList.map(m => {
return (
<Item
@ -162,7 +162,7 @@ const AudioOutputMenu = ({
}) => {
return (
<SessionContextMenuContainer>
<Menu id={triggerId} animation={animation.fade}>
<Menu id={triggerId} animation="fade">
{audioOutputsList.map(m => {
return (
<Item

View File

@ -1,11 +1,11 @@
/* eslint-disable @typescript-eslint/no-misused-promises */
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { animation, Item, Menu, useContextMenu } from 'react-contexify';
import { Item, ItemParams, Menu, useContextMenu } from 'react-contexify';
import { useDispatch } from 'react-redux';
import { useClickAway, useMouse } from 'react-use';
import styled from 'styled-components';
import { isNumber } from 'lodash';
import { Data } from '../../../../data/data';
import { MessageInteraction } from '../../../../interactions';
@ -103,49 +103,6 @@ const DeleteForEveryone = ({ messageId }: { messageId: string }) => {
type MessageId = { messageId: string };
const SaveAttachment = ({ messageId }: MessageId) => {
const convoId = useSelectedConversationKey();
const attachments = useMessageAttachments(messageId);
const timestamp = useMessageTimestamp(messageId);
const serverTimestamp = useMessageServerTimestamp(messageId);
const sender = useMessageSender(messageId);
const saveAttachment = useCallback(
(e: any) => {
// this is quite dirty but considering that we want the context menu of the message to show on click on the attachment
// and the context menu save attachment item to save the right attachment I did not find a better way for now.
let targetAttachmentIndex = e.triggerEvent.path[1].getAttribute('data-attachmentindex');
e.event.stopPropagation();
if (!attachments?.length || !convoId || !sender) {
return;
}
if (!targetAttachmentIndex) {
targetAttachmentIndex = 0;
}
if (targetAttachmentIndex > attachments.length) {
return;
}
const messageTimestamp = timestamp || serverTimestamp || 0;
void saveAttachmentToDisk({
attachment: attachments[targetAttachmentIndex],
messageTimestamp,
messageSender: sender,
conversationId: convoId,
});
},
[convoId, sender, attachments, serverTimestamp, timestamp]
);
if (!convoId) {
return null;
}
return attachments?.length ? (
<Item onClick={saveAttachment}>{window.i18n('downloadAttachment')}</Item>
) : null;
};
const AdminActionItems = ({ messageId }: MessageId) => {
const convoId = useSelectedConversationKey();
const isPublic = useSelectedIsPublic();
@ -218,6 +175,11 @@ export const MessageContextMenu = (props: Props) => {
const status = useMessageStatus(messageId);
const isDeletable = useMessageIsDeletable(messageId);
const text = useMessageBody(messageId);
const attachments = useMessageAttachments(messageId);
const timestamp = useMessageTimestamp(messageId);
const serverTimestamp = useMessageServerTimestamp(messageId);
const sender = useMessageSender(messageId);
const isOutgoing = direction === 'outgoing';
const isSent = status === 'sent' || status === 'read'; // a read message should be replyable
@ -233,21 +195,24 @@ export const MessageContextMenu = (props: Props) => {
const [mouseX, setMouseX] = useState(0);
const [mouseY, setMouseY] = useState(0);
const onContextMenuShown = () => {
if (showEmojiPanel) {
setShowEmojiPanel(false);
}
window.contextMenuShown = true;
};
const onContextMenuHidden = useCallback(() => {
// This function will called before the click event
// on the message would trigger (and I was unable to
// prevent propagation in this case), so use a short timeout
setTimeout(() => {
window.contextMenuShown = false;
}, 100);
}, []);
const onVisibilityChange = useCallback(
(isVisible: boolean) => {
if (isVisible) {
if (showEmojiPanel) {
setShowEmojiPanel(false);
}
window.contextMenuShown = true;
return;
}
// This function will called before the click event
// on the message would trigger (and I was unable to
// prevent propagation in this case), so use a short timeout
setTimeout(() => {
window.contextMenuShown = false;
}, 100);
},
[showEmojiPanel]
);
const onShowDetail = async () => {
const found = await Data.getMessageById(messageId);
@ -313,6 +278,29 @@ export const MessageContextMenu = (props: Props) => {
}
};
const saveAttachment = (e: ItemParams) => {
// this is quite dirty but considering that we want the context menu of the message to show on click on the attachment
// and the context menu save attachment item to save the right attachment I did not find a better way for now.
const targetAttachmentIndex = isNumber(e?.props?.dataAttachmentIndex)
? e.props.dataAttachmentIndex
: 0;
e.event.stopPropagation();
if (!attachments?.length || !convoId || !sender) {
return;
}
if (targetAttachmentIndex > attachments.length) {
return;
}
const messageTimestamp = timestamp || serverTimestamp || 0;
void saveAttachmentToDisk({
attachment: attachments[targetAttachmentIndex],
messageTimestamp,
messageSender: sender,
conversationId: convoId,
});
};
useClickAway(emojiPanelRef, () => {
onEmojiLoseFocus();
});
@ -360,18 +348,14 @@ export const MessageContextMenu = (props: Props) => {
</StyledEmojiPanelContainer>
)}
<SessionContextMenuContainer>
<Menu
id={contextMenuId}
onShown={onContextMenuShown}
onHidden={onContextMenuHidden}
animation={animation.fade}
>
<Menu id={contextMenuId} onVisibilityChange={onVisibilityChange} animation="fade">
{enableReactions && (
// eslint-disable-next-line @typescript-eslint/no-misused-promises
<MessageReactBar action={onEmojiClick} additionalAction={onShowEmoji} />
)}
<SaveAttachment messageId={messageId} />
{attachments?.length ? (
<Item onClick={saveAttachment}>{window.i18n('downloadAttachment')}</Item>
) : null}
<Item onClick={copyText}>{window.i18n('copyMessage')}</Item>
{(isSent || !isOutgoing) && (
<Item onClick={onReply}>{window.i18n('replyToMessage')}</Item>

View File

@ -7,6 +7,7 @@ import styled, { keyframes } from 'styled-components';
import useInterval from 'react-use/lib/useInterval';
import useMount from 'react-use/lib/useMount';
import { isNil, isString, toNumber } from 'lodash';
import { Data } from '../../../../data/data';
import { MessageRenderingProps } from '../../../../models/messageType';
import { getConversationController } from '../../../../session/conversations';
@ -180,12 +181,22 @@ export const GenericReadableMessage = (props: Props) => {
const handleContextMenu = useCallback(
(e: React.MouseEvent<HTMLElement>) => {
const enableContextMenu = !multiSelectMode && !msgProps?.isKickedFromGroup;
const attachmentIndexStr = (e?.target as any)?.parentElement?.getAttribute?.(
'data-attachmentindex'
);
const attachmentIndex =
isString(attachmentIndexStr) && !isNil(toNumber(attachmentIndexStr))
? toNumber(attachmentIndexStr)
: 0;
if (enableContextMenu) {
contextMenu.hideAll();
contextMenu.show({
id: ctxMenuID,
event: e,
props: {
dataAttachmentIndex: attachmentIndex,
},
});
}
setIsRightClicked(enableContextMenu);

View File

@ -1,5 +1,5 @@
import React from 'react';
import { animation, Item, Menu, Submenu } from 'react-contexify';
import { Item, Menu, Submenu } from 'react-contexify';
import { useSelector } from 'react-redux';
import { setDisappearingMessagesByConvoId } from '../../interactions/conversationInteractions';
import { isSearching } from '../../state/selectors/search';
@ -64,7 +64,7 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => {
return (
<ContextConversationProvider value={convoId}>
<SessionContextMenuContainer>
<Menu id={triggerId} animation={animation.fade}>
<Menu id={triggerId} animation="fade">
<DisappearingMessageMenuItem />
<NotificationForConvoMenuItem />
<BlockMenuItem />

View File

@ -1,5 +1,5 @@
import React from 'react';
import { animation, Item, Menu } from 'react-contexify';
import { Item, Menu } from 'react-contexify';
import { useSelector } from 'react-redux';
import { useIsPinned, useIsPrivate, useIsPrivateAndFriend } from '../../hooks/useParamSelector';
@ -44,7 +44,7 @@ const ConversationListItemContextMenu = (props: PropsContextConversationItem) =>
return (
<SessionContextMenuContainer>
<Menu id={triggerId} animation={animation.fade}>
<Menu id={triggerId} animation="fade">
{/* Message request related actions */}
<AcceptMsgRequestMenuItem />
<DeclineMsgRequestMenuItem />

View File

@ -1,5 +1,5 @@
import React from 'react';
import { animation, Item, Menu } from 'react-contexify';
import { Item, Menu } from 'react-contexify';
import { useDispatch } from 'react-redux';
import { SessionContextMenuContainer } from '../SessionContextMenuContainer';
@ -28,7 +28,7 @@ export const MessageRequestBannerContextMenu = (props: PropsContextConversationI
return (
<SessionContextMenuContainer>
<Menu id={triggerId} animation={animation.fade}>
<Menu id={triggerId} animation="fade">
<HideBannerMenuItem />
</Menu>
</SessionContextMenuContainer>

682
yarn.lock

File diff suppressed because it is too large Load Diff