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`] = ` + + +
+ +
+
+
+ +
+ +
+ +

+ Application Name +

+
+
+
+ + alpha + +
+
+ + v0.0.7 + +
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + 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";