From 95ba8fda074f402599bb4d10ccd5af3a8c6a8357 Mon Sep 17 00:00:00 2001 From: Jonathan Prusik Date: Fri, 16 May 2025 17:57:56 -0400 Subject: [PATCH] refactor at-risk notification components --- .../container.lit-stories.ts | 9 +-- .../notification/at-risk-password/body.ts | 47 +++++++----- .../at-risk-password/container.ts | 54 +++++++------- .../notification/at-risk-password/footer.ts | 15 +++- .../notification/at-risk-password/message.ts | 72 +++++++------------ .../notification/confirmation/body.ts | 4 +- .../notification/confirmation/container.ts | 2 +- .../notification/confirmation/footer.ts | 7 +- .../notification/confirmation/message.ts | 6 +- .../content/components/notification/footer.ts | 10 +-- 10 files changed, 107 insertions(+), 119 deletions(-) diff --git a/apps/browser/src/autofill/content/components/lit-stories/notification/at-risk-notification/container.lit-stories.ts b/apps/browser/src/autofill/content/components/lit-stories/notification/at-risk-notification/container.lit-stories.ts index e66edc5122f..1c5860ad7dd 100644 --- a/apps/browser/src/autofill/content/components/lit-stories/notification/at-risk-notification/container.lit-stories.ts +++ b/apps/browser/src/autofill/content/components/lit-stories/notification/at-risk-notification/container.lit-stories.ts @@ -2,7 +2,6 @@ import { Meta, StoryObj } from "@storybook/web-components"; import { ThemeTypes } from "@bitwarden/common/platform/enums"; -import { NotificationTypes } from "../../../../../notification/abstractions/notification-bar"; import { AtRiskNotification, AtRiskNotificationProps, @@ -10,19 +9,15 @@ import { import { mockI18n, mockBrowserI18nGetMessage } from "../../mock-data"; export default { - title: "Components/Notifications/AtRiskNotification", + title: "Components/Notifications/At-Risk Notification", argTypes: { - error: { control: "text" }, theme: { control: "select", options: [...Object.values(ThemeTypes)] }, - type: { control: "select", options: [NotificationTypes.AtRiskPassword] }, }, args: { - error: "", - type: NotificationTypes.AtRiskPassword, theme: ThemeTypes.Light, handleCloseNotification: () => alert("Close notification action triggered"), params: { - passwordChangeUri: "https://webtests.dev", // Remove to see "navigate" version of notification + passwordChangeUri: "webtests.dev", // Remove to see "navigate" version of notification organizationName: "Acme Co.", }, i18n: mockI18n, diff --git a/apps/browser/src/autofill/content/components/notification/at-risk-password/body.ts b/apps/browser/src/autofill/content/components/notification/at-risk-password/body.ts index 062a7e50c1a..3cc08a26210 100644 --- a/apps/browser/src/autofill/content/components/notification/at-risk-password/body.ts +++ b/apps/browser/src/autofill/content/components/notification/at-risk-password/body.ts @@ -1,40 +1,49 @@ +import createEmotion from "@emotion/css/create-instance"; import { html, nothing } from "lit"; import { Theme } from "@bitwarden/common/platform/enums"; +import { spacing, themes } from "../../constants/styles"; import { Warning } from "../../illustrations"; -import { iconContainerStyles, notificationConfirmationBodyStyles } from "../confirmation/body"; import { AtRiskNotificationMessage } from "./message"; -export const componentClassPrefix = "notification-confirmation-body"; +export const componentClassPrefix = "at-risk-notification-body"; + +const { css } = createEmotion({ + key: componentClassPrefix, +}); export type AtRiskNotificationBodyProps = { - confirmationMessage: string; - messageDetails?: string; + riskMessage: string; theme: Theme; - handleOpenVault: (e: Event) => void; }; -export function AtRiskNotificationBody({ - confirmationMessage, - messageDetails, - theme, - handleOpenVault, -}: AtRiskNotificationBodyProps) { - const showConfirmationMessage = confirmationMessage || messageDetails; - +export function AtRiskNotificationBody({ riskMessage, theme }: AtRiskNotificationBodyProps) { return html` -
-
${Warning()}
- ${showConfirmationMessage +
+
${Warning()}
+ ${riskMessage ? AtRiskNotificationMessage({ - message: confirmationMessage, - messageDetails, + message: riskMessage, theme, - handleClick: handleOpenVault, }) : nothing}
`; } + +const iconContainerStyles = css` + > svg { + width: 50px; + height: auto; + } +`; +const atRiskNotificationBodyStyles = ({ theme }: { theme: Theme }) => css` + gap: ${spacing[4]}; + display: flex; + align-items: center; + justify-content: flex-start; + background-color: ${themes[theme].background.alt}; + padding: 12px; +`; diff --git a/apps/browser/src/autofill/content/components/notification/at-risk-password/container.ts b/apps/browser/src/autofill/content/components/notification/at-risk-password/container.ts index 64382bb4653..90da0833fd9 100644 --- a/apps/browser/src/autofill/content/components/notification/at-risk-password/container.ts +++ b/apps/browser/src/autofill/content/components/notification/at-risk-password/container.ts @@ -1,16 +1,15 @@ +import { css } from "@emotion/css"; import { html, nothing } from "lit"; -import { ThemeTypes } from "@bitwarden/common/platform/enums"; +import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums"; -import { - AtRiskPasswordNotificationParams, - NotificationBarIframeInitData, - NotificationType, - NotificationTypes, -} from "../../../../notification/abstractions/notification-bar"; +import { NotificationBarIframeInitData } from "../../../../notification/abstractions/notification-bar"; import { I18n } from "../../common-types"; -import { notificationContainerStyles } from "../confirmation/container"; -import { NotificationHeader } from "../header"; +import { themes, spacing } from "../../constants/styles"; +import { + NotificationHeader, + componentClassPrefix as notificationHeaderClassPrefix, +} from "../header"; import { AtRiskNotificationBody } from "./body"; import { AtRiskNotificationFooter } from "./footer"; @@ -18,37 +17,32 @@ import { AtRiskNotificationFooter } from "./footer"; export type AtRiskNotificationProps = NotificationBarIframeInitData & { handleCloseNotification: (e: Event) => void; } & { - error?: string; i18n: I18n; - type: NotificationType; - params: AtRiskPasswordNotificationParams; }; export function AtRiskNotification({ handleCloseNotification, i18n, theme = ThemeTypes.Light, - type, params, }: AtRiskNotificationProps) { - const headerMessage = getHeaderMessage(i18n, type); const { passwordChangeUri, organizationName } = params; + const riskMessage = chrome.i18n.getMessage( + passwordChangeUri ? "atRiskChangePrompt" : "atRiskNavigatePrompt", + organizationName, + ); return html` -
+
${NotificationHeader({ handleCloseNotification, i18n, - message: headerMessage, + message: i18n.atRiskPassword, theme, })} ${AtRiskNotificationBody({ theme, - handleOpenVault: () => {}, - confirmationMessage: chrome.i18n.getMessage( - passwordChangeUri ? "atRiskChangePrompt" : "atRiskNavigatePrompt", - organizationName, - ), + riskMessage, })} ${passwordChangeUri ? AtRiskNotificationFooter({ @@ -61,6 +55,18 @@ export function AtRiskNotification({ `; } -function getHeaderMessage(i18n: I18n, type?: NotificationType) { - return type === NotificationTypes.AtRiskPassword ? i18n.atRiskPassword : undefined; -} +const atRiskNotificationContainerStyles = (theme: Theme) => css` + position: absolute; + right: 20px; + border: 1px solid ${themes[theme].secondary["300"]}; + border-radius: ${spacing["4"]}; + box-shadow: -2px 4px 6px 0px #0000001a; + background-color: ${themes[theme].background.alt}; + width: 400px; + overflow: hidden; + + [class*="${notificationHeaderClassPrefix}-"] { + border-radius: ${spacing["4"]} ${spacing["4"]} 0 0; + border-bottom: 0.5px solid ${themes[theme].secondary["300"]}; + } +`; diff --git a/apps/browser/src/autofill/content/components/notification/at-risk-password/footer.ts b/apps/browser/src/autofill/content/components/notification/at-risk-password/footer.ts index 30b7567a48b..31a9f62f257 100644 --- a/apps/browser/src/autofill/content/components/notification/at-risk-password/footer.ts +++ b/apps/browser/src/autofill/content/components/notification/at-risk-password/footer.ts @@ -1,3 +1,4 @@ +import { css } from "@emotion/css"; import { html } from "lit"; import { Theme } from "@bitwarden/common/platform/enums"; @@ -5,8 +6,7 @@ import { Theme } from "@bitwarden/common/platform/enums"; import { ActionButton } from "../../buttons/action-button"; import { AdditionalTasksButtonContent } from "../../buttons/additional-tasks/button-content"; import { I18n } from "../../common-types"; -// Utilizes default notification styles, not confirmation. -import { notificationFooterStyles } from "../footer"; +import { spacing } from "../../constants/styles"; export type AtRiskNotificationFooterProps = { i18n: I18n; @@ -19,7 +19,7 @@ export function AtRiskNotificationFooter({ theme, passwordChangeUri, }: AtRiskNotificationFooterProps) { - return html`
+ return html`
${passwordChangeUri && ActionButton({ handleClick: () => { @@ -31,3 +31,12 @@ export function AtRiskNotificationFooter({ })}
`; } + +const atRiskNotificationFooterStyles = css` + display: flex; + padding: ${spacing[2]} ${spacing[4]} ${spacing[4]} ${spacing[4]}; + + :last-child { + border-radius: 0 0 ${spacing["4"]} ${spacing["4"]}; + } +`; diff --git a/apps/browser/src/autofill/content/components/notification/at-risk-password/message.ts b/apps/browser/src/autofill/content/components/notification/at-risk-password/message.ts index e3c9e2a3af5..42d4907711d 100644 --- a/apps/browser/src/autofill/content/components/notification/at-risk-password/message.ts +++ b/apps/browser/src/autofill/content/components/notification/at-risk-password/message.ts @@ -1,68 +1,44 @@ +import { css } from "@emotion/css"; import { html, nothing } from "lit"; import { Theme } from "@bitwarden/common/platform/enums"; -import { - AdditionalMessageStyles, - notificationConfirmationButtonTextStyles, - notificationConfirmationMessageStyles, -} from "../confirmation/message"; +import { themes } from "../../constants/styles"; export type AtRiskNotificationMessageProps = { - buttonAria?: string; - buttonText?: string; - itemName?: string; message?: string; - messageDetails?: string; - handleClick: (e: Event) => void; theme: Theme; }; -export function AtRiskNotificationMessage({ - buttonAria, - buttonText, - message, - messageDetails, - handleClick, - theme, -}: AtRiskNotificationMessageProps) { +export function AtRiskNotificationMessage({ message, theme }: AtRiskNotificationMessageProps) { return html`
- ${message || buttonText + ${message ? html` - - ${message || nothing} - ${buttonText - ? html` - handleButtonKeyDown(e, () => handleClick(e))} - aria-label=${buttonAria} - tabindex="0" - role="button" - > - ${buttonText} - - ` - : nothing} + + ${message} ` : nothing} - ${messageDetails - ? html`
${messageDetails}
` - : nothing}
`; } -function handleButtonKeyDown(event: KeyboardEvent, handleClick: () => void) { - if (event.key === "Enter" || event.key === " ") { - event.preventDefault(); - handleClick(); - } -} +const baseTextStyles = css` + overflow-x: hidden; + text-align: left; + text-overflow: ellipsis; + line-height: 24px; + font-family: Roboto, sans-serif; + font-size: 16px; +`; + +const atRiskNotificationMessageStyles = (theme: Theme) => css` + ${baseTextStyles} + + color: ${themes[theme].text.main}; + font-weight: 400; + white-space: normal; + word-break: break-word; + display: inline; +`; diff --git a/apps/browser/src/autofill/content/components/notification/confirmation/body.ts b/apps/browser/src/autofill/content/components/notification/confirmation/body.ts index f72099007e5..6bb94cab2c6 100644 --- a/apps/browser/src/autofill/content/components/notification/confirmation/body.ts +++ b/apps/browser/src/autofill/content/components/notification/confirmation/body.ts @@ -59,13 +59,13 @@ export function NotificationConfirmationBody({ `; } -export const iconContainerStyles = (error?: string | boolean) => css` +const iconContainerStyles = (error?: string) => css` > svg { width: ${!error ? "50px" : "40px"}; height: auto; } `; -export const notificationConfirmationBodyStyles = ({ theme }: { theme: Theme }) => css` +const notificationConfirmationBodyStyles = ({ theme }: { theme: Theme }) => css` gap: ${spacing[4]}; display: flex; align-items: center; 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 a02e4d69330..dabb21e7d17 100644 --- a/apps/browser/src/autofill/content/components/notification/confirmation/container.ts +++ b/apps/browser/src/autofill/content/components/notification/confirmation/container.ts @@ -96,7 +96,7 @@ export function NotificationConfirmationContainer({ `; } -export const notificationContainerStyles = (theme: Theme) => css` +const notificationContainerStyles = (theme: Theme) => css` position: absolute; right: 20px; border: 1px solid ${themes[theme].secondary["300"]}; diff --git a/apps/browser/src/autofill/content/components/notification/confirmation/footer.ts b/apps/browser/src/autofill/content/components/notification/confirmation/footer.ts index bd2e9480d56..ba01efe5a53 100644 --- a/apps/browser/src/autofill/content/components/notification/confirmation/footer.ts +++ b/apps/browser/src/autofill/content/components/notification/confirmation/footer.ts @@ -22,7 +22,7 @@ export function NotificationConfirmationFooter({ const primaryButtonText = i18n.nextSecurityTaskAction; return html` -
+
${ActionButton({ handleClick: handleButtonClick, buttonText: AdditionalTasksButtonContent({ buttonText: primaryButtonText, theme }), @@ -32,13 +32,10 @@ export function NotificationConfirmationFooter({ `; } -const maxWidthMinContent = css` - max-width: min-content; -`; - const notificationConfirmationFooterStyles = ({ theme }: { theme: Theme }) => css` background-color: ${themes[theme].background.alt}; padding: 0 ${spacing[3]} ${spacing[3]} ${spacing[3]}; + max-width: min-content; :last-child { border-radius: 0 0 ${spacing["4"]} ${spacing["4"]}; diff --git a/apps/browser/src/autofill/content/components/notification/confirmation/message.ts b/apps/browser/src/autofill/content/components/notification/confirmation/message.ts index 687c563148b..7f15d882297 100644 --- a/apps/browser/src/autofill/content/components/notification/confirmation/message.ts +++ b/apps/browser/src/autofill/content/components/notification/confirmation/message.ts @@ -88,7 +88,7 @@ const baseTextStyles = css` font-size: 16px; `; -export const notificationConfirmationMessageStyles = (theme: Theme) => css` +const notificationConfirmationMessageStyles = (theme: Theme) => css` ${baseTextStyles} color: ${themes[theme].text.main}; @@ -111,7 +111,7 @@ const itemNameStyles = (theme: Theme) => css` vertical-align: bottom; `; -export const notificationConfirmationButtonTextStyles = (theme: Theme) => css` +const notificationConfirmationButtonTextStyles = (theme: Theme) => css` ${baseTextStyles} color: ${themes[theme].primary[600]}; @@ -119,7 +119,7 @@ export const notificationConfirmationButtonTextStyles = (theme: Theme) => css` cursor: pointer; `; -export const AdditionalMessageStyles = ({ theme }: { theme: Theme }) => css` +const AdditionalMessageStyles = ({ theme }: { theme: Theme }) => css` ${typography.body2} font-size: 14px; diff --git a/apps/browser/src/autofill/content/components/notification/footer.ts b/apps/browser/src/autofill/content/components/notification/footer.ts index 071f2579543..b47dd5cc094 100644 --- a/apps/browser/src/autofill/content/components/notification/footer.ts +++ b/apps/browser/src/autofill/content/components/notification/footer.ts @@ -21,7 +21,6 @@ export type NotificationFooterProps = { personalVaultIsAllowed: boolean; theme: Theme; handleSaveAction: (e: Event) => void; - passwordChangeUri?: string; }; export function NotificationFooter({ @@ -44,7 +43,7 @@ export function NotificationFooter({ } return html` -
+
${!isChangeNotification ? NotificationButtonRow({ collections, @@ -63,15 +62,12 @@ export function NotificationFooter({ `; } -export const displayFlex = css` - display: flex; -`; - -export const notificationFooterStyles = ({ +const notificationFooterStyles = ({ isChangeNotification, }: { isChangeNotification: boolean; }) => css` + display: flex; padding: ${spacing[2]} ${spacing[4]} ${isChangeNotification ? spacing[1] : spacing[4]} ${spacing[4]};