1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 01:03:35 +00:00

PM-21688 finalize a11y UX concerns misc (#14805)

* PM-21688 finalize a11y UX concerns misc

* add Close to close button for SR, handle error new item SR

* fix hover state for badge

* dynamic update button

* fix types

* Update apps/browser/src/autofill/content/components/lit-stories/mock-data.ts

Co-authored-by: Jonathan Prusik <jprusik@users.noreply.github.com>

* handle undefined

---------

Co-authored-by: Jonathan Prusik <jprusik@users.noreply.github.com>
This commit is contained in:
Daniel Riera
2025-05-16 12:51:11 -04:00
committed by GitHub
parent c8629b92d3
commit 32727e23db
11 changed files with 53 additions and 6 deletions

View File

@@ -1071,6 +1071,10 @@
},
"description": "Aria label for the view button in notification bar confirmation message"
},
"notificationNewItemAria": {
"message": "New Item, opens in new window",
"description": "Aria label for the new item button in notification bar confirmation message when error is prompted"
},
"notificationEditTooltip": {
"message": "Edit before saving",
"description": "Tooltip and Aria label for edit button on cipher item"

View File

@@ -64,6 +64,10 @@ const actionButtonStyles = ({ disabled, theme }: { disabled: boolean; theme: The
background-color: ${themes[theme].primary["700"]};
color: ${themes[theme].text.contrast};
}
:focus {
outline: 2px solid ${themes[theme].primary["600"]};
outline-offset: 1px;
}
`}
svg {

View File

@@ -8,15 +8,19 @@ import { border, themes, typography, spacing } from "../constants/styles";
export type BadgeButtonProps = {
buttonAction: (e: Event) => void;
buttonText: string;
itemName: string;
disabled?: boolean;
theme: Theme;
username?: string;
};
export function BadgeButton({
buttonAction,
buttonText,
disabled = false,
itemName,
theme,
username,
}: BadgeButtonProps) {
const handleButtonClick = (event: Event) => {
if (!disabled) {
@@ -28,6 +32,7 @@ export function BadgeButton({
<button
type="button"
title=${buttonText}
aria-label=${[buttonText, [itemName, username].filter(Boolean).join(" ")]}
class=${badgeButtonStyles({ disabled, theme })}
@click=${handleButtonClick}
>
@@ -65,5 +70,9 @@ const badgeButtonStyles = ({ disabled, theme }: { disabled: boolean; theme: Them
background-color: ${themes[theme].primary["600"]};
color: ${themes[theme].text.contrast};
}
:focus {
outline: 2px solid ${themes[theme].primary["600"]};
outline-offset: 2px;
}
`}
`;

View File

@@ -3,17 +3,24 @@ import { html } from "lit";
import { Theme } from "@bitwarden/common/platform/enums";
import { I18n } from "../common-types";
import { spacing, themes } from "../constants/styles";
import { Close as CloseIcon } from "../icons";
export type CloseButtonProps = {
i18n: I18n;
handleCloseNotification: (e: Event) => void;
theme: Theme;
};
export function CloseButton({ handleCloseNotification, theme }: CloseButtonProps) {
export function CloseButton({ handleCloseNotification, i18n, theme }: CloseButtonProps) {
return html`
<button type="button" class=${closeButtonStyles(theme)} @click=${handleCloseNotification}>
<button
type="button"
aria-label=${i18n.close}
class=${closeButtonStyles(theme)}
@click=${handleCloseNotification}
>
${CloseIcon({ theme })}
</button>
`;

View File

@@ -8,8 +8,10 @@ import { I18n } from "../common-types";
export type CipherActionProps = {
handleAction?: (e: Event) => void;
i18n: I18n;
itemName: string;
notificationType: typeof NotificationTypes.Change | typeof NotificationTypes.Add;
theme: Theme;
username?: string;
};
export function CipherAction({
@@ -17,14 +19,18 @@ export function CipherAction({
/* no-op */
},
i18n,
itemName,
notificationType,
theme,
username,
}: CipherActionProps) {
return notificationType === NotificationTypes.Change
? BadgeButton({
buttonAction: handleAction,
buttonText: i18n.notificationUpdate,
itemName,
theme,
username,
})
: EditButton({
buttonAction: handleAction,

View File

@@ -32,14 +32,21 @@ export function CipherItem({
notificationType,
theme = ThemeTypes.Light,
}: CipherItemProps) {
const { icon } = cipher;
const { icon, name, login } = cipher;
const uri = (icon.imageEnabled && icon.image) || undefined;
let cipherActionButton = null;
if (notificationType === NotificationTypes.Change || notificationType === NotificationTypes.Add) {
cipherActionButton = html`<div>
${CipherAction({ handleAction, i18n, notificationType, theme })}
${CipherAction({
handleAction,
i18n,
itemName: name,
notificationType,
theme,
username: login?.username,
})}
</div>`;
}

View File

@@ -3,6 +3,7 @@ import { Meta, StoryObj } from "@storybook/web-components";
import { ThemeTypes } from "@bitwarden/common/platform/enums/theme-type.enum";
import { CloseButton, CloseButtonProps } from "../../buttons/close-button";
import { mockI18n } from "../mock-data";
export default {
title: "Components/Buttons/Close Button",
@@ -15,6 +16,7 @@ export default {
handleCloseNotification: () => {
alert("Close button clicked!");
},
i18n: mockI18n,
},
parameters: {
design: {

View File

@@ -127,6 +127,7 @@ export const mockI18n = {
notificationUnlock: "Unlock",
notificationUnlockDesc: "Unlock your Bitwarden vault to complete the autofill request.",
notificationViewAria: `View $ITEMNAME$, opens in new window`,
notificationNewItemAria: "New Item, opens in new window",
saveAction: "Save",
saveAsNewLoginAction: "Save as new login",
saveFailure: "Error saving",

View File

@@ -45,7 +45,9 @@ export function NotificationConfirmationContainer({
const headerMessage = getHeaderMessage(i18n, type, error);
const confirmationMessage = getConfirmationMessage(i18n, type, error);
const buttonText = error ? i18n.newItem : i18n.view;
const buttonAria = chrome.i18n.getMessage("notificationViewAria", [itemName]);
const buttonAria = error
? i18n.notificationNewItemAria
: chrome.i18n.getMessage("notificationViewAria", [itemName]);
let messageDetails: string | undefined;
let remainingTasksCount: number | undefined;
@@ -68,6 +70,7 @@ export function NotificationConfirmationContainer({
<div class=${notificationContainerStyles(theme)}>
${NotificationHeader({
handleCloseNotification,
i18n,
message: headerMessage,
theme,
})}

View File

@@ -53,6 +53,7 @@ export function NotificationContainer({
<div class=${notificationContainerStyles(theme)}>
${NotificationHeader({
handleCloseNotification,
i18n,
message: headerMessage,
theme,
})}

View File

@@ -4,6 +4,7 @@ import { html } from "lit";
import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums";
import { CloseButton } from "../buttons/close-button";
import { I18n } from "../common-types";
import { spacing, themes } from "../constants/styles";
import { BrandIconContainer } from "../icons/brand-icon-container";
@@ -16,6 +17,7 @@ const { css } = createEmotion({
});
export type NotificationHeaderProps = {
i18n: I18n;
message?: string;
standalone?: boolean;
theme: Theme;
@@ -23,6 +25,7 @@ export type NotificationHeaderProps = {
};
export function NotificationHeader({
i18n,
message,
standalone = false,
theme = ThemeTypes.Light,
@@ -35,7 +38,7 @@ export function NotificationHeader({
<div class=${notificationHeaderStyles({ standalone, theme })}>
${showIcon ? BrandIconContainer({ theme }) : null}
${message ? NotificationHeaderMessage({ message, theme }) : null}
${isDismissable ? CloseButton({ handleCloseNotification, theme }) : null}
${isDismissable ? CloseButton({ handleCloseNotification, i18n, theme }) : null}
</div>
`;
}