fix: name the recipient on the composer chip remove button

This commit is contained in:
Linus Rath
2026-10-31 19:58:47 +01:00
parent b9dcbdea52
commit 7c39730616
3 changed files with 45 additions and 1 deletions
@@ -6,6 +6,7 @@ import { radius, spacing, typography, type ThemePalette } from '../../theme/toke
import { useLocaleStore } from '../../stores/locale-store';
import { getEmailInitials } from '../../lib/avatar-utils';
import { SUGGESTION_ROW_HEIGHT } from '../../lib/recipient-picker';
import { recipientRemoveAccessibilityLabel } from '../../lib/recipient-chip-a11y';
import type { RecipientSuggestion } from '../../stores/contacts-store';
/** A recipient chip's data. Group chips carry their resolved members and no email. */
@@ -43,7 +44,7 @@ export function RecipientChip({
// A 12 px icon: the touch area reaches about 40 dp around it.
hitSlop={14}
accessibilityRole="button"
accessibilityLabel={t('email_composer.recipient_remove', 'Remove')}
accessibilityLabel={recipientRemoveAccessibilityLabel(recipient, t)}
>
<X size={12} color={invalid ? c.error : c.textMuted} />
</Pressable>
@@ -0,0 +1,27 @@
// The cross on a composer recipient chip said only "Remove".
import { describe, expect, it, vi } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
vi.mock('expo-localization', () => ({ getLocales: () => [] }));
import { translate } from '../../i18n';
import { recipientRemoveAccessibilityLabel } from '../recipient-chip-a11y';
const t = (key: string, fallback?: string, params?: Record<string, string | number>) =>
translate('en', key, fallback ?? key, params);
describe('recipient chip remove label', () => {
it('names the recipient', () => {
expect(recipientRemoveAccessibilityLabel({ name: 'Anna Berg', email: 'anna@example.org' }, t)).toBe('Remove Anna Berg');
});
it('falls back to the address when the chip has no name', () => {
expect(recipientRemoveAccessibilityLabel({ name: ' ', email: 'anna@example.org' }, t)).toBe('Remove anna@example.org');
});
it('is what the chip cross uses', () => {
const source = fs.readFileSync(path.resolve(__dirname, '../../components/compose/RecipientSuggestionList.tsx'), 'utf8');
expect(source).toMatch(/accessibilityLabel=\{recipientRemoveAccessibilityLabel\(/);
});
});
+16
View File
@@ -0,0 +1,16 @@
// What a screen reader says for the cross on a To/Cc/Bcc chip. It said only
// "Remove", so with several chips nobody could tell which one a cross took
// away. The webmail names the recipient (email-composer.tsx,
// recipient_remove_named), as the event editor here already does.
type Translate = (key: string, fallback?: string, params?: Record<string, string | number>) => string;
/** "Remove Anna Berg", or "Remove anna@example.org" when the chip has no name. */
export function recipientRemoveAccessibilityLabel(
recipient: { name?: string; email: string },
t: Translate,
): string {
const name = recipient.name?.trim() || recipient.email.trim();
if (!name) return t('email_composer.recipient_remove', 'Remove');
return t('email_composer.recipient_remove_named', 'Remove {name}', { name });
}