Files
cinny/src/app/components/message/Reaction.tsx
T

131 lines
3.7 KiB
TypeScript
Raw Normal View History

2023-10-06 13:44:06 +11:00
import React from 'react';
import { Box, Text, as } from 'folds';
import classNames from 'classnames';
import { MatrixClient, MatrixEvent, Room } from 'matrix-js-sdk';
import * as css from './Reaction.css';
import { getHexcodeForEmoji, getShortcodeFor } from '../../plugins/emoji';
import { getMemberDisplayName } from '../../utils/room';
2024-09-07 21:45:55 +08:00
import { eventWithShortcode, getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
2023-10-06 13:44:06 +11:00
export const Reaction = as<
'button',
{
mx: MatrixClient;
count: number;
reaction: string;
/** Custom-emoji shortcode from the reaction event, used for its label. */
shortcode?: string;
2024-09-07 21:45:55 +08:00
useAuthentication?: boolean;
2023-10-06 13:44:06 +11:00
}
>(({ className, mx, count, reaction, shortcode, useAuthentication, ...props }, ref) => {
// Name a unicode reaction by the emoji itself: screen readers speak it by its
// proper name ("party popper"). Don't use getShortcodeFor here — it returns
// undefined until the lazy emoji data loads, so the same button would flip
// between "🎉 reaction" and "tada reaction" depending on timing (#179).
const name = reaction.startsWith('mxc://')
? shortcode
? `:${shortcode}:`
: 'custom emoji'
: reaction;
const label = `${name} reaction, ${count} ${count === 1 ? 'person' : 'people'}`;
return (
<Box
as="button"
className={classNames(css.Reaction, className)}
alignItems="Center"
shrink="No"
gap="200"
aria-label={label}
{...props}
ref={ref}
>
<Text className={css.ReactionText} as="span" size="T400">
{reaction.startsWith('mxc://') ? (
<img
className={css.ReactionImg}
src={mxcUrlToHttp(mx, reaction, useAuthentication) ?? reaction}
alt={reaction}
/>
) : (
<Text as="span" size="Inherit" truncate>
{reaction}
</Text>
)}
</Text>
<Text as="span" size="T300">
{count}
</Text>
</Box>
);
});
2023-10-06 13:44:06 +11:00
type ReactionTooltipMsgProps = {
room: Room;
reaction: string;
events: MatrixEvent[];
};
export function ReactionTooltipMsg({ room, reaction, events }: ReactionTooltipMsgProps) {
const shortCodeEvt = events.find(eventWithShortcode);
const shortcode =
shortCodeEvt?.getContent().shortcode ??
getShortcodeFor(getHexcodeForEmoji(reaction)) ??
reaction;
const names = events.map(
(ev: MatrixEvent) =>
getMemberDisplayName(room, ev.getSender() ?? 'Unknown') ??
getMxIdLocalPart(ev.getSender() ?? 'Unknown') ??
'Unknown',
2023-10-06 13:44:06 +11:00
);
return (
<>
{names.length === 1 && <b>{names[0]}</b>}
{names.length === 2 && (
<>
<b>{names[0]}</b>
<Text as="span" size="Inherit" priority="300">
{' and '}
</Text>
<b>{names[1]}</b>
</>
)}
{names.length === 3 && (
<>
<b>{names[0]}</b>
<Text as="span" size="Inherit" priority="300">
{', '}
</Text>
<b>{names[1]}</b>
<Text as="span" size="Inherit" priority="300">
{' and '}
</Text>
<b>{names[2]}</b>
</>
)}
{names.length > 3 && (
<>
<b>{names[0]}</b>
<Text as="span" size="Inherit" priority="300">
{', '}
</Text>
<b>{names[1]}</b>
<Text as="span" size="Inherit" priority="300">
{', '}
</Text>
<b>{names[2]}</b>
<Text as="span" size="Inherit" priority="300">
{' and '}
</Text>
<b>{names.length - 3} others</b>
</>
)}
<Text as="span" size="Inherit" priority="300">
{' reacted with '}
</Text>
:<b>{shortcode}</b>:
</>
);
}