signal-desktop/ts/components/conversation/TypingBubble.tsx

126 lines
3.6 KiB
TypeScript
Raw Normal View History

2023-01-03 19:55:46 +00:00
// Copyright 2018 Signal Messenger, LLC
2020-10-30 20:34:04 +00:00
// SPDX-License-Identifier: AGPL-3.0-only
import type { ReactElement } from 'react';
2018-11-14 19:10:32 +00:00
import React from 'react';
import classNames from 'classnames';
import { TypingAnimation } from './TypingAnimation';
import { Avatar } from '../Avatar';
import type { LocalizerType, ThemeType } from '../../types/Util';
import type { ConversationType } from '../../state/ducks/conversations';
import type { BadgeType } from '../../badges/types';
2018-11-14 19:10:32 +00:00
const MAX_AVATARS_COUNT = 3;
export type PropsType = {
conversationId: string;
conversationType: 'group' | 'direct';
showContactModal: (contactId: string, conversationId?: string) => void;
2019-01-14 21:49:58 +00:00
i18n: LocalizerType;
theme: ThemeType;
typingContacts: Array<
Pick<
ConversationType,
| 'acceptedMessageRequest'
| 'avatarPath'
| 'color'
| 'id'
| 'isMe'
| 'phoneNumber'
| 'profileName'
| 'sharedGroupNames'
| 'title'
> & {
badge: undefined | BadgeType;
}
>;
};
2018-11-14 19:10:32 +00:00
export function TypingBubble({
conversationId,
conversationType,
showContactModal,
i18n,
theme,
typingContacts,
}: PropsType): ReactElement {
const isGroup = conversationType === 'group';
2018-11-14 19:10:32 +00:00
const typingContactsOverflowCount = Math.max(
typingContacts.length - MAX_AVATARS_COUNT,
0
);
return (
<div
className={classNames(
'module-message',
'module-message--incoming',
isGroup ? 'module-message--group' : null
)}
>
{isGroup && (
<div className="module-message__typing-avatar-container">
{typingContactsOverflowCount > 0 && (
<div
className="module-message__typing-avatar module-message__typing-avatar--overflow-count
"
>
<div
aria-label={i18n('icu:TypingBubble__avatar--overflow-count', {
count: typingContactsOverflowCount,
})}
className="module-Avatar"
>
<div className="module-Avatar__contents">
<div aria-hidden="true" className="module-Avatar__label">
+{typingContactsOverflowCount}
</div>
</div>
</div>
</div>
)}
{typingContacts.slice(-1 * MAX_AVATARS_COUNT).map(contact => (
<div key={contact.id} className="module-message__typing-avatar">
<Avatar
acceptedMessageRequest={contact.acceptedMessageRequest}
avatarPath={contact.avatarPath}
badge={contact.badge}
color={contact.color}
conversationType="direct"
i18n={i18n}
isMe={contact.isMe}
onClick={event => {
event.stopPropagation();
event.preventDefault();
showContactModal(contact.id, conversationId);
}}
phoneNumber={contact.phoneNumber}
profileName={contact.profileName}
theme={theme}
title={contact.title}
sharedGroupNames={contact.sharedGroupNames}
size={28}
/>
</div>
))}
</div>
)}
<div className="module-message__container-outer">
<div
className={classNames(
'module-message__container',
'module-message__container--incoming'
)}
>
<div className="module-message__typing-container">
<TypingAnimation color="light" i18n={i18n} />
2018-11-14 19:10:32 +00:00
</div>
</div>
</div>
</div>
);
2018-11-14 19:10:32 +00:00
}