fix: show a message row's quick actions when the row gets the keyboard focus

This commit is contained in:
Linus Rath
2026-10-28 10:11:15 +01:00
parent 135ed4c4fc
commit 917b313d5d
2 changed files with 21 additions and 0 deletions
@@ -808,6 +808,24 @@ describe('ThreadListItem hover actions', () => {
fireEvent.pointerOver(row!, { relatedTarget: screen.getByTestId('list') });
expect(screen.getByTestId('hover-action-delete')).toBeTruthy();
});
// Tabbing to a row's checkbox shows them too (group-focus-within), so they
// have to be there without a pointer.
it.each([
['a single message', () => groupEmailsByThread([makeEmail()])[0]],
['a conversation', () => groupEmailsByThread([
makeEmail({ id: 'a', receivedAt: '2024-01-15T10:00:00Z' }),
makeEmail({ id: 'b', receivedAt: '2024-01-15T11:00:00Z' }),
])[0]],
])('mounts them for %s when a control in the row gets the keyboard focus', (_name, makeThread) => {
const { container } = renderInList(makeThread());
expect(screen.queryByTestId('hover-action-delete')).toBeNull();
const row = screen.queryByTestId('email-list-item') ?? container.querySelector('[data-unread]');
const control = row!.querySelector<HTMLElement>('button, [tabindex]:not([tabindex="-1"])');
expect(control).not.toBeNull();
act(() => { control!.focus(); });
expect(screen.getByTestId('hover-action-delete')).toBeTruthy();
});
});
describe('ThreadListItem open message', () => {
+3
View File
@@ -80,6 +80,7 @@ export function listMailboxRole(state: {
?? (state.isUnifiedView ? (state.unifiedRole ?? undefined) : undefined);
}
/** Hover actions mount on the first pointerover or keyboard focus in the row. */
function useArmOnPointerOver(): [boolean, () => void] {
const [armed, setArmed] = React.useState(false);
const arm = React.useCallback(() => setArmed(true), []);
@@ -545,6 +546,7 @@ const SingleEmailItem = React.forwardRef<HTMLDivElement, SingleEmailItemProps>(
{...touchHandlers}
data-testid="email-list-item"
onPointerOver={armHoverActions}
onFocus={armHoverActions}
onPointerDown={(e) => { if (onPrefetch && isMousePressOnRow(e)) onPrefetch(); }}
data-email-id={email.id}
data-subject={email.subject || ''}
@@ -1198,6 +1200,7 @@ export const ThreadListItem = React.forwardRef<HTMLDivElement, ThreadListItemPro
{...dragHandlers}
{...threadTouchHandlers}
onPointerOver={armHoverActions}
onFocus={armHoverActions}
onPointerDown={(e) => { if (onPrefetch && isMousePressOnRow(e)) onPrefetch(latestEmail); }}
aria-current={isSelected ? 'true' : undefined}
data-unread={hasUnread ? 'true' : 'false'}