From 32727e23dbaeaaa5701ebb1880539c67116c851e Mon Sep 17 00:00:00 2001 From: Daniel Riera Date: Fri, 16 May 2025 12:51:11 -0400 Subject: [PATCH] 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 * handle undefined --------- Co-authored-by: Jonathan Prusik --- apps/browser/src/_locales/en/messages.json | 4 ++++ .../content/components/buttons/action-button.ts | 4 ++++ .../content/components/buttons/badge-button.ts | 9 +++++++++ .../content/components/buttons/close-button.ts | 11 +++++++++-- .../content/components/cipher/cipher-action.ts | 6 ++++++ .../autofill/content/components/cipher/cipher-item.ts | 11 +++++++++-- .../lit-stories/buttons/close-button.lit-stories.ts | 2 ++ .../content/components/lit-stories/mock-data.ts | 1 + .../components/notification/confirmation/container.ts | 5 ++++- .../content/components/notification/container.ts | 1 + .../content/components/notification/header.ts | 5 ++++- 11 files changed, 53 insertions(+), 6 deletions(-) diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 61a6d73e52c..f436c45ab75 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -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" diff --git a/apps/browser/src/autofill/content/components/buttons/action-button.ts b/apps/browser/src/autofill/content/components/buttons/action-button.ts index 41d92a0449d..8d8bfacec77 100644 --- a/apps/browser/src/autofill/content/components/buttons/action-button.ts +++ b/apps/browser/src/autofill/content/components/buttons/action-button.ts @@ -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 { diff --git a/apps/browser/src/autofill/content/components/buttons/badge-button.ts b/apps/browser/src/autofill/content/components/buttons/badge-button.ts index 9852c07d47b..3cdd453ee1a 100644 --- a/apps/browser/src/autofill/content/components/buttons/badge-button.ts +++ b/apps/browser/src/autofill/content/components/buttons/badge-button.ts @@ -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({ `; diff --git a/apps/browser/src/autofill/content/components/cipher/cipher-action.ts b/apps/browser/src/autofill/content/components/cipher/cipher-action.ts index 94bfa2c73c1..34ad5e1c9a9 100644 --- a/apps/browser/src/autofill/content/components/cipher/cipher-action.ts +++ b/apps/browser/src/autofill/content/components/cipher/cipher-action.ts @@ -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, diff --git a/apps/browser/src/autofill/content/components/cipher/cipher-item.ts b/apps/browser/src/autofill/content/components/cipher/cipher-item.ts index c290b68a291..ab3b57f535c 100644 --- a/apps/browser/src/autofill/content/components/cipher/cipher-item.ts +++ b/apps/browser/src/autofill/content/components/cipher/cipher-item.ts @@ -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`
- ${CipherAction({ handleAction, i18n, notificationType, theme })} + ${CipherAction({ + handleAction, + i18n, + itemName: name, + notificationType, + theme, + username: login?.username, + })}
`; } diff --git a/apps/browser/src/autofill/content/components/lit-stories/buttons/close-button.lit-stories.ts b/apps/browser/src/autofill/content/components/lit-stories/buttons/close-button.lit-stories.ts index 56e66654cb8..886c16c7515 100644 --- a/apps/browser/src/autofill/content/components/lit-stories/buttons/close-button.lit-stories.ts +++ b/apps/browser/src/autofill/content/components/lit-stories/buttons/close-button.lit-stories.ts @@ -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: { diff --git a/apps/browser/src/autofill/content/components/lit-stories/mock-data.ts b/apps/browser/src/autofill/content/components/lit-stories/mock-data.ts index 7ca347ecb14..81cdf5a50f3 100644 --- a/apps/browser/src/autofill/content/components/lit-stories/mock-data.ts +++ b/apps/browser/src/autofill/content/components/lit-stories/mock-data.ts @@ -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", diff --git a/apps/browser/src/autofill/content/components/notification/confirmation/container.ts b/apps/browser/src/autofill/content/components/notification/confirmation/container.ts index d4d66c7a7be..fc6ae4a353b 100644 --- a/apps/browser/src/autofill/content/components/notification/confirmation/container.ts +++ b/apps/browser/src/autofill/content/components/notification/confirmation/container.ts @@ -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({
${NotificationHeader({ handleCloseNotification, + i18n, message: headerMessage, theme, })} diff --git a/apps/browser/src/autofill/content/components/notification/container.ts b/apps/browser/src/autofill/content/components/notification/container.ts index 94adb1e2549..313e3eecf01 100644 --- a/apps/browser/src/autofill/content/components/notification/container.ts +++ b/apps/browser/src/autofill/content/components/notification/container.ts @@ -53,6 +53,7 @@ export function NotificationContainer({
${NotificationHeader({ handleCloseNotification, + i18n, message: headerMessage, theme, })} diff --git a/apps/browser/src/autofill/content/components/notification/header.ts b/apps/browser/src/autofill/content/components/notification/header.ts index b2f8962917b..3d657b77ecd 100644 --- a/apps/browser/src/autofill/content/components/notification/header.ts +++ b/apps/browser/src/autofill/content/components/notification/header.ts @@ -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({
${showIcon ? BrandIconContainer({ theme }) : null} ${message ? NotificationHeaderMessage({ message, theme }) : null} - ${isDismissable ? CloseButton({ handleCloseNotification, theme }) : null} + ${isDismissable ? CloseButton({ handleCloseNotification, i18n, theme }) : null}
`; }