Skip to content

Commit

Permalink
Move "right space" width logic to the MessageList
Browse files Browse the repository at this point in the history
  • Loading branch information
Roma Koval committed Jun 11, 2024
1 parent d0816ce commit 09c9a8e
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 200 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {QualifiedId} from '@wireapp/api-client/lib/user';
import cx from 'classnames';
import ko from 'knockout';

import {DeliveredIndicator} from 'Components/MessagesList/Message/DeliveredIndicator/DeliveredIndicator';
import {ReadIndicator} from 'Components/MessagesList/Message/ReadIndicator';
import {Conversation} from 'src/script/entity/Conversation';
import {CompositeMessage} from 'src/script/entity/message/CompositeMessage';
Expand Down Expand Up @@ -59,14 +58,14 @@ export interface ContentMessageProps extends Omit<MessageActions, 'onClickResetS
hideHeader: boolean;
hasMarker?: boolean;
isFocused: boolean;
isLastDeliveredMessage: boolean;
message: ContentMessage;
onClickButton: (message: CompositeMessage, buttonId: string) => void;
onRetry: (message: ContentMessage) => void;
quotedMessage?: ContentMessage;
selfId: QualifiedId;
isMsgElementsFocusable: boolean;
onClickReaction: (emoji: string) => void;
rightMarginWidth: number;
}

export const ContentMessageComponent = ({
Expand All @@ -76,7 +75,6 @@ export const ContentMessageComponent = ({
selfId,
hideHeader,
isFocused,
isLastDeliveredMessage,
contextMenu,
onClickAvatar,
onClickImage,
Expand All @@ -88,9 +86,9 @@ export const ContentMessageComponent = ({
isMsgElementsFocusable,
onClickReaction,
onClickDetails,
rightMarginWidth,
}: ContentMessageProps) => {
const messageRef = useRef<HTMLDivElement | null>(null);
const [deliveryIndicatorRef, setDeliveryIndicatorRef] = useState<HTMLDivElement | null>(null);

// check if current message is focused and its elements focusable
const msgFocusState = useMemo(() => isMsgElementsFocusable && isFocused, [isMsgElementsFocusable, isFocused]);
Expand Down Expand Up @@ -166,138 +164,129 @@ export const ContentMessageComponent = ({
useClickOutside(messageRef, hideActionMenuVisibility);

return (
<>
<div
aria-label={messageAriaLabel}
className="content-message-wrapper"
css={{
width: `calc(100% - ${deliveryIndicatorRef?.offsetWidth || 0}px)`,
}}
ref={contentMessageWrapperRef}
onMouseEnter={() => {
// open another floating action menu if none already open
if (!isMenuOpen) {
setActionMenuVisibility(true);
}
}}
onMouseLeave={() => {
// close floating message actions when no active menu is open like context menu/emoji picker
if (!isMenuOpen) {
setActionMenuVisibility(false);
}
}}
>
{(was_edited || !hideHeader) && (
<MessageHeader onClickAvatar={onClickAvatar} message={message} focusTabIndex={messageFocusedTabIndex}>
{was_edited && (
<span className="message-header-label-icon icon-edit" title={message.displayEditedTimestamp()}></span>
)}

<span className="content-message-timestamp">
<MessageTime timestamp={timestamp} data-timestamp-type="normal">
{timeAgo}
</MessageTime>
</span>
</MessageHeader>
)}

<div
className={cx('message-body', {
'message-asset': isAssetMessage,
'message-quoted': !!quote,
'ephemeral-asset-expired': isObfuscated && isAssetMessage,
'icon-file': isObfuscated && isFileMessage,
'icon-movie': isObfuscated && isVideoMessage,
})}
{...(ephemeralCaption && {title: ephemeralCaption})}
>
{ephemeral_status === EphemeralStatusType.ACTIVE && (
<div className="message-ephemeral-timer">
<EphemeralTimer message={message} />
</div>
<div
aria-label={messageAriaLabel}
className="content-message-wrapper"
ref={contentMessageWrapperRef}
onMouseEnter={() => {
// open another floating action menu if none already open
if (!isMenuOpen) {
setActionMenuVisibility(true);
}
}}
onMouseLeave={() => {
// close floating message actions when no active menu is open like context menu/emoji picker
if (!isMenuOpen) {
setActionMenuVisibility(false);
}
}}
>
{(was_edited || !hideHeader) && (
<MessageHeader onClickAvatar={onClickAvatar} message={message} focusTabIndex={messageFocusedTabIndex}>
{was_edited && (
<span className="message-header-label-icon icon-edit" title={message.displayEditedTimestamp()}></span>
)}

{quote && (
<Quote
conversation={conversation}
quote={quote}
selfId={selfId}
findMessage={findMessage}
showDetail={onClickImage}
focusMessage={onClickTimestamp}
handleClickOnMessage={onClickMessage}
showUserDetails={onClickAvatar}
isMessageFocused={msgFocusState}
/>
)}

{assets.map(asset => (
<ContentAsset
key={asset.type}
asset={asset}
message={message}
selfId={selfId}
onClickButton={onClickButton}
onClickImage={onClickImage}
onClickMessage={onClickMessage}
isMessageFocused={msgFocusState}
is1to1Conversation={conversation.is1to1()}
onClickDetails={() => onClickDetails(message)}
/>
))}
<span className="content-message-timestamp">
<MessageTime timestamp={timestamp} data-timestamp-type="normal">
{timeAgo}
</MessageTime>
</span>
</MessageHeader>
)}

{isAssetMessage && (
<ReadIndicator message={message} is1to1Conversation={conversation.is1to1()} onClick={onClickDetails} />
)}

{!isConversationReadonly && isActionMenuVisible && (
<MessageActionsMenu
isMsgWithHeader={!hideHeader}
message={message}
handleActionMenuVisibility={setActionMenuVisibility}
contextMenu={contextMenu}
isMessageFocused={msgFocusState}
handleReactionClick={onClickReaction}
reactionsTotalCount={reactions.length}
isRemovedFromConversation={conversation.removed_from_conversation()}
/>
)}
</div>
<div
className={cx('message-body', {
'message-asset': isAssetMessage,
'message-quoted': !!quote,
'ephemeral-asset-expired': isObfuscated && isAssetMessage,
'icon-file': isObfuscated && isFileMessage,
'icon-movie': isObfuscated && isVideoMessage,
})}
{...(ephemeralCaption && {title: ephemeralCaption})}
>
{ephemeral_status === EphemeralStatusType.ACTIVE && (
<div className="message-ephemeral-timer">
<EphemeralTimer message={message} />
</div>
)}

{[StatusType.FAILED, StatusType.FEDERATION_ERROR].includes(status) && (
<CompleteFailureToSendWarning
{...(status === StatusType.FEDERATION_ERROR && {unreachableDomain: conversation.domain})}
{quote && (
<Quote
conversation={conversation}
quote={quote}
selfId={selfId}
findMessage={findMessage}
showDetail={onClickImage}
focusMessage={onClickTimestamp}
handleClickOnMessage={onClickMessage}
showUserDetails={onClickAvatar}
isMessageFocused={msgFocusState}
onRetry={() => onRetry(message)}
/>
)}

{failedToSend && (
<PartialFailureToSendWarning
{assets.map(asset => (
<ContentAsset
key={asset.type}
asset={asset}
message={message}
selfId={selfId}
onClickButton={onClickButton}
onClickImage={onClickImage}
onClickMessage={onClickMessage}
isMessageFocused={msgFocusState}
failedToSend={failedToSend}
knownUsers={conversation.allUserEntities()}
is1to1Conversation={conversation.is1to1()}
onClickDetails={() => onClickDetails(message)}
/>
))}

{isAssetMessage && (
<ReadIndicator message={message} is1to1Conversation={conversation.is1to1()} onClick={onClickDetails} />
)}

{!!reactions.length && (
<MessageReactionsList
reactions={reactions}
selfUserId={selfId}
handleReactionClick={onClickReaction}
{!isConversationReadonly && isActionMenuVisible && (
<MessageActionsMenu
isMsgWithHeader={!hideHeader}
message={message}
handleActionMenuVisibility={setActionMenuVisibility}
contextMenu={contextMenu}
isMessageFocused={msgFocusState}
onTooltipReactionCountClick={() => onClickReactionDetails(message)}
onLastReactionKeyEvent={() => setActionMenuVisibility(false)}
handleReactionClick={onClickReaction}
reactionsTotalCount={reactions.length}
isRemovedFromConversation={conversation.removed_from_conversation()}
users={conversation.allUserEntities()}
rightMarginWidth={rightMarginWidth}
/>
)}
</div>
<DeliveredIndicator
ref={setDeliveryIndicatorRef}
isLastDeliveredMessage={isLastDeliveredMessage}
height={messageRef.current?.offsetHeight}
/>
</>

{[StatusType.FAILED, StatusType.FEDERATION_ERROR].includes(status) && (
<CompleteFailureToSendWarning
{...(status === StatusType.FEDERATION_ERROR && {unreachableDomain: conversation.domain})}
isMessageFocused={msgFocusState}
onRetry={() => onRetry(message)}
/>
)}

{failedToSend && (
<PartialFailureToSendWarning
isMessageFocused={msgFocusState}
failedToSend={failedToSend}
knownUsers={conversation.allUserEntities()}
/>
)}

{!!reactions.length && (
<MessageReactionsList
reactions={reactions}
selfUserId={selfId}
handleReactionClick={onClickReaction}
isMessageFocused={msgFocusState}
onTooltipReactionCountClick={() => onClickReactionDetails(message)}
onLastReactionKeyEvent={() => setActionMenuVisibility(false)}
isRemovedFromConversation={conversation.removed_from_conversation()}
users={conversation.allUserEntities()}
/>
)}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@ export const messageActionsGroup: CSSObject = {
padding: '2px',
};

export const messageBodyActions: CSSObject = {
export const messageBodyActions = (rightMarginWidth: number): CSSObject => ({
display: 'inline-flex',
alignItems: 'center',
minHeight: '32px',
minWidth: '40px',
position: 'absolute',
right: '16px',
right: `${16 - rightMarginWidth}px`,
top: '-34px',
userSelect: 'none',
'@media (max-width: @screen-md-min)': {
height: '45px',
flexDirection: 'column',
},
};
});

export const messageActionsMenuButton = (isReactable = true): CSSObject => {
const defaultStyle: CSSObject = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export interface MessageActionsMenuProps {
handleReactionClick: (emoji: string) => void;
reactionsTotalCount: number;
isRemovedFromConversation: boolean;
rightMarginWidth: number;
}

const MessageActionsMenu: FC<MessageActionsMenuProps> = ({
Expand All @@ -74,6 +75,7 @@ const MessageActionsMenu: FC<MessageActionsMenuProps> = ({
handleReactionClick,
reactionsTotalCount,
isRemovedFromConversation,
rightMarginWidth,
}) => {
const {entries: menuEntries} = useKoSubscribableChildren(contextMenu, ['entries']);
const messageFocusedTabIndex = useMessageFocusedTabIndex(isMessageFocused);
Expand Down Expand Up @@ -163,7 +165,7 @@ const MessageActionsMenu: FC<MessageActionsMenuProps> = ({
}
});
return (
<div css={{...messageBodyActions, ...messageReactionTop}} ref={wrapperRef}>
<div css={{...messageBodyActions(rightMarginWidth), ...messageReactionTop}} ref={wrapperRef}>
<div
css={messageActionsGroup}
role="group"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,20 @@

import {CSSObject} from '@emotion/react';

export const DeliveryIndicatorContainerStyles = (height?: number): CSSObject => ({
display: 'flex',
export const DeliveryIndicatorStyles = (visible: boolean): CSSObject => ({
boxSizing: 'border-box',
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
top: 0,
right: 0,
transform: 'translateX(100%)',
overflow: 'unset',
padding: '0 24px 0 16px',
height: height ? `${height}px` : 'min-content',
});

export const DeliveredIndicatorStyles = (isLastDeliveredMessage: boolean): CSSObject => ({
padding: '7px 24px 7px 16px',
color: 'var(--content-message-timestamp)',
fontSize: 'var(--font-size-small)',
fontWeight: 'var(--font-weight-regular)',
lineHeight: 'var(--line-height-sm)',
wordWrap: 'normal',
whiteSpace: 'normal',
width: 'min-content',
visibility: isLastDeliveredMessage ? 'unset' : 'hidden',
visibility: visible ? 'unset' : 'hidden',
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ describe('DeliveredIndicator', () => {
expect(DeliveredIndicator.displayName).toBe('DeliveredIndicator');
});

it('shows "delivered" when it is the last delivered message, no height provided', () => {
it('shows "delivered" when it is the last delivered message', () => {
const {getByTestId} = render(<DeliveredIndicator isLastDeliveredMessage />);

expect(getByTestId('status-message-read-receipt-delivered')).toBeTruthy();
});

it('hides "delivered" when it is not the last delivered message, height provided', () => {
it('hides "delivered" when it is not the last delivered message', () => {
const {queryByTestId} = render(<DeliveredIndicator isLastDeliveredMessage={false} />);

expect(queryByTestId('status-message-read-receipt-delivered')).toBeNull();
Expand Down
Loading

0 comments on commit 09c9a8e

Please sign in to comment.