mirror of
https://github.com/bitwarden/browser
synced 2025-12-18 17:23:37 +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:
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
@@ -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>
|
||||
`;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>`;
|
||||
}
|
||||
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
})}
|
||||
|
||||
@@ -53,6 +53,7 @@ export function NotificationContainer({
|
||||
<div class=${notificationContainerStyles(theme)}>
|
||||
${NotificationHeader({
|
||||
handleCloseNotification,
|
||||
i18n,
|
||||
message: headerMessage,
|
||||
theme,
|
||||
})}
|
||||
|
||||
@@ -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>
|
||||
`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user