mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 08:13:50 +00:00
feat: move a recipient between To, Cc and Bcc from the chip's menu
This commit is contained in:
@@ -299,3 +299,29 @@ describe('recipient fields (SR-06, CV-02)', () => {
|
||||
expect(chip).toHaveTextContent('invalid_recipient');
|
||||
});
|
||||
});
|
||||
|
||||
describe('moving a recipient by keyboard (MO-07)', () => {
|
||||
it('moves a chip to Cc from its menu and announces it', async () => {
|
||||
render(<EmailComposer initialData={{ ...DRAFT, to: 'Anna Berg <anna@example.com>' }} />);
|
||||
const chip = within(screen.getByRole('list', { name: 'to:' })).getByRole('listitem');
|
||||
chip.focus();
|
||||
fireEvent.keyDown(chip, { key: 'Enter' });
|
||||
|
||||
const move = await screen.findByTestId('recipient-move-cc');
|
||||
expect(move).toHaveTextContent('recipient_move_to:cc');
|
||||
expect(screen.queryByTestId('recipient-move-to')).toBeNull();
|
||||
fireEvent.click(move);
|
||||
|
||||
await waitFor(() => expect(screen.queryByRole('list', { name: 'to:' })).toBeNull());
|
||||
expect(within(screen.getByRole('list', { name: 'cc_label' })).getByRole('listitem')).toHaveTextContent('Anna Berg');
|
||||
expect(liveRegion()).toHaveTextContent('recipient_moved:Anna Berg|cc');
|
||||
});
|
||||
|
||||
it('opens the chip menu with Shift+F10 too', async () => {
|
||||
render(<EmailComposer initialData={{ ...DRAFT, to: 'anna@example.com' }} />);
|
||||
const chip = within(screen.getByRole('list', { name: 'to:' })).getByRole('listitem');
|
||||
chip.focus();
|
||||
fireEvent.keyDown(chip, { key: 'F10', shiftKey: true });
|
||||
expect(await screen.findByTestId('recipient-move-bcc')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5174,6 +5174,7 @@ export function RecipientChipInput({
|
||||
const chipRefs = useRef<Array<HTMLElement | null>>([]);
|
||||
const errorId = `${labelId}-error`;
|
||||
const chipHintId = `${labelId}-chip-hint`;
|
||||
const fieldNames: Record<'to' | 'cc' | 'bcc', string> = { to: t('to'), cc: t('cc'), bcc: t('bcc') };
|
||||
const tabChip = chips.length === 0 ? -1 : Math.min(rovingChip ?? chips.length - 1, chips.length - 1);
|
||||
|
||||
const focusChip = (index: number) => {
|
||||
@@ -5749,6 +5750,21 @@ export function RecipientChipInput({
|
||||
)}
|
||||
<ContextMenuItem label={t('recipient_edit_name')} onClick={handleEditName} />
|
||||
<ContextMenuSeparator />
|
||||
{/* Moving between fields without dragging (WCAG 2.5.7). */}
|
||||
{(['to', 'cc', 'bcc'] as const).filter((target) => target !== field).map((target) => (
|
||||
<ContextMenuItem
|
||||
key={target}
|
||||
testId={`recipient-move-${target}`}
|
||||
label={t('recipient_move_to', { field: fieldNames[target] })}
|
||||
onClick={() => {
|
||||
if (contextMenu.data) onMoveChip(contextMenu.data.recipient, field, target);
|
||||
closeContextMenu();
|
||||
setRovingChip(null);
|
||||
setTimeout(() => inputRef.current?.focus(), 0);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem label={t('recipient_remove')} onClick={() => {
|
||||
if (contextMenu.data) {
|
||||
handleChipRemove(contextMenu.data.index, { stopPropagation: () => {} } as React.MouseEvent);
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "نسخ",
|
||||
"recipient_remove_named": "إزالة {name}",
|
||||
"recipient_chip_hint": "يزيله مفتاح Delete، ويفتح Enter خيارات أخرى",
|
||||
"recipient_move_to": "نقل إلى {field}",
|
||||
"recipient_added": "تمت إضافة {name} إلى {field}",
|
||||
"recipient_removed": "تمت إزالة {name} من {field}",
|
||||
"recipient_moved": "تم نقل {name} إلى {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Copia",
|
||||
"recipient_remove_named": "Treu {name}",
|
||||
"recipient_chip_hint": "Supr el treu, Retorn obre més opcions",
|
||||
"recipient_move_to": "Mou a {field}",
|
||||
"recipient_added": "S'ha afegit {name} a {field}",
|
||||
"recipient_removed": "S'ha tret {name} de {field}",
|
||||
"recipient_moved": "S'ha mogut {name} a {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Kopírovat",
|
||||
"recipient_remove_named": "Odebrat {name}",
|
||||
"recipient_chip_hint": "Delete příjemce odebere, Enter otevře další možnosti",
|
||||
"recipient_move_to": "Přesunout do {field}",
|
||||
"recipient_added": "{name} přidán do {field}",
|
||||
"recipient_removed": "{name} odebrán z {field}",
|
||||
"recipient_moved": "{name} přesunut do {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Kopiér",
|
||||
"recipient_remove_named": "Fjern {name}",
|
||||
"recipient_chip_hint": "Delete fjerner modtageren, Enter åbner flere muligheder",
|
||||
"recipient_move_to": "Flyt til {field}",
|
||||
"recipient_added": "{name} tilføjet til {field}",
|
||||
"recipient_removed": "{name} fjernet fra {field}",
|
||||
"recipient_moved": "{name} flyttet til {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Kopieren",
|
||||
"recipient_remove_named": "{name} entfernen",
|
||||
"recipient_chip_hint": "Entf entfernt den Empfänger, Eingabe öffnet weitere Optionen",
|
||||
"recipient_move_to": "Nach {field} verschieben",
|
||||
"recipient_added": "{name} zu {field} hinzugefügt",
|
||||
"recipient_removed": "{name} aus {field} entfernt",
|
||||
"recipient_moved": "{name} nach {field} verschoben",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"send_guard_failed": "Not sent - a plugin that checks messages before sending failed or did not answer.",
|
||||
"recipient_remove_named": "Remove {name}",
|
||||
"recipient_chip_hint": "Delete removes it, Enter opens more options",
|
||||
"recipient_move_to": "Move to {field}",
|
||||
"recipient_added": "Added {name} to {field}",
|
||||
"recipient_removed": "Removed {name} from {field}",
|
||||
"recipient_moved": "Moved {name} to {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Copiar",
|
||||
"recipient_remove_named": "Quitar a {name}",
|
||||
"recipient_chip_hint": "Supr lo quita, Intro abre más opciones",
|
||||
"recipient_move_to": "Mover a {field}",
|
||||
"recipient_added": "Se añadió a {name} en {field}",
|
||||
"recipient_removed": "Se quitó a {name} de {field}",
|
||||
"recipient_moved": "Se movió a {name} a {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Kopeeri",
|
||||
"recipient_remove_named": "Eemalda {name}",
|
||||
"recipient_chip_hint": "Delete eemaldab saaja, Enter avab rohkem valikuid",
|
||||
"recipient_move_to": "Teisalda väljale {field}",
|
||||
"recipient_added": "{name} lisati väljale {field}",
|
||||
"recipient_removed": "{name} eemaldati väljalt {field}",
|
||||
"recipient_moved": "{name} teisaldati väljale {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "کپی",
|
||||
"recipient_remove_named": "حذف {name}",
|
||||
"recipient_chip_hint": "کلید Delete آن را حذف میکند و Enter گزینههای بیشتری باز میکند",
|
||||
"recipient_move_to": "انتقال به {field}",
|
||||
"recipient_added": "{name} به {field} افزوده شد",
|
||||
"recipient_removed": "{name} از {field} حذف شد",
|
||||
"recipient_moved": "{name} به {field} منتقل شد",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Copier",
|
||||
"recipient_remove_named": "Retirer {name}",
|
||||
"recipient_chip_hint": "Suppr le retire, Entrée ouvre d'autres options",
|
||||
"recipient_move_to": "Déplacer vers {field}",
|
||||
"recipient_added": "{name} ajouté à {field}",
|
||||
"recipient_removed": "{name} retiré de {field}",
|
||||
"recipient_moved": "{name} déplacé vers {field}",
|
||||
|
||||
@@ -968,6 +968,7 @@
|
||||
"copy": "העתק",
|
||||
"recipient_remove_named": "הסרת {name}",
|
||||
"recipient_chip_hint": "Delete מסיר את הנמען, Enter פותח אפשרויות נוספות",
|
||||
"recipient_move_to": "העברה אל {field}",
|
||||
"recipient_added": "{name} נוסף אל {field}",
|
||||
"recipient_removed": "{name} הוסר מ{field}",
|
||||
"recipient_moved": "{name} הועבר אל {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Másolás",
|
||||
"recipient_remove_named": "{name} eltávolítása",
|
||||
"recipient_chip_hint": "A Delete eltávolítja, az Enter további lehetőségeket nyit meg",
|
||||
"recipient_move_to": "Áthelyezés ide: {field}",
|
||||
"recipient_added": "{name} hozzáadva ide: {field}",
|
||||
"recipient_removed": "{name} eltávolítva innen: {field}",
|
||||
"recipient_moved": "{name} áthelyezve ide: {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Copia",
|
||||
"recipient_remove_named": "Rimuovi {name}",
|
||||
"recipient_chip_hint": "Canc lo rimuove, Invio apre altre opzioni",
|
||||
"recipient_move_to": "Sposta in {field}",
|
||||
"recipient_added": "{name} aggiunto a {field}",
|
||||
"recipient_removed": "{name} rimosso da {field}",
|
||||
"recipient_moved": "{name} spostato in {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "コピー",
|
||||
"recipient_remove_named": "{name} を削除",
|
||||
"recipient_chip_hint": "Delete キーで削除、Enter キーでその他のオプション",
|
||||
"recipient_move_to": "{field} に移動",
|
||||
"recipient_added": "{name} を {field} に追加しました",
|
||||
"recipient_removed": "{name} を {field} から削除しました",
|
||||
"recipient_moved": "{name} を {field} に移動しました",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "복사",
|
||||
"recipient_remove_named": "{name} 제거",
|
||||
"recipient_chip_hint": "Delete 키로 제거하고 Enter 키로 다른 옵션을 열 수 있어요",
|
||||
"recipient_move_to": "{field}(으)로 이동",
|
||||
"recipient_added": "{name}을(를) {field}에 추가했어요",
|
||||
"recipient_removed": "{name}을(를) {field}에서 제거했어요",
|
||||
"recipient_moved": "{name}을(를) {field}(으)로 옮겼어요",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Kopēt",
|
||||
"recipient_remove_named": "Noņemt {name}",
|
||||
"recipient_chip_hint": "Delete to noņem, Enter atver citas iespējas",
|
||||
"recipient_move_to": "Pārvietot uz {field}",
|
||||
"recipient_added": "{name} pievienots laukam {field}",
|
||||
"recipient_removed": "{name} noņemts no lauka {field}",
|
||||
"recipient_moved": "{name} pārvietots uz {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Хуулах",
|
||||
"recipient_remove_named": "{name}-г хасах",
|
||||
"recipient_chip_hint": "Delete товч хасна, Enter товч бусад сонголтыг нээнэ",
|
||||
"recipient_move_to": "{field} руу зөөх",
|
||||
"recipient_added": "{name}-г {field}-д нэмлээ",
|
||||
"recipient_removed": "{name}-г {field}-ээс хаслаа",
|
||||
"recipient_moved": "{name}-г {field} руу зөөлөө",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Kopier",
|
||||
"recipient_remove_named": "Fjern {name}",
|
||||
"recipient_chip_hint": "Delete fjerner mottakeren, Enter åpner flere valg",
|
||||
"recipient_move_to": "Flytt til {field}",
|
||||
"recipient_added": "{name} lagt til i {field}",
|
||||
"recipient_removed": "{name} fjernet fra {field}",
|
||||
"recipient_moved": "{name} flyttet til {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Kopiëren",
|
||||
"recipient_remove_named": "{name} verwijderen",
|
||||
"recipient_chip_hint": "Delete verwijdert de ontvanger, Enter opent meer opties",
|
||||
"recipient_move_to": "Verplaatsen naar {field}",
|
||||
"recipient_added": "{name} toegevoegd aan {field}",
|
||||
"recipient_removed": "{name} verwijderd uit {field}",
|
||||
"recipient_moved": "{name} verplaatst naar {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Kopiuj",
|
||||
"recipient_remove_named": "Usuń {name}",
|
||||
"recipient_chip_hint": "Delete usuwa odbiorcę, Enter otwiera więcej opcji",
|
||||
"recipient_move_to": "Przenieś do {field}",
|
||||
"recipient_added": "Dodano {name} do {field}",
|
||||
"recipient_removed": "Usunięto {name} z {field}",
|
||||
"recipient_moved": "Przeniesiono {name} do {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Copiar",
|
||||
"recipient_remove_named": "Remover {name}",
|
||||
"recipient_chip_hint": "Delete remove o destinatário, Enter abre mais opções",
|
||||
"recipient_move_to": "Mover para {field}",
|
||||
"recipient_added": "{name} adicionado a {field}",
|
||||
"recipient_removed": "{name} removido de {field}",
|
||||
"recipient_moved": "{name} movido para {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Copiază",
|
||||
"recipient_remove_named": "Elimină {name}",
|
||||
"recipient_chip_hint": "Delete îl elimină, Enter deschide mai multe opțiuni",
|
||||
"recipient_move_to": "Mută la {field}",
|
||||
"recipient_added": "{name} a fost adăugat la {field}",
|
||||
"recipient_removed": "{name} a fost eliminat din {field}",
|
||||
"recipient_moved": "{name} a fost mutat la {field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Копировать",
|
||||
"recipient_remove_named": "Убрать {name}",
|
||||
"recipient_chip_hint": "Delete убирает получателя, Enter открывает другие действия",
|
||||
"recipient_move_to": "Переместить в {field}",
|
||||
"recipient_added": "{name}: добавлен в «{field}»",
|
||||
"recipient_removed": "{name}: убран из «{field}»",
|
||||
"recipient_moved": "{name}: перемещён в «{field}»",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Kopírovať",
|
||||
"recipient_remove_named": "Odstrániť {name}",
|
||||
"recipient_chip_hint": "Delete príjemcu odstráni, Enter otvorí ďalšie možnosti",
|
||||
"recipient_move_to": "Presunúť do {field}",
|
||||
"recipient_added": "{name} pridaný do {field}",
|
||||
"recipient_removed": "{name} odstránený z {field}",
|
||||
"recipient_moved": "{name} presunutý do {field}",
|
||||
|
||||
@@ -1251,6 +1251,7 @@
|
||||
"signature_edit_hint": "ดับเบิลคลิกเพื่อแก้ไขลายเซ็น",
|
||||
"recipient_remove_named": "นำ {name} ออก",
|
||||
"recipient_chip_hint": "กด Delete เพื่อนำออก กด Enter เพื่อเปิดตัวเลือกเพิ่มเติม",
|
||||
"recipient_move_to": "ย้ายไปที่ {field}",
|
||||
"recipient_added": "เพิ่ม {name} ใน {field} แล้ว",
|
||||
"recipient_removed": "นำ {name} ออกจาก {field} แล้ว",
|
||||
"recipient_moved": "ย้าย {name} ไปที่ {field} แล้ว",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Kopyala",
|
||||
"recipient_remove_named": "{name} kişisini kaldır",
|
||||
"recipient_chip_hint": "Delete kaldırır, Enter diğer seçenekleri açar",
|
||||
"recipient_move_to": "{field} alanına taşı",
|
||||
"recipient_added": "{name}, {field} alanına eklendi",
|
||||
"recipient_removed": "{name}, {field} alanından kaldırıldı",
|
||||
"recipient_moved": "{name}, {field} alanına taşındı",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "Копіювати",
|
||||
"recipient_remove_named": "Прибрати {name}",
|
||||
"recipient_chip_hint": "Delete прибирає одержувача, Enter відкриває інші дії",
|
||||
"recipient_move_to": "Перемістити в {field}",
|
||||
"recipient_added": "{name}: додано в «{field}»",
|
||||
"recipient_removed": "{name}: прибрано з «{field}»",
|
||||
"recipient_moved": "{name}: переміщено в «{field}»",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "複製",
|
||||
"recipient_remove_named": "移除 {name}",
|
||||
"recipient_chip_hint": "按 Delete 移除,按 Enter 開啟更多選項",
|
||||
"recipient_move_to": "移到{field}",
|
||||
"recipient_added": "已將 {name} 新增到{field}",
|
||||
"recipient_removed": "已將 {name} 從{field}移除",
|
||||
"recipient_moved": "已將 {name} 移到{field}",
|
||||
|
||||
@@ -1003,6 +1003,7 @@
|
||||
"copy": "复制",
|
||||
"recipient_remove_named": "移除 {name}",
|
||||
"recipient_chip_hint": "按 Delete 移除,按 Enter 打开更多选项",
|
||||
"recipient_move_to": "移到{field}",
|
||||
"recipient_added": "已将 {name} 添加到{field}",
|
||||
"recipient_removed": "已将 {name} 从{field}移除",
|
||||
"recipient_moved": "已将 {name} 移到{field}",
|
||||
|
||||
Reference in New Issue
Block a user