Skip to content

Commit

Permalink
fix(web-components): changes to ic-badge and ic-navigation-button to …
Browse files Browse the repository at this point in the history
…show notifications in mobile

ic-badge now renders as inline variant when in ic-top-navigation and in mobile view.
  • Loading branch information
gd2910 committed Feb 12, 2025
1 parent 8f687d3 commit 0d90b60
Show file tree
Hide file tree
Showing 6 changed files with 346 additions and 13 deletions.
45 changes: 43 additions & 2 deletions packages/web-components/src/components/ic-badge/ic-badge.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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.
*/
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,88 @@ exports[`ic-badge should render slotted in a tab with aria-label set on badge: s
</ic-tab>
`;

exports[`ic-badge should render slotted in a top navigation: should render slotted in a top navigation 1`] = `
<ic-top-navigation app-title="Application Name" status="alpha" version="v0.0.7">
<mock:shadow-root>
<div class="top-navigation">
<ic-section-container aligned="full-width" full-height="">
<header role="banner">
<div class="top-panel-container">
<div class="app-details-container">
<a class="title-link" href="/">
<div class="app-icon-container">
<slot name="app-icon"></slot>
</div>
<ic-typography variant="h3">
<h1 class="title-wrap">
Application Name
</h1>
</ic-typography>
</a>
<div class="app-status">
<ic-typography aria-label="app tag" class="app-status-text" variant="label-uppercase">
alpha
</ic-typography>
</div>
<div class="app-version">
<ic-typography aria-label="app version" class="app-version-text" variant="label">
v0.0.7
</ic-typography>
</div>
</div>
<div class="search-menu-container">
<div class="search-actions-container">
<slot name="search"></slot>
<div class="icon-buttons-container">
<slot name="buttons"></slot>
</div>
</div>
</div>
</div>
</header>
</ic-section-container>
</div>
</mock:shadow-root>
<svg fill="#000000" height="24px" slot="app-icon" viewBox="0 0 24 24" width="24px" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0V0z" fill="none"></path>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"></path>
</svg>
<ic-search-bar label="Search" placeholder="Search" slot="search"></ic-search-bar>
<ic-navigation-button href="https://www.google.com" label="Button One" slot="buttons" target="_blank" title="Google 1">
<svg fill="#000000" height="24px" slot="icon" viewBox="0 0 24 24" width="24px" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0V0z" fill="none"></path>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"></path>
</svg>
<ic-badge class="ic-badge-medium ic-badge-near ic-badge-neutral ic-badge-show ic-badge-text" label="1" role="status" slot="badge">
<mock:shadow-root>
<ic-typography variant="badge">
1
</ic-typography>
</mock:shadow-root>
</ic-badge>
</ic-navigation-button>
<ic-navigation-button href="https://www.google.com" label="Button Two" slot="buttons" target="_blank" title="Google 2">
<svg fill="#000000" height="24px" slot="icon" viewBox="0 0 24 24" width="24px" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0z" fill="none"></path>
<path d="M21 6h-2v9H6v2c0 .55.45 1 1 1h11l4 4V7c0-.55-.45-1-1-1zm-4 6V3c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1v14l4-4h10c.55 0 1-.45 1-1z"></path>
</svg>
<ic-badge class="ic-badge-dot ic-badge-medium ic-badge-near ic-badge-neutral ic-badge-show" role="status" slot="badge" type="dot">
<mock:shadow-root>
<span class="sr-only">
badge
</span>
</mock:shadow-root>
</ic-badge>
</ic-navigation-button>
<ic-navigation-button label="Button Three" onclick="alert('test')" slot="buttons">
<svg fill="#000000" height="24px" slot="icon" viewBox="0 0 24 24" width="24px" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0V0z" fill="none"></path>
<path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"></path>
</svg>
</ic-navigation-button>
</ic-top-navigation>
`;

exports[`ic-badge should render slotted in a vertical card with aria-label set on badge: should render slotted in a card 1`] = `
<ic-card-vertical heading="Badge">
<mock:shadow-root>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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],
Expand Down Expand Up @@ -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: `<ic-top-navigation
app-title="Application Name"
status="alpha"
version="v0.0.7"
>
<svg
slot="app-icon"
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="#000000"
>
<path d="M0 0h24v24H0V0z" fill="none" />
<path
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
/>
</svg>
<ic-search-bar
slot="search"
placeholder="Search"
label="Search"
></ic-search-bar>
<ic-navigation-button
label="Button One"
slot="buttons"
href="https://www.google.com"
target="_blank"
title="Google 1"
>
<svg
slot="icon"
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="#000000"
>
<path d="M0 0h24v24H0V0z" fill="none" />
<path
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
/>
</svg>
<ic-badge label="1" slot="badge"></ic-badge>
</ic-navigation-button>
<ic-navigation-button
label="Button Two"
slot="buttons"
href="https://www.google.com"
target="_blank"
title="Google 2"
>
<svg
slot="icon"
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="#000000"
>
<path d="M0 0h24v24H0z" fill="none" />
<path
d="M21 6h-2v9H6v2c0 .55.45 1 1 1h11l4 4V7c0-.55-.45-1-1-1zm-4 6V3c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1v14l4-4h10c.55 0 1-.45 1-1z"
/>
</svg>
<ic-badge slot="badge" type="dot"></ic-badge>
</ic-navigation-button>
<ic-navigation-button
label="Button Three"
slot="buttons"
onclick="alert('test')"
>
<svg
slot="icon"
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="#000000"
>
<path d="M0 0h24v24H0V0z" fill="none" />
<path
d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"
/>
</svg>
</ic-navigation-button>
</ic-top-navigation>`,
});

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],
Expand Down Expand Up @@ -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: `<ic-top-navigation
app-title="Application Name"
status="alpha"
version="v0.0.7"
>
<svg
slot="app-icon"
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="#000000"
>
<path d="M0 0h24v24H0V0z" fill="none" />
<path
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
/>
</svg>
<ic-search-bar
slot="search"
placeholder="Search"
label="Search"
></ic-search-bar>
<ic-navigation-button
label="Button One"
slot="buttons"
href="https://www.google.com"
target="_blank"
title="Google 1"
>
<svg
slot="icon"
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="#000000"
>
<path d="M0 0h24v24H0V0z" fill="none" />
<path
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
/>
</svg>
<ic-badge label="1" slot="badge"></ic-badge>
</ic-navigation-button>
<ic-navigation-button
label="Button Two"
slot="buttons"
href="https://www.google.com"
target="_blank"
title="Google 2"
>
<svg
slot="icon"
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="#000000"
>
<path d="M0 0h24v24H0z" fill="none" />
<path
d="M21 6h-2v9H6v2c0 .55.45 1 1 1h11l4 4V7c0-.55-.45-1-1-1zm-4 6V3c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1v14l4-4h10c.55 0 1-.45 1-1z"
/>
</svg>
<ic-badge slot="badge" type="dot"></ic-badge>
</ic-navigation-button>
<ic-navigation-button
label="Button Three"
slot="buttons"
onclick="alert('test')"
>
<svg
slot="icon"
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="#000000"
>
<path d="M0 0h24v24H0V0z" fill="none" />
<path
d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"
/>
</svg>
</ic-navigation-button>
</ic-top-navigation>`,
});

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");
});
});
Loading

0 comments on commit 0d90b60

Please sign in to comment.