Skip to content

Commit b2ad50b

Browse files
[PM-16100][A11y][Extension] Usernames not being read by screen readers like they used to be (#13800)
* update autofill a11y * fixes to cipher item title
1 parent 10695fd commit b2ad50b

File tree

6 files changed

+51
-19
lines changed

6 files changed

+51
-19
lines changed

apps/browser/src/_locales/en/messages.json

+28
Original file line numberDiff line numberDiff line change
@@ -4279,6 +4279,20 @@
42794279
}
42804280
}
42814281
},
4282+
"viewItemTitleWithField": {
4283+
"message": "View item - $ITEMNAME$ - $FIELD$",
4284+
"description": "Title for a link that opens a view for an item.",
4285+
"placeholders": {
4286+
"itemname": {
4287+
"content": "$1",
4288+
"example": "Secret Item"
4289+
},
4290+
"field": {
4291+
"content": "$2",
4292+
"example": "Username"
4293+
}
4294+
}
4295+
},
42824296
"autofillTitle": {
42834297
"message": "Autofill - $ITEMNAME$",
42844298
"description": "Title for a button that autofills a login item.",
@@ -4289,6 +4303,20 @@
42894303
}
42904304
}
42914305
},
4306+
"autofillTitleWithField": {
4307+
"message": "Autofill - $ITEMNAME$ - $FIELD$",
4308+
"description": "Title for a button that autofills a login item.",
4309+
"placeholders": {
4310+
"itemname": {
4311+
"content": "$1",
4312+
"example": "Secret Item"
4313+
},
4314+
"field": {
4315+
"content": "$2",
4316+
"example": "Username"
4317+
}
4318+
}
4319+
},
42924320
"copyFieldValue": {
42934321
"message": "Copy $FIELD$, $VALUE$",
42944322
"description": "Title for a button that copies a field value to the clipboard.",

apps/browser/src/vault/popup/components/vault-v2/autofill-vault-list-items/autofill-vault-list-items.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
[description]="(showEmptyAutofillTip$ | async) ? ('autofillSuggestionsTip' | i18n) : null"
88
showAutofillButton
99
[disableDescriptionMargin]="showEmptyAutofillTip$ | async"
10-
[primaryActionAutofill]="clickItemsToAutofillVaultView"
10+
[primaryActionAutofill]="clickItemsToAutofillVaultView$ | async"
1111
[groupByType]="groupByType()"
1212
></app-vault-list-items-container>

apps/browser/src/vault/popup/components/vault-v2/autofill-vault-list-items/autofill-vault-list-items.component.ts

+6-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { CommonModule } from "@angular/common";
2-
import { Component, OnInit } from "@angular/core";
2+
import { Component } from "@angular/core";
33
import { toSignal } from "@angular/core/rxjs-interop";
4-
import { combineLatest, firstValueFrom, map, Observable } from "rxjs";
4+
import { combineLatest, map, Observable } from "rxjs";
55

66
import { JslibModule } from "@bitwarden/angular/jslib.module";
77
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
@@ -33,7 +33,7 @@ import { VaultListItemsContainerComponent } from "../vault-list-items-container/
3333
selector: "app-autofill-vault-list-items",
3434
templateUrl: "autofill-vault-list-items.component.html",
3535
})
36-
export class AutofillVaultListItemsComponent implements OnInit {
36+
export class AutofillVaultListItemsComponent {
3737
/**
3838
* The list of ciphers that can be used to autofill the current page.
3939
* @protected
@@ -47,7 +47,9 @@ export class AutofillVaultListItemsComponent implements OnInit {
4747
*/
4848
protected showRefresh: boolean = BrowserPopupUtils.inSidebar(window);
4949

50-
clickItemsToAutofillVaultView = false;
50+
/** Flag indicating whether the login item should automatically autofill when clicked */
51+
protected clickItemsToAutofillVaultView$: Observable<boolean> =
52+
this.vaultSettingsService.clickItemsToAutofillVaultView$;
5153

5254
protected groupByType = toSignal(
5355
this.vaultPopupItemsService.hasFilterApplied$.pipe(map((hasFilter) => !hasFilter)),
@@ -84,12 +86,6 @@ export class AutofillVaultListItemsComponent implements OnInit {
8486
// TODO: Migrate logic to show Autofill policy toast PM-8144
8587
}
8688

87-
async ngOnInit() {
88-
this.clickItemsToAutofillVaultView = await firstValueFrom(
89-
this.vaultSettingsService.clickItemsToAutofillVaultView$,
90-
);
91-
}
92-
9389
/**
9490
* Refreshes the current tab to re-populate the autofill ciphers.
9591
* @protected

apps/browser/src/vault/popup/components/vault-v2/vault-list-items-container/vault-list-items-container.component.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ <h3 class="tw-text-muted tw-text-xs tw-font-semibold tw-pl-1 tw-mb-1 bit-compact
9999
type="button"
100100
(click)="primaryActionOnSelect(cipher)"
101101
(dblclick)="launchCipher(cipher)"
102-
[appA11yTitle]="cipherItemTitleKey | async | i18n: cipher.name"
102+
[appA11yTitle]="
103+
cipherItemTitleKey(cipher) | async | i18n: cipher.name : cipher.login.username
104+
"
103105
class="{{ itemHeightClass }}"
104106
>
105107
<div slot="start" class="tw-justify-start tw-w-7 tw-flex">

apps/browser/src/vault/popup/components/vault-v2/vault-list-items-container/vault-list-items-container.component.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,14 @@ export class VaultListItemsContainerComponent implements OnInit, AfterViewInit {
206206
/**
207207
* Resolved i18n key to use for suggested cipher items
208208
*/
209-
cipherItemTitleKey = this.currentURIIsBlocked$.pipe(
210-
map((uriIsBlocked) =>
211-
this.primaryActionAutofill && !uriIsBlocked ? "autofillTitle" : "viewItemTitle",
212-
),
213-
);
209+
cipherItemTitleKey = (cipher: CipherView) =>
210+
this.currentURIIsBlocked$.pipe(
211+
map((uriIsBlocked) => {
212+
const hasUsername = cipher.login?.username != null;
213+
const key = this.primaryActionAutofill && !uriIsBlocked ? "autofillTitle" : "viewItemTitle";
214+
return hasUsername ? `${key}WithField` : key;
215+
}),
216+
);
214217

215218
/**
216219
* Option to show the autofill button for each item.

libs/common/src/vault/services/vault-settings/vault-settings.service.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Observable, map } from "rxjs";
1+
import { Observable, map, shareReplay } from "rxjs";
22

33
import { ActiveUserState, GlobalState, StateProvider } from "../../../platform/state";
44
import { VaultSettingsService as VaultSettingsServiceAbstraction } from "../../abstractions/vault-settings/vault-settings.service";
@@ -46,7 +46,10 @@ export class VaultSettingsService implements VaultSettingsServiceAbstraction {
4646
* {@link VaultSettingsServiceAbstraction.clickItemsToAutofillVaultView$$}
4747
*/
4848
readonly clickItemsToAutofillVaultView$: Observable<boolean> =
49-
this.clickItemsToAutofillVaultViewState.state$.pipe(map((x) => x ?? false));
49+
this.clickItemsToAutofillVaultViewState.state$.pipe(
50+
map((x) => x ?? false),
51+
shareReplay({ bufferSize: 1, refCount: false }),
52+
);
5053

5154
constructor(private stateProvider: StateProvider) {}
5255

0 commit comments

Comments
 (0)