From a1cf4ad077cc9252bdc729446fb6678838dda76a Mon Sep 17 00:00:00 2001 From: Cyrus Gray <144336577+graycyrus@users.noreply.github.com> Date: Wed, 24 Jun 2026 02:15:58 +0530 Subject: [PATCH] fix(chat): tuck the reaction affordance onto the message-bubble corner (#4018) --- app/src/pages/Conversations.tsx | 196 ++++++++++++++++---------------- 1 file changed, 100 insertions(+), 96 deletions(-) diff --git a/app/src/pages/Conversations.tsx b/app/src/pages/Conversations.tsx index 20e30d936..ae0b3ace4 100644 --- a/app/src/pages/Conversations.tsx +++ b/app/src/pages/Conversations.tsx @@ -1858,30 +1858,109 @@ const Conversations = ({ }`}> {msg.sender === 'agent' ? (
- {agentMessageViewMode === 'text' ? ( - - ) : ( - splitAgentMessageIntoBubbles(msg.content).map( - (segment, index, parts) => { - const position: AgentBubblePosition = - parts.length === 1 - ? 'single' - : index === 0 - ? 'first' - : index === parts.length - 1 - ? 'last' - : 'middle'; +
+ {agentMessageViewMode === 'text' ? ( + + ) : ( + splitAgentMessageIntoBubbles(msg.content).map( + (segment, index, parts) => { + const position: AgentBubblePosition = + parts.length === 1 + ? 'single' + : index === 0 + ? 'first' + : index === parts.length - 1 + ? 'last' + : 'middle'; + return ( + + ); + } + ) + )} + {/* Reaction affordance — the closed "+", the open picker, + and the resulting reaction chips all live here, tucked + onto the bubble's bottom-left corner so the control + never jumps to a separate row below the timestamp. */} + {latestVisibleMessage?.id === msg.id && + (() => { + const myReactions = + (msg.extraMetadata?.myReactions as string[] | undefined) ?? []; + const pickerOpen = reactionPickerMsgId === msg.id; return ( - +
+ {myReactions.map(emoji => ( + + ))} + {pickerOpen ? ( +
+ {['👍', '❤️', '😂', '🔥', '👀', '🎯'].map(emoji => ( + + ))} + +
+ ) : ( + + )} +
); - } - ) - )} + })()} +
{(() => { const raw = msg.extraMetadata?.citations; if (!Array.isArray(raw)) return null; @@ -2025,81 +2104,6 @@ const Conversations = ({ )} - {(() => { - if (latestVisibleMessage?.id !== msg.id) return null; - const myReactions = - (msg.extraMetadata?.myReactions as string[] | undefined) ?? []; - const hasReactions = myReactions.length > 0; - // Show reaction row only for the most recent visible message. - if (!hasReactions && msg.sender !== 'agent') return null; - return ( -
- {myReactions.map(emoji => ( - - ))} - {msg.sender === 'agent' && - (reactionPickerMsgId === msg.id ? ( -
- {['👍', '❤️', '😂', '🔥', '👀', '🎯'].map(emoji => ( - - ))} - -
- ) : ( - - ))} -
- ); - })()}