fix(desktop): narrow chat action hover area #642

Message actions were still tied to the full message row, so moving the pointer into blank space beside a short chat bubble kept copy and timestamp controls visible. Move the hover group onto the actual message shell and keep full-width behavior only for document-style assistant replies.

Constraint: Message actions still rely on group-hover and focus-within for pointer and keyboard access.
Rejected: Remove focus-within reveal | would regress keyboard users who tab to copy or fork controls.
Confidence: high
Scope-risk: narrow
Directive: Keep normal bubble hover bounds tied to the message shell; document-layout replies intentionally remain full-width.
Tested: cd desktop && bun run test src/components/chat/MessageList.test.tsx --run
Tested: cd desktop && bun run test src/components/chat/UserMessage.test.tsx --run
Tested: bun run check:desktop
Tested: git diff --check
Not-tested: Live Tauri native hover smoke
Related: #642
This commit is contained in:
程序员阿江(Relakkes) 2026-05-31 15:42:58 +08:00
parent 587922ba75
commit 8c5c2a0913
3 changed files with 9 additions and 5 deletions

View File

@ -64,14 +64,14 @@ export const AssistantMessage = memo(function AssistantMessage({ content, isStre
const documentLayout = shouldUseDocumentLayout(content)
return (
<div className="group mb-5 flex justify-start">
<div className="mb-5 flex justify-start">
<div
data-message-shell="assistant"
data-layout={documentLayout ? 'document' : 'bubble'}
className={`flex min-w-0 flex-col items-start gap-2 ${
className={`group flex min-w-0 flex-col items-start gap-2 ${
documentLayout
? 'w-full max-w-full'
: 'w-full max-w-[88%] sm:max-w-[80%] lg:max-w-[72%]'
: 'max-w-[88%] sm:max-w-[80%] lg:max-w-[72%]'
}`}
>
<div className={`rounded-[20px] rounded-tl-[8px] border border-[var(--color-border)]/60 bg-[var(--color-surface)] px-4 py-3 text-sm text-[var(--color-text-primary)] shadow-sm ${

View File

@ -2725,8 +2725,12 @@ describe('MessageList nested tool calls', () => {
expect(userShell).toBeTruthy()
expect(userShell?.className).toContain('items-end')
expect(userShell?.className).toContain('group')
expect(userShell?.className).not.toContain('w-full')
expect(assistantShell).toBeTruthy()
expect(assistantShell?.className).toContain('items-start')
expect(assistantShell?.className).toContain('group')
expect(assistantShell?.className).not.toContain('w-full')
expect(assistantShell?.className).not.toContain('ml-10')
expect(userActions?.getAttribute('data-align')).toBe('end')
expect(assistantActions?.getAttribute('data-align')).toBe('start')

View File

@ -14,10 +14,10 @@ export const UserMessage = memo(function UserMessage({ content, attachments, bra
const hasText = content.trim().length > 0
return (
<div className="group mb-5 flex justify-end">
<div className="mb-5 flex justify-end">
<div
data-message-shell="user"
className="flex min-w-0 w-full max-w-[82%] flex-col items-end gap-2 sm:max-w-[78%] lg:max-w-[72%]"
className="group flex min-w-0 max-w-[82%] flex-col items-end gap-2 sm:max-w-[78%] lg:max-w-[72%]"
>
{attachments && attachments.length > 0 && (
<AttachmentGallery attachments={attachments} variant="message" />