From 0f0f8c6ba21d4534a1fc1a70191d25bc8d10315d Mon Sep 17 00:00:00 2001 From: Zack Date: Mon, 15 Jun 2026 12:20:27 +0200 Subject: [PATCH] Refactor UnreadNotificationBadge to shared MVVM view (#33672) * Refactor notification badge to shared MVVM view * Bage icons Images * Narrow unread notification badge refactor scope * Align unread badge MVVM pattern * Reduce unread badge viewmodel duplication * Document unread badge viewmodel props * Remove legacy badge classes from shared view * Update css for knocked door * Update thread badge e2e selector * Update read receipt badge e2e selectors --- .../web/playwright/e2e/read-receipts/index.ts | 4 +- .../playwright/e2e/threads/threads.spec.ts | 4 +- .../UnreadNotificationBadge.tsx | 29 ++- .../UnreadNotificationBadgeViewModel.ts | 184 ++++++++++++++++++ .../components/views/rooms/EventTile-test.tsx | 14 +- .../UnreadNotificationBadge-test.tsx | 26 +-- .../UnreadNotificationBadgeViewModel-test.ts | 117 +++++++++++ .../dot-auto.png | Bin 0 -> 16663 bytes .../hidden-auto.png | Bin 0 -> 16380 bytes .../highlight-auto.png | Bin 0 -> 16982 bytes .../knocked-auto.png | Bin 0 -> 17219 bytes .../notification-auto.png | Bin 0 -> 17081 bytes packages/shared-components/src/index.ts | 1 + .../NotificationBadgeView.module.css | 62 ++++++ .../NotificationBadgeView.stories.tsx | 72 +++++++ .../NotificationBadgeView.test.tsx | 41 ++++ .../NotificationBadgeView.tsx | 95 +++++++++ .../NotificationBadgeView.test.tsx.snap | 17 ++ .../NotificationBadgeView/index.tsx | 13 ++ 19 files changed, 655 insertions(+), 24 deletions(-) create mode 100644 apps/web/src/viewmodels/room/notification-badge/UnreadNotificationBadgeViewModel.ts create mode 100644 apps/web/test/viewmodels/room/notification-badge/UnreadNotificationBadgeViewModel-test.ts create mode 100644 packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/dot-auto.png create mode 100644 packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/hidden-auto.png create mode 100644 packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/highlight-auto.png create mode 100644 packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/knocked-auto.png create mode 100644 packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/notification-auto.png create mode 100644 packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.module.css create mode 100644 packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx create mode 100644 packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.test.tsx create mode 100644 packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.tsx create mode 100644 packages/shared-components/src/notifications/NotificationBadgeView/__snapshots__/NotificationBadgeView.test.tsx.snap create mode 100644 packages/shared-components/src/notifications/NotificationBadgeView/index.tsx diff --git a/apps/web/playwright/e2e/read-receipts/index.ts b/apps/web/playwright/e2e/read-receipts/index.ts index bd04be36a8..6ff5789795 100644 --- a/apps/web/playwright/e2e/read-receipts/index.ts +++ b/apps/web/playwright/e2e/read-receipts/index.ts @@ -557,7 +557,7 @@ class Helpers { */ async assertReadThread(rootMessage: string) { const tile = await this.getThreadListTile(rootMessage); - await expect(tile.locator(".mx_NotificationBadge")).not.toBeVisible(); + await expect(tile.getByTestId("notification-badge")).not.toBeVisible(); } /** @@ -566,7 +566,7 @@ class Helpers { */ async assertUnreadThread(rootMessage: string) { const tile = await this.getThreadListTile(rootMessage); - await expect(tile.locator(".mx_NotificationBadge")).toBeVisible(); + await expect(tile.getByTestId("notification-badge")).toBeVisible(); } /** diff --git a/apps/web/playwright/e2e/threads/threads.spec.ts b/apps/web/playwright/e2e/threads/threads.spec.ts index b143c4a83a..1ace1c4499 100644 --- a/apps/web/playwright/e2e/threads/threads.spec.ts +++ b/apps/web/playwright/e2e/threads/threads.spec.ts @@ -269,7 +269,9 @@ test.describe("Threads", () => { // Check the number of the replies await expect(locator.locator(".mx_ThreadPanel_replies_amount").getByText("2")).toBeAttached(); // Make sure the notification dot is visible - await expect(locator.locator(".mx_NotificationBadge_visible")).toBeVisible(); + const notificationBadge = locator.getByTestId("notification-badge"); + await expect(notificationBadge).toBeVisible(); + await expect(notificationBadge).toHaveAttribute("data-badge-type", "dot"); // User opens thread via threads list await locator.locator(".mx_EventTile_line").click(); diff --git a/apps/web/src/components/views/rooms/NotificationBadge/UnreadNotificationBadge.tsx b/apps/web/src/components/views/rooms/NotificationBadge/UnreadNotificationBadge.tsx index 0677278054..8e3912bf1c 100644 --- a/apps/web/src/components/views/rooms/NotificationBadge/UnreadNotificationBadge.tsx +++ b/apps/web/src/components/views/rooms/NotificationBadge/UnreadNotificationBadge.tsx @@ -7,10 +7,10 @@ Please see LICENSE files in the repository root for full details. */ import { type Room } from "matrix-js-sdk/src/matrix"; -import React, { type JSX } from "react"; +import React, { type JSX, useEffect } from "react"; +import { NotificationBadgeView, useCreateAutoDisposedViewModel } from "@element-hq/web-shared-components"; -import { useUnreadNotifications } from "../../../../hooks/useUnreadNotifications"; -import { StatelessNotificationBadge } from "./StatelessNotificationBadge"; +import { UnreadNotificationBadgeViewModel } from "../../../../viewmodels/room/notification-badge/UnreadNotificationBadgeViewModel"; interface Props { room?: Room; @@ -23,7 +23,26 @@ interface Props { } export function UnreadNotificationBadge({ room, threadId, forceDot }: Props): JSX.Element { - const { symbol, count, level } = useUnreadNotifications(room, threadId); + const vm = useCreateAutoDisposedViewModel( + () => + new UnreadNotificationBadgeViewModel({ + room, + threadId, + forceDot, + }), + ); - return ; + useEffect(() => { + vm.setRoom(room); + }, [room, vm]); + + useEffect(() => { + vm.setThreadId(threadId); + }, [threadId, vm]); + + useEffect(() => { + vm.setForceDot(forceDot); + }, [forceDot, vm]); + + return ; } diff --git a/apps/web/src/viewmodels/room/notification-badge/UnreadNotificationBadgeViewModel.ts b/apps/web/src/viewmodels/room/notification-badge/UnreadNotificationBadgeViewModel.ts new file mode 100644 index 0000000000..bc02f3e1eb --- /dev/null +++ b/apps/web/src/viewmodels/room/notification-badge/UnreadNotificationBadgeViewModel.ts @@ -0,0 +1,184 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import { type NotificationCount, type Room, RoomEvent } from "matrix-js-sdk/src/matrix"; +import { + BaseViewModel, + type NotificationBadgeType, + type NotificationBadgeViewSnapshot, + type NotificationBadgeViewModel as NotificationBadgeViewModelInterface, +} from "@element-hq/web-shared-components"; + +import { determineUnreadState } from "../../../RoomNotifs"; +import { NotificationLevel } from "../../../stores/notifications/NotificationLevel"; +import SettingsStore from "../../../settings/SettingsStore"; +import { formatCount } from "../../../utils/FormattingUtils"; + +const notificationChangeEvents = [ + RoomEvent.Receipt, + RoomEvent.Timeline, + RoomEvent.Redaction, + RoomEvent.LocalEchoUpdated, + RoomEvent.MyMembership, +]; + +function getBadgeType(level: NotificationLevel, symbol: string | null, forceDot?: boolean): NotificationBadgeType { + if (forceDot || level <= NotificationLevel.Activity) { + return "dot"; + } + + return symbol && symbol.length >= 3 ? "badge_3char" : "badge_2char"; +} + +export interface UnreadNotificationBadgeViewModelProps { + /** + * Room whose unread state should be represented by the badge. + */ + room?: Room; + /** + * Thread to read unread state from. Omit for room-level unread state. + */ + threadId?: string; + /** + * Show a dot instead of a numeric/symbol badge whenever the badge would otherwise render. + */ + forceDot?: boolean; +} + +interface InternalProps extends UnreadNotificationBadgeViewModelProps { + hideBold: boolean; +} + +export class UnreadNotificationBadgeViewModel + extends BaseViewModel + implements NotificationBadgeViewModelInterface +{ + private listenerCleanups: Array<() => void> = []; + + private static readonly computeSnapshot = (props: InternalProps): NotificationBadgeViewSnapshot => { + const { symbol, count, level } = determineUnreadState(props.room, props.threadId, false); + const displaySymbol = symbol ?? (count > 0 ? formatCount(count) : null); + const hasUnreadCount = level >= NotificationLevel.Notification && (count > 0 || symbol !== null); + const isSuppressedActivity = props.hideBold && level === NotificationLevel.Activity; + + return { + shouldRender: level !== NotificationLevel.None && !isSuppressedActivity, + isVisible: symbol === null && count === 0 ? true : hasUnreadCount, + isNotification: level === NotificationLevel.Notification, + isHighlight: level >= NotificationLevel.Highlight, + isKnocked: false, + badgeType: getBadgeType(level, displaySymbol, props.forceDot), + symbol: displaySymbol, + }; + }; + + public constructor(props: UnreadNotificationBadgeViewModelProps) { + const internalProps: InternalProps = { + ...props, + hideBold: SettingsStore.getValue("feature_hidebold"), + }; + + super(internalProps, UnreadNotificationBadgeViewModel.computeSnapshot(internalProps)); + + this.setupListeners(); + + const hideBoldWatcherRef = SettingsStore.watchSetting("feature_hidebold", null, this.onHideBoldSettingChanged); + this.disposables.track(() => SettingsStore.unwatchSetting(hideBoldWatcherRef)); + } + + public dispose(): void { + this.teardownListeners(); + super.dispose(); + } + + public setRoom(room?: Room): void { + if (this.props.room === room) return; + + this.props = { + ...this.props, + room, + }; + this.setupListeners(); + this.updateSnapshotFromProps(); + } + + public setThreadId(threadId?: string): void { + if (this.props.threadId === threadId) return; + + this.props = { + ...this.props, + threadId, + }; + this.updateSnapshotFromProps(); + } + + public setForceDot(forceDot?: boolean): void { + if (this.props.forceDot === forceDot) return; + + this.props = { + ...this.props, + forceDot, + }; + this.updateSnapshotFromProps(); + } + + private setHideBold(hideBold: boolean): void { + if (this.props.hideBold === hideBold) return; + + this.props = { + ...this.props, + hideBold, + }; + this.updateSnapshotFromProps(); + } + + private updateSnapshotFromProps(): void { + this.snapshot.merge(UnreadNotificationBadgeViewModel.computeSnapshot(this.props)); + } + + private setupListeners(): void { + this.teardownListeners(); + + const { room } = this.props; + if (!room) return; + + room.on(RoomEvent.UnreadNotifications, this.onRoomUnreadNotifications); + for (const eventName of notificationChangeEvents) { + room.on(eventName, this.onNotificationChanged); + } + + this.listenerCleanups.push(() => { + room.off(RoomEvent.UnreadNotifications, this.onRoomUnreadNotifications); + for (const eventName of notificationChangeEvents) { + room.off(eventName, this.onNotificationChanged); + } + }); + } + + private teardownListeners(): void { + for (const cleanup of this.listenerCleanups) { + cleanup(); + } + this.listenerCleanups = []; + } + + private readonly onRoomUnreadNotifications = ( + _unreadNotifications?: NotificationCount, + evtThreadId?: string, + ): void => { + if (this.props.threadId && this.props.threadId !== evtThreadId) return; + this.updateSnapshotFromProps(); + }; + + private readonly onNotificationChanged = (): void => { + this.updateSnapshotFromProps(); + }; + + private readonly onHideBoldSettingChanged = (): void => { + this.setHideBold(SettingsStore.getValue("feature_hidebold")); + }; +} diff --git a/apps/web/test/unit-tests/components/views/rooms/EventTile-test.tsx b/apps/web/test/unit-tests/components/views/rooms/EventTile-test.tsx index 4677b6bdea..f7ea551ecd 100644 --- a/apps/web/test/unit-tests/components/views/rooms/EventTile-test.tsx +++ b/apps/web/test/unit-tests/components/views/rooms/EventTile-test.tsx @@ -1007,21 +1007,25 @@ describe("EventTile", () => { const { container } = getComponent({}, TimelineRenderingType.ThreadsList); // By default, the thread will assume it is read. - expect(container.getElementsByClassName("mx_NotificationBadge")).toHaveLength(0); + expect(container.querySelectorAll('[data-testid="notification-badge"]')).toHaveLength(0); act(() => { room.setThreadUnreadNotificationCount(mxEvent.getId()!, NotificationCountType.Total, 3); }); - expect(container.getElementsByClassName("mx_NotificationBadge")).toHaveLength(1); - expect(container.getElementsByClassName("mx_NotificationBadge_level_highlight")).toHaveLength(0); + let badges = container.querySelectorAll('[data-testid="notification-badge"]'); + expect(badges).toHaveLength(1); + expect(badges[0]).toHaveAttribute("data-badge-type", "dot"); + expect(badges[0]).toHaveAttribute("data-notification-level", "notification"); act(() => { room.setThreadUnreadNotificationCount(mxEvent.getId()!, NotificationCountType.Highlight, 1); }); - expect(container.getElementsByClassName("mx_NotificationBadge")).toHaveLength(1); - expect(container.getElementsByClassName("mx_NotificationBadge_level_highlight")).toHaveLength(1); + badges = container.querySelectorAll('[data-testid="notification-badge"]'); + expect(badges).toHaveLength(1); + expect(badges[0]).toHaveAttribute("data-badge-type", "dot"); + expect(badges[0]).toHaveAttribute("data-notification-level", "highlight"); }); }); diff --git a/apps/web/test/unit-tests/components/views/rooms/NotificationBadge/UnreadNotificationBadge-test.tsx b/apps/web/test/unit-tests/components/views/rooms/NotificationBadge/UnreadNotificationBadge-test.tsx index 6628889dc7..b1e9a2835c 100644 --- a/apps/web/test/unit-tests/components/views/rooms/NotificationBadge/UnreadNotificationBadge-test.tsx +++ b/apps/web/test/unit-tests/components/views/rooms/NotificationBadge/UnreadNotificationBadge-test.tsx @@ -38,6 +38,10 @@ describe("UnreadNotificationBadge", () => { return ; } + function getBadge(container: HTMLElement): Element | null { + return container.querySelector('[data-testid="notification-badge"]'); + } + beforeEach(() => { client = stubClient(); client.supportsThreads = () => true; @@ -84,27 +88,27 @@ describe("UnreadNotificationBadge", () => { it("renders unread notification badge", () => { const { container } = render(getComponent()); - expect(container.querySelector(".mx_NotificationBadge_visible")).toBeTruthy(); - expect(container.querySelector(".mx_NotificationBadge_level_highlight")).toBeFalsy(); + expect(getBadge(container)).toHaveTextContent("1"); + expect(getBadge(container)).toHaveAttribute("data-notification-level", "notification"); act(() => { room.setUnreadNotificationCount(NotificationCountType.Highlight, 1); }); - expect(container.querySelector(".mx_NotificationBadge_level_highlight")).toBeTruthy(); + expect(getBadge(container)).toHaveAttribute("data-notification-level", "highlight"); }); it("renders unread thread notification badge", () => { const { container } = render(getComponent(THREAD_ID)); - expect(container.querySelector(".mx_NotificationBadge_visible")).toBeTruthy(); - expect(container.querySelector(".mx_NotificationBadge_level_highlight")).toBeFalsy(); + expect(getBadge(container)).toHaveTextContent("1"); + expect(getBadge(container)).toHaveAttribute("data-notification-level", "notification"); act(() => { room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Highlight, 1); }); - expect(container.querySelector(".mx_NotificationBadge_level_highlight")).toBeTruthy(); + expect(getBadge(container)).toHaveAttribute("data-notification-level", "highlight"); }); it("hides unread notification badge", () => { @@ -112,7 +116,7 @@ describe("UnreadNotificationBadge", () => { room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Total, 0); room.setThreadUnreadNotificationCount(THREAD_ID, NotificationCountType.Highlight, 0); const { container } = render(getComponent(THREAD_ID)); - expect(container.querySelector(".mx_NotificationBadge_visible")).toBeFalsy(); + expect(getBadge(container)).toBeNull(); }); }); @@ -142,7 +146,7 @@ describe("UnreadNotificationBadge", () => { muteRoom(room); const { container } = render(getComponent()); - expect(container.querySelector(".mx_NotificationBadge")).toBeNull(); + expect(getBadge(container)).toBeNull(); }); it("activity renders unread notification badge", () => { @@ -168,8 +172,8 @@ describe("UnreadNotificationBadge", () => { room.addLiveEvents([event], { addToState: true }); const { container } = render(getComponent(THREAD_ID)); - expect(container.querySelector(".mx_NotificationBadge_dot")).toBeTruthy(); - expect(container.querySelector(".mx_NotificationBadge_visible")).toBeTruthy(); - expect(container.querySelector(".mx_NotificationBadge_level_highlight")).toBeFalsy(); + expect(getBadge(container)).toBeInTheDocument(); + expect(getBadge(container)).toHaveAttribute("data-badge-type", "dot"); + expect(getBadge(container)).not.toHaveAttribute("data-notification-level", "highlight"); }); }); diff --git a/apps/web/test/viewmodels/room/notification-badge/UnreadNotificationBadgeViewModel-test.ts b/apps/web/test/viewmodels/room/notification-badge/UnreadNotificationBadgeViewModel-test.ts new file mode 100644 index 0000000000..05b3497cad --- /dev/null +++ b/apps/web/test/viewmodels/room/notification-badge/UnreadNotificationBadgeViewModel-test.ts @@ -0,0 +1,117 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import { NotificationCountType, PendingEventOrdering, Room, RoomEvent } from "matrix-js-sdk/src/matrix"; + +import type { MatrixClient } from "matrix-js-sdk/src/matrix"; +import { stubClient } from "../../../test-utils/test-utils"; +import { UnreadNotificationBadgeViewModel } from "../../../../src/viewmodels/room/notification-badge/UnreadNotificationBadgeViewModel"; + +describe("UnreadNotificationBadgeViewModel", () => { + let client: MatrixClient; + let room: Room; + const trackedRoomEvents = [ + RoomEvent.UnreadNotifications, + RoomEvent.Receipt, + RoomEvent.Timeline, + RoomEvent.Redaction, + RoomEvent.LocalEchoUpdated, + RoomEvent.MyMembership, + ]; + + beforeEach(() => { + client = stubClient(); + room = new Room("!room:example.org", client, "@user:example.org", { + pendingEventOrdering: PendingEventOrdering.Detached, + }); + }); + + function setUnreads(greys: number, reds: number): void { + room.setUnreadNotificationCount(NotificationCountType.Total, greys); + room.setUnreadNotificationCount(NotificationCountType.Highlight, reds); + } + + it("computes the initial snapshot from unread state", () => { + setUnreads(12, 0); + + const vm = new UnreadNotificationBadgeViewModel({ room }); + + expect(vm.getSnapshot()).toMatchObject({ + shouldRender: true, + isVisible: true, + isNotification: true, + isHighlight: false, + badgeType: "badge_2char", + symbol: "12", + }); + + vm.dispose(); + }); + + it("updates when the room unread state changes", () => { + const vm = new UnreadNotificationBadgeViewModel({ room }); + const listener = jest.fn(); + vm.subscribe(listener); + + setUnreads(0, 2); + + expect(vm.getSnapshot()).toMatchObject({ + isHighlight: true, + symbol: "2", + }); + expect(listener).toHaveBeenCalled(); + + vm.dispose(); + }); + + it("skips unchanged force-dot setter updates", () => { + setUnreads(1, 0); + const vm = new UnreadNotificationBadgeViewModel({ room, forceDot: false }); + const listener = jest.fn(); + vm.subscribe(listener); + + vm.setForceDot(false); + + expect(listener).not.toHaveBeenCalled(); + + vm.setForceDot(true); + + expect(listener).toHaveBeenCalledTimes(1); + expect(vm.getSnapshot().badgeType).toBe("dot"); + + vm.dispose(); + }); + + it("moves room event listeners when the room changes", () => { + const nextRoom = new Room("!next:example.org", client, "@user:example.org", { + pendingEventOrdering: PendingEventOrdering.Detached, + }); + const initialRoomListenerCounts = new Map( + trackedRoomEvents.map((eventName) => [eventName, room.listenerCount(eventName)]), + ); + const initialNextRoomListenerCounts = new Map( + trackedRoomEvents.map((eventName) => [eventName, nextRoom.listenerCount(eventName)]), + ); + const vm = new UnreadNotificationBadgeViewModel({ room }); + + for (const eventName of trackedRoomEvents) { + expect(room.listenerCount(eventName)).toBe(initialRoomListenerCounts.get(eventName)! + 1); + } + + vm.setRoom(nextRoom); + + for (const eventName of trackedRoomEvents) { + expect(room.listenerCount(eventName)).toBe(initialRoomListenerCounts.get(eventName)); + expect(nextRoom.listenerCount(eventName)).toBe(initialNextRoomListenerCounts.get(eventName)! + 1); + } + + vm.dispose(); + for (const eventName of trackedRoomEvents) { + expect(nextRoom.listenerCount(eventName)).toBe(initialNextRoomListenerCounts.get(eventName)); + } + }); +}); diff --git a/packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/dot-auto.png b/packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/dot-auto.png new file mode 100644 index 0000000000000000000000000000000000000000..d00dcb7348fe3285ad79658979a83cbe24fe45e3 GIT binary patch literal 16663 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 C``2s$ literal 0 HcmV?d00001 diff --git a/packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/hidden-auto.png b/packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/hidden-auto.png new file mode 100644 index 0000000000000000000000000000000000000000..17fe39394f561638fc5cf269603be3fafcbe35cd GIT binary patch literal 16380 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 Ro_InG>>t)Ir>}X@{{cu8Y-#`i literal 0 HcmV?d00001 diff --git a/packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/highlight-auto.png b/packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/highlight-auto.png new file mode 100644 index 0000000000000000000000000000000000000000..4182c6511afa45bff0b5172bd13e272f3b7c9eb8 GIT binary patch literal 16982 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 literal 0 HcmV?d00001 diff --git a/packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/knocked-auto.png b/packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/knocked-auto.png new file mode 100644 index 0000000000000000000000000000000000000000..d8b0b93f7e39afa1ecd3badad0c873594821892f GIT binary patch literal 17219 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 NO!S_R{j+NQ{{#7{BYXe= literal 0 HcmV?d00001 diff --git a/packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/notification-auto.png b/packages/shared-components/__vis__/linux/__baselines__/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx/notification-auto.png new file mode 100644 index 0000000000000000000000000000000000000000..7aa23cf6388121f7a47cae4ddf65d085a3d63eb7 GIT binary patch literal 17081 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 svg { + width: 16px; + height: 16px; +} + +.notificationBadge.visible.badge2Char { + width: 1rem; + height: 1rem; + border-radius: 1rem; +} + +.notificationBadge.visible.badge3Char { + width: 1.625rem; + height: 1rem; + border-radius: 1rem; +} + +.notificationBadge.visible .count { + font-size: 0.625rem; + line-height: 0.875rem; + font-weight: var(--cpd-font-weight-semibold); + color: var(--cpd-color-text-on-solid-primary); +} diff --git a/packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx b/packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx new file mode 100644 index 0000000000..44a87dfe3a --- /dev/null +++ b/packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.stories.tsx @@ -0,0 +1,72 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import React, { type JSX } from "react"; + +import type { Meta, StoryObj } from "@storybook/react-vite"; +import { useMockedViewModel } from "../../core/viewmodel"; +import { withViewDocs } from "../../../.storybook/withViewDocs"; +import { NotificationBadgeView, type NotificationBadgeViewSnapshot } from "./NotificationBadgeView"; + +type WrapperProps = NotificationBadgeViewSnapshot; + +const NotificationBadgeViewWrapperImpl = ({ ...snapshotProps }: WrapperProps): JSX.Element => { + const vm = useMockedViewModel(snapshotProps, {}); + + return ; +}; + +const NotificationBadgeViewWrapper = withViewDocs(NotificationBadgeViewWrapperImpl, NotificationBadgeView); + +const meta = { + title: "Notifications/NotificationBadgeView", + component: NotificationBadgeViewWrapper, + tags: ["autodocs"], + args: { + shouldRender: true, + isVisible: true, + isNotification: false, + isHighlight: false, + isKnocked: false, + badgeType: "badge_2char", + symbol: "3", + knockLabel: "Request to join sent", + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Notification: Story = {}; + +export const Dot: Story = { + args: { + badgeType: "dot", + symbol: null, + isNotification: true, + }, +}; + +export const Highlight: Story = { + args: { + isHighlight: true, + symbol: "!", + }, +}; + +export const Knocked: Story = { + args: { + isKnocked: true, + symbol: "!", + }, +}; + +export const Hidden: Story = { + args: { + shouldRender: false, + }, +}; diff --git a/packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.test.tsx b/packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.test.tsx new file mode 100644 index 0000000000..35f8753631 --- /dev/null +++ b/packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.test.tsx @@ -0,0 +1,41 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import { render, screen } from "@test-utils"; +import { composeStories } from "@storybook/react-vite"; +import React from "react"; +import { describe, expect, it } from "vitest"; + +import * as stories from "./NotificationBadgeView.stories"; + +const { Notification, Dot, Knocked, Hidden } = composeStories(stories); + +describe("NotificationBadgeView", () => { + it("renders the default notification badge", () => { + const { container } = render(); + + expect(container).toMatchSnapshot(); + }); + + it("renders a dot badge", () => { + render(); + + expect(screen.getByTestId("notification-badge")).toHaveAttribute("data-badge-type", "dot"); + }); + + it("renders a knocked badge icon", () => { + render(); + + expect(screen.getByLabelText("Request to join sent")).toBeInTheDocument(); + }); + + it("does not render when hidden", () => { + const { container } = render(); + + expect(container.firstChild).toBeNull(); + }); +}); diff --git a/packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.tsx b/packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.tsx new file mode 100644 index 0000000000..52b558840e --- /dev/null +++ b/packages/shared-components/src/notifications/NotificationBadgeView/NotificationBadgeView.tsx @@ -0,0 +1,95 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import React, { type JSX } from "react"; +import classNames from "classnames"; +import { AskToJoinIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; + +import { type ViewModel, useViewModel } from "../../core/viewmodel"; +import styles from "./NotificationBadgeView.module.css"; + +export type NotificationBadgeType = "dot" | "badge_2char" | "badge_3char"; + +export interface NotificationBadgeViewSnapshot { + /** + * Controls whether the badge root should render. + */ + shouldRender: boolean; + /** + * Controls whether the badge receives the visible styling class. + */ + isVisible: boolean; + /** + * Marks the badge as a regular notification. + */ + isNotification: boolean; + /** + * Marks the badge as a highlight notification. + */ + isHighlight: boolean; + /** + * Marks the badge as representing a knock request. + */ + isKnocked: boolean; + /** + * Controls the visual badge shape. + */ + badgeType: NotificationBadgeType; + /** + * Display text for non-knock badges. + */ + symbol: string | null; + /** + * Accessible label for the knock icon. + */ + knockLabel?: string; +} + +export type NotificationBadgeViewModel = ViewModel; + +interface NotificationBadgeViewProps { + vm: NotificationBadgeViewModel; +} + +export function NotificationBadgeView({ vm }: Readonly): JSX.Element { + const { shouldRender, isVisible, isNotification, isHighlight, isKnocked, badgeType, symbol, knockLabel } = + useViewModel(vm); + + if (!shouldRender) { + return <>; + } + + const classes = classNames(styles.notificationBadge, { + [styles.visible]: isVisible, + [styles.notification]: isNotification, + [styles.highlight]: isHighlight, + [styles.dot]: badgeType === "dot", + [styles.badge2Char]: badgeType === "badge_2char", + [styles.badge3Char]: badgeType === "badge_3char", + // Badges with text should always use light colors. + "cpd-theme-light": badgeType !== "dot", + }); + const notificationLevel = isHighlight ? "highlight" : isNotification ? "notification" : undefined; + + const content = + isKnocked && knockLabel ? ( + + ) : ( + {symbol} + ); + + return ( +
+ {content} +
+ ); +} diff --git a/packages/shared-components/src/notifications/NotificationBadgeView/__snapshots__/NotificationBadgeView.test.tsx.snap b/packages/shared-components/src/notifications/NotificationBadgeView/__snapshots__/NotificationBadgeView.test.tsx.snap new file mode 100644 index 0000000000..2f5ce14acc --- /dev/null +++ b/packages/shared-components/src/notifications/NotificationBadgeView/__snapshots__/NotificationBadgeView.test.tsx.snap @@ -0,0 +1,17 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`NotificationBadgeView > renders the default notification badge 1`] = ` +
+
+ + 3 + +
+
+`; diff --git a/packages/shared-components/src/notifications/NotificationBadgeView/index.tsx b/packages/shared-components/src/notifications/NotificationBadgeView/index.tsx new file mode 100644 index 0000000000..fbb2fef1ee --- /dev/null +++ b/packages/shared-components/src/notifications/NotificationBadgeView/index.tsx @@ -0,0 +1,13 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +export { + NotificationBadgeView, + type NotificationBadgeType, + type NotificationBadgeViewModel, + type NotificationBadgeViewSnapshot, +} from "./NotificationBadgeView";