refactor: give the user card context a stable, stateless contract

Merged
GG
19d ago
+134-32

Proposed changes (including videos or screenshots)

UserCardContext exposed the overlay state, the triggerRef and react-aria's stateful trigger props. A single UserCardProvider serves every trigger in a room, which had two side effects:

  • Re-renders: the context value changed whenever a card opened or closed, so every message header, avatar and mention subscribed to it re-rendered.
  • A11y: aria-expanded / aria-controls were spread on every trigger, so while any one card was open, all the triggers in the room were announced as expanded.

The contract is now:

type UserCardContextValue = {
	openUserCard: (e: UIEvent, username: string) => void;
	openUserInfo: (username: string) => void; // new: open the full profile directly
	closeUserCard: () => void;
	triggerProps: AriaAttributes; // static: { 'aria-haspopup': 'dialog' }
};

All entries are identity-stable, so the value never changes. Nothing outside the provider read state or triggerRef. openUserInfo has no consumer yet; the card behavior change (click on a name opens the full profile) builds on it next.

The card still opens on click, as today.

Extracted from #41650 (user information redesign), where @ivans-netto designed this contract. Stacked on #42507; #41650 is stacked on top.

Issue(s)

CORE-1962

Steps to test or reproduce

  1. Click a user's name in a message: the card opens as before; "See full profile" and the actions work.
  2. With a screen reader, open a card and move to another message's author: it's no longer announced as expanded.

Further comments

UserCardProvider.spec.tsx checks the context value stays the same object across opening and closing a card (it changed 3 times before) and that triggers carry no aria-expanded.

Summary by CodeRabbit

  • Bug Fixes
    • Opening or closing a user card no longer triggers re-renders across messages, helping keep room interactions more stable.
    • Room announcements of user-card triggers no longer repeat while a card is open.
    • The trigger that opens a user card now reports its expanded state to assistive technologies; other triggers remain unexpanded.
    • Clicking the text inside a user-card trigger opens the card as expected.