Message: Fix quick reaction position (#2969)

This commit is contained in:
Alexander Zinchuk 2023-04-15 13:51:28 +02:00
parent 180599f5d4
commit a27ec8243b
5 changed files with 46 additions and 27 deletions

View File

@ -80,6 +80,7 @@
opacity: 0; opacity: 0;
transition: transform 0.2s ease-out, opacity 0.2s ease-out; transition: transform 0.2s ease-out, opacity 0.2s ease-out;
transition-delay: 0.2s; transition-delay: 0.2s;
z-index: 1;
&.visible { &.visible {
opacity: 1 !important; opacity: 1 !important;

View File

@ -263,6 +263,9 @@ type ReactionsPosition =
'inside' 'inside'
| 'outside' | 'outside'
| 'none'; | 'none';
type QuickReactionPosition =
'in-content'
| 'in-meta';
const NBSP = '\u00A0'; const NBSP = '\u00A0';
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
@ -371,7 +374,7 @@ const Message: FC<OwnProps & StateProps> = ({
// eslint-disable-next-line no-null/no-null // eslint-disable-next-line no-null/no-null
const bottomMarkerRef = useRef<HTMLDivElement>(null); const bottomMarkerRef = useRef<HTMLDivElement>(null);
// eslint-disable-next-line no-null/no-null // eslint-disable-next-line no-null/no-null
const contentRef = useRef<HTMLDivElement>(null); const quickReactionRef = useRef<HTMLDivElement>(null);
const messageHeightRef = useRef(0); const messageHeightRef = useRef(0);
@ -492,7 +495,7 @@ const Message: FC<OwnProps & StateProps> = ({
handleBeforeContextMenu, handleBeforeContextMenu,
chatId, chatId,
isContextMenuShown, isContextMenuShown,
contentRef, quickReactionRef,
isOwn, isOwn,
isInDocumentGroupNotLast, isInDocumentGroupNotLast,
); );
@ -641,6 +644,8 @@ const Message: FC<OwnProps & StateProps> = ({
reactionsPosition = 'none'; reactionsPosition = 'none';
} }
const quickReactionPosition: QuickReactionPosition = isCustomShape ? 'in-meta' : 'in-content';
useEnsureMessage( useEnsureMessage(
isRepliesChat && message.replyToChatId ? message.replyToChatId : chatId, isRepliesChat && message.replyToChatId ? message.replyToChatId : chatId,
hasReply ? message.replyToMessageId : undefined, hasReply ? message.replyToMessageId : undefined,
@ -788,6 +793,25 @@ const Message: FC<OwnProps & StateProps> = ({
); );
} }
function renderQuickReactionButton() {
if (!defaultReaction) return undefined;
return (
<div
className={buildClassName('quick-reaction', isQuickReactionVisible && !activeReactions && 'visible')}
onClick={handleSendQuickReaction}
ref={quickReactionRef}
>
<ReactionStaticEmoji
reaction={defaultReaction}
size={QUICK_REACTION_SIZE}
availableReactions={availableReactions}
observeIntersection={observeIntersectionForPlaying}
/>
</div>
);
}
function renderReactionsAndMeta() { function renderReactionsAndMeta() {
const meta = ( const meta = (
<MessageMeta <MessageMeta
@ -798,6 +822,9 @@ const Message: FC<OwnProps & StateProps> = ({
outgoingStatus={outgoingStatus} outgoingStatus={outgoingStatus}
signature={signature} signature={signature}
withReactionOffset={reactionsPosition === 'inside'} withReactionOffset={reactionsPosition === 'inside'}
renderQuickReactionButton={
withQuickReactionButton && quickReactionPosition === 'in-meta' ? renderQuickReactionButton : undefined
}
availableReactions={availableReactions} availableReactions={availableReactions}
isTranslated={Boolean(requestedTranslationLanguage ? currentTranslatedText : undefined)} isTranslated={Boolean(requestedTranslationLanguage ? currentTranslatedText : undefined)}
onClick={handleMetaClick} onClick={handleMetaClick}
@ -1216,7 +1243,6 @@ const Message: FC<OwnProps & StateProps> = ({
className={buildClassName('message-content-wrapper', contentClassName.includes('text') && 'can-select-text')} className={buildClassName('message-content-wrapper', contentClassName.includes('text') && 'can-select-text')}
> >
<div <div
ref={contentRef}
className={contentClassName} className={contentClassName}
style={style} style={style}
dir="auto" dir="auto"
@ -1256,19 +1282,7 @@ const Message: FC<OwnProps & StateProps> = ({
{withAppendix && ( {withAppendix && (
<div className="svg-appendix" dangerouslySetInnerHTML={isOwn ? APPENDIX_OWN : APPENDIX_NOT_OWN} /> <div className="svg-appendix" dangerouslySetInnerHTML={isOwn ? APPENDIX_OWN : APPENDIX_NOT_OWN} />
)} )}
{withQuickReactionButton && ( {withQuickReactionButton && quickReactionPosition === 'in-content' && renderQuickReactionButton()}
<div
className={buildClassName('quick-reaction', isQuickReactionVisible && !activeReactions && 'visible')}
onClick={handleSendQuickReaction}
>
<ReactionStaticEmoji
reaction={defaultReaction}
size={QUICK_REACTION_SIZE}
availableReactions={availableReactions}
observeIntersection={observeIntersectionForPlaying}
/>
</div>
)}
</div> </div>
{message.inlineButtons && ( {message.inlineButtons && (
<InlineButtons message={message} onClick={clickBotInlineButton} /> <InlineButtons message={message} onClick={clickBotInlineButton} />

View File

@ -168,8 +168,6 @@
.Message:not(.own) { .Message:not(.own) {
.custom-shape .with-subheader + .MessageMeta { .custom-shape .with-subheader + .MessageMeta {
right: auto;
left: 13.25rem;
bottom: 0.25rem; bottom: 0.25rem;
} }
} }

View File

@ -1,4 +1,4 @@
import type { FC } from '../../../lib/teact/teact'; import type { FC, TeactNode } from '../../../lib/teact/teact';
import React, { memo, useMemo } from '../../../lib/teact/teact'; import React, { memo, useMemo } from '../../../lib/teact/teact';
import { getActions } from '../../../global'; import { getActions } from '../../../global';
@ -31,6 +31,7 @@ type OwnProps = {
isPinned?: boolean; isPinned?: boolean;
onClick: (e: React.MouseEvent<HTMLDivElement>) => void; onClick: (e: React.MouseEvent<HTMLDivElement>) => void;
onTranslationClick: (e: React.MouseEvent<HTMLDivElement>) => void; onTranslationClick: (e: React.MouseEvent<HTMLDivElement>) => void;
renderQuickReactionButton?: () => TeactNode | undefined;
onOpenThread: NoneToVoidFunction; onOpenThread: NoneToVoidFunction;
}; };
@ -40,6 +41,7 @@ const MessageMeta: FC<OwnProps> = ({
signature, signature,
withReactionOffset, withReactionOffset,
repliesThreadInfo, repliesThreadInfo,
renderQuickReactionButton,
noReplies, noReplies,
isTranslated, isTranslated,
isPinned, isPinned,
@ -140,6 +142,7 @@ const MessageMeta: FC<OwnProps> = ({
{outgoingStatus && ( {outgoingStatus && (
<MessageOutgoingStatus status={outgoingStatus} /> <MessageOutgoingStatus status={outgoingStatus} />
)} )}
{renderQuickReactionButton && renderQuickReactionButton()}
</span> </span>
); );
}; };

View File

@ -30,7 +30,7 @@ export default function useOuterHandlers(
handleBeforeContextMenu: (e: React.MouseEvent) => void, handleBeforeContextMenu: (e: React.MouseEvent) => void,
chatId: string, chatId: string,
isContextMenuShown: boolean, isContextMenuShown: boolean,
contentRef: RefObject<HTMLDivElement>, quickReactionRef: RefObject<HTMLDivElement>,
isOwn: boolean, isOwn: boolean,
shouldHandleMouseLeave: boolean, shouldHandleMouseLeave: boolean,
) { ) {
@ -46,16 +46,18 @@ export default function useOuterHandlers(
} }
function handleMouseMove(e: React.MouseEvent) { function handleMouseMove(e: React.MouseEvent) {
const container = contentRef.current; const quickReactionContainer = quickReactionRef.current;
if (!container) return; if (!quickReactionContainer) return;
const { clientX, clientY } = e; const { clientX, clientY } = e;
const { const {
x, width, y, height, x: quickReactionX, width: quickReactionWidth, y: quickReactionY, height: quickReactionHeight,
} = container.getBoundingClientRect(); } = quickReactionContainer.getBoundingClientRect();
const x = quickReactionX + quickReactionWidth / 2;
const y = quickReactionY + quickReactionHeight / 2;
const isVisibleX = Math.abs((isOwn ? (clientX - x) : (x + width - clientX))) < QUICK_REACTION_AREA_WIDTH; const isVisibleX = Math.abs(x - clientX) < QUICK_REACTION_AREA_WIDTH;
const isVisibleY = Math.abs(y + height - clientY) < QUICK_REACTION_AREA_HEIGHT; const isVisibleY = Math.abs(y - clientY) < QUICK_REACTION_AREA_HEIGHT;
if (isVisibleX && isVisibleY) { if (isVisibleX && isVisibleY) {
markQuickReactionVisible(); markQuickReactionVisible();
} else { } else {
@ -63,7 +65,8 @@ export default function useOuterHandlers(
} }
} }
function handleSendQuickReaction() { function handleSendQuickReaction(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
e.stopPropagation();
sendDefaultReaction({ sendDefaultReaction({
chatId, chatId,
messageId, messageId,