From 0d90b60ae1015474eec71dbd1a9a8fd048dea0cf Mon Sep 17 00:00:00 2001
From: gd2910 <122624946+gd2910@users.noreply.github.com>
Date: Tue, 11 Feb 2025 13:15:33 +0000
Subject: [PATCH] fix(web-components): changes to ic-badge and
ic-navigation-button to show notifications in mobile
ic-badge now renders as inline variant when in ic-top-navigation and in mobile view.
---
.../src/components/ic-badge/ic-badge.tsx | 45 +++-
.../__snapshots__/ic-badge.spec.tsx.snap | 82 +++++++
.../ic-badge/test/basic/ic-badge.spec.tsx | 204 ++++++++++++++++++
.../ic-navigation-button.css | 4 +
.../ic-navigation-button.tsx | 4 +-
.../ic-top-navigation.stories.mdx | 20 +-
6 files changed, 346 insertions(+), 13 deletions(-)
diff --git a/packages/web-components/src/components/ic-badge/ic-badge.tsx b/packages/web-components/src/components/ic-badge/ic-badge.tsx
index 2e942a0534..b237fb4a9b 100644
--- a/packages/web-components/src/components/ic-badge/ic-badge.tsx
+++ b/packages/web-components/src/components/ic-badge/ic-badge.tsx
@@ -1,4 +1,12 @@
-import { Component, Element, Host, Prop, Watch, h } from "@stencil/core";
+import {
+ Component,
+ Element,
+ Host,
+ Prop,
+ Watch,
+ h,
+ Listen,
+} from "@stencil/core";
import {
IcBadgePositions,
IcBadgeTypes,
@@ -17,6 +25,9 @@ import {
onComponentRequiredPropUndefined,
} from "../../utils/helpers";
+const NAVIGATION_BUTTON = "IC-NAVIGATION-BUTTON";
+const TOP_NAVIGATION = "IC-TOP-NAVIGATION";
+
/**
* @slot badge-icon - Icon will be rendered inside the badge if type is set to icon.
*/
@@ -64,7 +75,7 @@ export class Badge {
/**
* The positioning of the badge in reference to the parent element.
*/
- @Prop() position?: IcBadgePositions = "far";
+ @Prop({ mutable: true }) position?: IcBadgePositions = "far";
/**
* The size of the badge to be displayed.
@@ -124,6 +135,20 @@ export class Badge {
);
}
+ componentWillRender(): void {
+ this.isInTopNav() && this.setPositionInTopNavigation();
+ }
+
+ @Listen("icNavigationMenuOpened", { target: "document" })
+ navBarMenuOpenHandler(): void {
+ this.isInTopNav() && (this.position = "inline");
+ }
+
+ @Listen("icNavigationMenuClosed", { target: "document" })
+ navBarMenuCloseHandler(): void {
+ this.isInTopNav() && (this.position = "near");
+ }
+
private setBadgeColour = () => {
const colorRGBA = convertToRGBA(this.customColor);
@@ -167,6 +192,22 @@ export class Badge {
}
};
+ private setPositionInTopNavigation = () => {
+ const parentTopNavEl = this.el.parentElement.parentElement;
+ parentTopNavEl.classList.contains("mobile-mode")
+ ? (this.position = "inline")
+ : (this.position = "near");
+ };
+
+ private isInTopNav = (): boolean => {
+ const parentEl = this.el.parentElement;
+ const grandparentEl = parentEl.parentElement;
+ return (
+ parentEl.tagName === NAVIGATION_BUTTON &&
+ grandparentEl.tagName === TOP_NAVIGATION
+ );
+ };
+
private isAccessibleLabelDefined = () =>
isPropDefined(this.accessibleLabel) && this.accessibleLabel !== null;
diff --git a/packages/web-components/src/components/ic-badge/test/basic/__snapshots__/ic-badge.spec.tsx.snap b/packages/web-components/src/components/ic-badge/test/basic/__snapshots__/ic-badge.spec.tsx.snap
index 4df67e617a..22686ac001 100644
--- a/packages/web-components/src/components/ic-badge/test/basic/__snapshots__/ic-badge.spec.tsx.snap
+++ b/packages/web-components/src/components/ic-badge/test/basic/__snapshots__/ic-badge.spec.tsx.snap
@@ -227,6 +227,88 @@ exports[`ic-badge should render slotted in a tab with aria-label set on badge: s
`;
+exports[`ic-badge should render slotted in a top navigation: should render slotted in a top navigation 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+ badge
+
+
+
+
+
+
+
+
+`;
+
exports[`ic-badge should render slotted in a vertical card with aria-label set on badge: should render slotted in a card 1`] = `
diff --git a/packages/web-components/src/components/ic-badge/test/basic/ic-badge.spec.tsx b/packages/web-components/src/components/ic-badge/test/basic/ic-badge.spec.tsx
index bb059b25b1..11612ea8ff 100644
--- a/packages/web-components/src/components/ic-badge/test/basic/ic-badge.spec.tsx
+++ b/packages/web-components/src/components/ic-badge/test/basic/ic-badge.spec.tsx
@@ -6,6 +6,7 @@ import { Tab } from "../../../ic-tab/ic-tab";
import { CardVertical } from "../../../ic-card-vertical/ic-card-vertical";
import { NavigationButton } from "../../../ic-navigation-button/ic-navigation-button";
import { NavigationItem } from "../../../ic-navigation-item/ic-navigation-item";
+import { TopNavigation } from "../../../ic-top-navigation/ic-top-navigation";
describe("ic-badge", () => {
it("should render with text slotted in a button", async () => {
@@ -54,6 +55,7 @@ describe("ic-badge", () => {
expect(page.root).toMatchSnapshot("should render warning variant");
});
+
it("should render info variant", async () => {
const page = await newSpecPage({
components: [Button, Badge],
@@ -217,6 +219,103 @@ describe("ic-badge", () => {
);
});
+ it("should render slotted in a top navigation", async () => {
+ const page = await newSpecPage({
+ components: [TopNavigation, NavigationItem, Badge],
+ html: `
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `,
+ });
+
+ expect(page.root).toMatchSnapshot(
+ "should render slotted in a top navigation"
+ );
+ });
+
it("should render slotted in a navigation item", async () => {
const page = await newSpecPage({
components: [NavigationItem, Badge],
@@ -321,4 +420,109 @@ describe("ic-badge", () => {
const badge = document.querySelector("ic-badge");
expect(badge.style.backgroundColor).toBe("rgba(222, 10, 43, 1)");
});
+
+ it("should set the correct variant when navigation menu is opened and closed", async () => {
+ const page = await newSpecPage({
+ components: [Badge, NavigationButton],
+ html: `
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `,
+ });
+
+ const badge = document.querySelector("ic-badge");
+
+ expect(page.rootInstance.mode).toBe("navbar");
+
+ document.dispatchEvent(new CustomEvent("icNavigationMenuOpened"));
+ expect(page.rootInstance.mode).toBe("menu");
+ expect(badge.position).toBe("inline");
+
+ document.dispatchEvent(new CustomEvent("icNavigationMenuClosed"));
+ expect(page.rootInstance.mode).toBe("navbar");
+ expect(badge.position).toBe("near");
+ });
});
diff --git a/packages/web-components/src/components/ic-navigation-button/ic-navigation-button.css b/packages/web-components/src/components/ic-navigation-button/ic-navigation-button.css
index 0fd9c5f150..de177043f4 100644
--- a/packages/web-components/src/components/ic-navigation-button/ic-navigation-button.css
+++ b/packages/web-components/src/components/ic-navigation-button/ic-navigation-button.css
@@ -28,3 +28,7 @@
color: var(--ic-top-navigation-icon-pressed);
background-color: var(--ic-top-navigation-icon-pressed-background);
}
+
+:host(.in-side-menu) ::slotted(ic-badge) {
+ margin-left: var(--ic-space-xs);
+}
diff --git a/packages/web-components/src/components/ic-navigation-button/ic-navigation-button.tsx b/packages/web-components/src/components/ic-navigation-button/ic-navigation-button.tsx
index 9b5192abd9..1b5073ebfd 100644
--- a/packages/web-components/src/components/ic-navigation-button/ic-navigation-button.tsx
+++ b/packages/web-components/src/components/ic-navigation-button/ic-navigation-button.tsx
@@ -212,9 +212,7 @@ export class NavigationButton {
>
{label}
- {isSlotUsed(this.el, "badge") && variant === "icon" && (
-
- )}
+ {isSlotUsed(this.el, "badge") && }
);
diff --git a/packages/web-components/src/components/ic-top-navigation/ic-top-navigation.stories.mdx b/packages/web-components/src/components/ic-top-navigation/ic-top-navigation.stories.mdx
index e800baa6fe..d3cd501b60 100644
--- a/packages/web-components/src/components/ic-top-navigation/ic-top-navigation.stories.mdx
+++ b/packages/web-components/src/components/ic-top-navigation/ic-top-navigation.stories.mdx
@@ -191,8 +191,9 @@ import NavigationGroup from "../ic-navigation-group/readme.md";