feat: quick emoji reactions on hover, in-app notification toasts, mention pulse audit

P5-17: MessageQuickReactions moved from 3-dots menu to hover toolbar;
shows 5 recent emoji directly on hover. Clicking a quick-reaction also
closes any open emoji picker (setEmojiBoardAnchor). Line separator
removed from component.

P5-7: LotusToastContainer slides in from bottom-right when window is
focused — replaces OS notification for in-focus events. Correct room
path (DM vs home) derived from mDirectAtom. Invite toast routes to
inbox. 4s auto-dismiss. Full TDS styling via CSS custom properties.

P5-8: Confirmed already implemented upstream (MentionHighlightPulse,
0.6s scale+glow, one-shot, prefers-reduced-motion). Marked complete.

Code-review fixes: toast navigation used nonexistent /room/ route;
emoji picker stayed open after toolbar quick-reaction.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-04 21:32:37 -04:00
parent 24e6882e72
commit 4876c2e4ca
7 changed files with 300 additions and 17 deletions
+9 -10
View File
@@ -152,7 +152,7 @@ type MessageQuickReactionsProps = {
export const MessageQuickReactions = as<'div', MessageQuickReactionsProps>(
({ onReaction, ...props }, ref) => {
const mx = useMatrixClient();
const recentEmojis = useRecentEmoji(mx, 4);
const recentEmojis = useRecentEmoji(mx, 5);
if (recentEmojis.length === 0) return <span />;
return (
@@ -180,7 +180,6 @@ export const MessageQuickReactions = as<'div', MessageQuickReactionsProps>(
</IconButton>
))}
</Box>
<Line size="300" />
</>
);
},
@@ -1035,6 +1034,14 @@ export const Message = React.memo(
</IconButton>
</PopOut>
)}
{canSendReaction && (
<MessageQuickReactions
onReaction={(key, shortcode) => {
onReactionToggle(mEvent.getId()!, key, shortcode);
setEmojiBoardAnchor(undefined);
}}
/>
)}
<IconButton
onClick={onReplyClick}
data-event-id={mEvent.getId()}
@@ -1085,14 +1092,6 @@ export const Message = React.memo(
}}
>
<Menu>
{canSendReaction && (
<MessageQuickReactions
onReaction={(key, shortcode) => {
onReactionToggle(mEvent.getId()!, key, shortcode);
closeMenu();
}}
/>
)}
<Box direction="Column" gap="100" className={css.MessageMenuGroup}>
{canSendReaction && (
<MenuItem