Skip to content

Commit

Permalink
first pass at "generated credential" screen reader notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
audreyality committed Jan 14, 2025
1 parent 553d20f commit 7fd5924
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 30 deletions.
12 changes: 12 additions & 0 deletions apps/browser/src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,18 @@
"generatePassphrase": {
"message": "Generate passphrase"
},
"passwordGenerated": {
"message": "Password generated"
},
"passphraseGenerated": {
"message": "Passphrase generated"
},
"usernameGenerated": {
"message": "Username generated"
},
"emailGenerated": {
"message": "Email generated"
},
"regeneratePassword": {
"message": "Regenerate password"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,6 @@ export class CredentialGeneratorHistoryComponent {

protected getGeneratedValueText(credential: GeneratedCredential) {
const info = this.generatorService.algorithm(credential.category);
return info.generatedValue;
return info.credentialType;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
[disabled]="!(algorithm$ | async)"
></button>
</div>
<div class="tw-sr-only" aria-live="assertive">{{ credentialGeneratedMessage$ | async }}</div>
</bit-card>
<tools-password-settings
class="tw-mt-6"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import {
catchError,
combineLatest,
combineLatestWith,
concatMap,
distinctUntilChanged,
filter,
map,
of,
ReplaySubject,
Subject,
switchMap,
Expand Down Expand Up @@ -473,7 +475,7 @@ export class CredentialGeneratorComponent implements OnInit, OnDestroy {
*/
protected credentialTypeLabel$ = this.algorithm$.pipe(
filter((algorithm) => !!algorithm),
map(({ generatedValue }) => generatedValue),
map(({ credentialType }) => credentialType),
);

/** Emits hint key for the currently selected credential type */
Expand All @@ -491,6 +493,14 @@ export class CredentialGeneratorComponent implements OnInit, OnDestroy {
/** Emits when a new credential is requested */
private readonly generate$ = new Subject<string>();

/**
* Emits the credential generated message whenever the generator runs
*/
protected credentialGeneratedMessage$ = this.value$.pipe(
withLatestFrom(this.algorithm$),
concatMap(([, algorithm]) => of("", algorithm.onGeneratedMessage)),
);

/** Request a new value from the generator
* @param requestor a label used to trace generation request
* origin in the debugger.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
[disabled]="!(algorithm$ | async)"
></button>
</div>
<div class="tw-sr-only" aria-live="assertive">{{ credentialGeneratedMessage$ | async }}</div>
</bit-card>
<tools-password-settings
class="tw-mt-6"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { Component, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output } fro
import {
BehaviorSubject,
catchError,
concatMap,
distinctUntilChanged,
filter,
map,
of,
ReplaySubject,
Subject,
switchMap,
Expand Down Expand Up @@ -249,7 +251,15 @@ export class PasswordGeneratorComponent implements OnInit, OnDestroy {
*/
protected credentialTypeLabel$ = this.algorithm$.pipe(
filter((algorithm) => !!algorithm),
map(({ generatedValue }) => generatedValue),
map(({ credentialType }) => credentialType),
);

/**
* Emits the credential generated message whenever the generator runs
*/
protected credentialGeneratedMessage$ = this.value$.pipe(
withLatestFrom(this.algorithm$),
concatMap(([, algorithm]) => of("", algorithm.onGeneratedMessage)),
);

private toOptions(algorithms: AlgorithmInfo[]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
{{ credentialTypeCopyLabel$ | async }}
</button>
</div>
<div class="tw-sr-only" aria-live="assertive">{{ credentialGeneratedMessage$ | async }}</div>
</bit-card>
<bit-section [disableMargin]="disableMargin">
<bit-section-header>
Expand Down
34 changes: 22 additions & 12 deletions libs/tools/generator/components/src/username-generator.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import {
catchError,
combineLatest,
combineLatestWith,
concatMap,
distinctUntilChanged,
filter,
map,
of,
ReplaySubject,
Subject,
switchMap,
Expand Down Expand Up @@ -375,6 +377,18 @@ export class UsernameGeneratorComponent implements OnInit, OnDestroy {
/** tracks the currently selected credential type */
protected algorithm$ = new ReplaySubject<AlgorithmInfo>(1);

/** Emits hint key for the currently selected credential type */
protected credentialTypeHint$ = new ReplaySubject<string>(1);

/** Emits the last generated value. */
protected readonly value$ = new BehaviorSubject<string>("");

/** Emits when the userId changes */
protected readonly userId$ = new BehaviorSubject<UserId>(null);

/** Emits when a new credential is requested */
private readonly generate$ = new Subject<string>();

protected showAlgorithm$ = this.algorithm$.pipe(
combineLatestWith(this.showForwarder$),
map(([algorithm, showForwarder]) => (showForwarder ? null : algorithm)),
Expand All @@ -401,20 +415,16 @@ export class UsernameGeneratorComponent implements OnInit, OnDestroy {
*/
protected credentialTypeLabel$ = this.algorithm$.pipe(
filter((algorithm) => !!algorithm),
map(({ generatedValue }) => generatedValue),
map(({ credentialType }) => credentialType),
);

/** Emits hint key for the currently selected credential type */
protected credentialTypeHint$ = new ReplaySubject<string>(1);

/** Emits the last generated value. */
protected readonly value$ = new BehaviorSubject<string>("");

/** Emits when the userId changes */
protected readonly userId$ = new BehaviorSubject<UserId>(null);

/** Emits when a new credential is requested */
private readonly generate$ = new Subject<string>();
/**
* Emits the credential generated message whenever the generator runs
*/
protected credentialGeneratedMessage$ = this.value$.pipe(
withLatestFrom(this.algorithm$),
concatMap(([, algorithm]) => of("", algorithm.onGeneratedMessage)),
);

/** Request a new value from the generator
* @param requestor a label used to trace generation request
Expand Down
18 changes: 12 additions & 6 deletions libs/tools/generator/core/src/data/generators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ const PASSPHRASE: CredentialGeneratorConfiguration<
category: "password",
nameKey: "passphrase",
generateKey: "generatePassphrase",
generatedValueKey: "passphrase",
onGeneratedMessageKey: "passphraseGenerated",
credentialTypeKey: "passphrase",
copyKey: "copyPassphrase",
useGeneratedValueKey: "useThisPassphrase",
onlyOnRequest: false,
Expand Down Expand Up @@ -118,7 +119,8 @@ const PASSWORD: CredentialGeneratorConfiguration<
category: "password",
nameKey: "password",
generateKey: "generatePassword",
generatedValueKey: "password",
onGeneratedMessageKey: "passwordGenerated",
credentialTypeKey: "password",
copyKey: "copyPassword",
useGeneratedValueKey: "useThisPassword",
onlyOnRequest: false,
Expand Down Expand Up @@ -195,7 +197,8 @@ const USERNAME: CredentialGeneratorConfiguration<EffUsernameGenerationOptions, N
category: "username",
nameKey: "randomWord",
generateKey: "generateUsername",
generatedValueKey: "username",
onGeneratedMessageKey: "usernameGenerated",
credentialTypeKey: "username",
copyKey: "copyUsername",
useGeneratedValueKey: "useThisUsername",
onlyOnRequest: false,
Expand Down Expand Up @@ -248,7 +251,8 @@ const CATCHALL: CredentialGeneratorConfiguration<CatchallGenerationOptions, NoPo
nameKey: "catchallEmail",
descriptionKey: "catchallEmailDesc",
generateKey: "generateEmail",
generatedValueKey: "email",
onGeneratedMessageKey: "emailGenerated",
credentialTypeKey: "email",
copyKey: "copyEmail",
useGeneratedValueKey: "useThisEmail",
onlyOnRequest: false,
Expand Down Expand Up @@ -304,7 +308,8 @@ const SUBADDRESS: CredentialGeneratorConfiguration<SubaddressGenerationOptions,
nameKey: "plusAddressedEmail",
descriptionKey: "plusAddressedEmailDesc",
generateKey: "generateEmail",
generatedValueKey: "email",
onGeneratedMessageKey: "emailGenerated",
credentialTypeKey: "email",
copyKey: "copyEmail",
useGeneratedValueKey: "useThisEmail",
onlyOnRequest: false,
Expand Down Expand Up @@ -362,7 +367,8 @@ export function toCredentialGeneratorConfiguration<Settings extends ApiSettings
nameKey: configuration.name,
descriptionKey: "forwardedEmailDesc",
generateKey: "generateEmail",
generatedValueKey: "email",
onGeneratedMessageKey: "emailGenerated",
credentialTypeKey: "email",
copyKey: "copyEmail",
useGeneratedValueKey: "useThisEmail",
onlyOnRequest: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ const SomeAlgorithm = "passphrase";
const SomeCategory = "password";
const SomeNameKey = "passphraseKey";
const SomeGenerateKey = "generateKey";
const SomeGeneratedValueKey = "generatedValueKey";
const SomeCredentialTypeKey = "credentialTypeKey";
const SomeOnGeneratedMessageKey = "onGeneratedMessageKey";
const SomeCopyKey = "copyKey";
const SomeUseGeneratedValueKey = "useGeneratedValueKey";

Expand All @@ -82,7 +83,8 @@ const SomeConfiguration: CredentialGeneratorConfiguration<SomeSettings, SomePoli
category: SomeCategory,
nameKey: SomeNameKey,
generateKey: SomeGenerateKey,
generatedValueKey: SomeGeneratedValueKey,
onGeneratedMessageKey: SomeOnGeneratedMessageKey,
credentialTypeKey: SomeCredentialTypeKey,
copyKey: SomeCopyKey,
useGeneratedValueKey: SomeUseGeneratedValueKey,
onlyOnRequest: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ export class CredentialGeneratorService {
category: generator.category,
name: integration ? integration.name : this.i18nService.t(generator.nameKey),
generate: this.i18nService.t(generator.generateKey),
generatedValue: this.i18nService.t(generator.generatedValueKey),
onGeneratedMessage: this.i18nService.t(generator.onGeneratedMessageKey),
credentialType: this.i18nService.t(generator.credentialTypeKey),
copy: this.i18nService.t(generator.copyKey),
useGeneratedValue: this.i18nService.t(generator.useGeneratedValueKey),
onlyOnRequest: generator.onlyOnRequest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,17 @@ export type AlgorithmInfo = {
/* Localized generate button label */
generate: string;

/** Localized "credential generated" informational message */
onGeneratedMessage: string;

/* Localized copy button label */
copy: string;

/* Localized dialog button label */
useGeneratedValue: string;

/* Localized generated value label */
generatedValue: string;
credentialType: string;

/** Localized algorithm description */
description?: string;
Expand Down Expand Up @@ -79,17 +82,22 @@ export type CredentialGeneratorInfo = {
/** Localization key for the credential description*/
descriptionKey?: string;

/* Localization key for the generate command label */
/** Localization key for the generate command label */
generateKey: string;

/* Localization key for the copy button label */
/** Localization key for the copy button label */
copyKey: string;

/* Localized "use generated credential" button label */
/** Localization key for the "credential generated" informational message */
onGeneratedMessageKey: string;

/** Localized "use generated credential" button label */
useGeneratedValueKey: string;

/* Localization key for describing values generated by this generator */
generatedValueKey: string;
/** Localization key for describing the kind of credential generated
* by this generator.
*/
credentialTypeKey: string;

/** When true, credential generation must be explicitly requested.
* @remarks this property is useful when credential generation
Expand Down

0 comments on commit 7fd5924

Please sign in to comment.