fix(web): stop the profile card re-anchoring to its own avatar (#39)
Avatar opened the profile popout whenever it received a user prop. Since user is how every avatar gets its gradient, colour and status dot, all 22 call sites became profile triggers by accident — including the picture inside the profile card itself, which re-anchored the card to that picture on every click and walked it across the screen (120px right, 36px down, until it pinned at the viewport clamp). Avatar is now presentational. A new ProfileAvatar carries the open-the-profile behaviour at the five call sites that actually want it. The card's own picture escalates to the full profile modal instead of reopening the card. The card also places itself off its measured size via the shared computeFloatingPosition engine, replacing six call sites that each hand-computed coordinates against a guessed 460px card height. Closes #37
This commit is contained in:
@@ -285,45 +285,17 @@ describe('DmMemberRow — profile popout anchoring', () => {
|
||||
await user.click(profileBtn);
|
||||
|
||||
expect(openUserProfileMock).toHaveBeenCalledTimes(1);
|
||||
// The row hands over its rect and the side it wants; the card works out its
|
||||
// own coordinates once it knows how tall it is (see UserProfilePopout).
|
||||
expect(openUserProfileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ id: member.id }),
|
||||
// Math.min(200, 800 - 450) = 200; left = 1500 - 316 = 1184.
|
||||
{ top: 200, left: 1184 },
|
||||
rect,
|
||||
'left',
|
||||
);
|
||||
// The row no longer routes 'profile' through onMenuAction.
|
||||
expect(onMenuAction).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('clamps top to (innerHeight - 450) when the row sits near the bottom of the viewport', async () => {
|
||||
const user = userEvent.setup();
|
||||
const { container } = renderRow();
|
||||
const row = container.querySelector('[data-dm-member-row]') as HTMLElement;
|
||||
|
||||
const rect: DOMRect = {
|
||||
top: 700,
|
||||
left: 1500,
|
||||
right: 1740,
|
||||
bottom: 740,
|
||||
width: 240,
|
||||
height: 40,
|
||||
x: 1500,
|
||||
y: 700,
|
||||
toJSON: () => ({}),
|
||||
} as DOMRect;
|
||||
row.getBoundingClientRect = () => rect;
|
||||
|
||||
Object.defineProperty(window, 'innerHeight', { value: 800, configurable: true });
|
||||
|
||||
openMenuByContextMenu(row);
|
||||
await user.click(await screen.findByText('View Profile'));
|
||||
|
||||
// Math.min(700, 800 - 450 = 350) → top clamped to 350.
|
||||
expect(openUserProfileMock).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ top: 350, left: 1184 },
|
||||
);
|
||||
});
|
||||
|
||||
it('falls back to onMenuAction("profile", ...) when the row has no bounding rect', async () => {
|
||||
const user = userEvent.setup();
|
||||
const { container, onMenuAction, member } = renderRow();
|
||||
|
||||
Reference in New Issue
Block a user