Skip to content

Commit

Permalink
fix(alert): update alert queue when an alert is removed from the DOM (#…
Browse files Browse the repository at this point in the history
…7189)

**Related Issue:** #6616

## Summary

- Adds new internal event `calciteInternalAlertUnregister` to dispatch
when an alert is removed from the DOM.
- Event is dispatched on the window since that is where the listeners
are and dispatching on the element won't reach the window since the
element would no longer be in the DOM.
- When the event is received, the queue is updated to remove the removed
alert element.
- queue is kept n'sync.


![giphy](https://github.com/Esri/calcite-components/assets/1231455/691e1744-6045-48b2-8e55-97479a2b8a5b)
  • Loading branch information
driskull authored Jun 21, 2023
1 parent 0e4c6bb commit edd59eb
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 1 deletion.
71 changes: 71 additions & 0 deletions packages/calcite-components/src/components/alert/alert.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,77 @@ describe("calcite-alert", () => {
expect(await container.isVisible()).toBe(false);
});

it("should update number of queued alerts with a calcite-chip when removing an alert", async () => {
const page = await newE2EPage();
await page.setContent(html`
<calcite-button id="buttonOne" onclick="document.querySelector('#first-open').setAttribute('open', '')"
>open alert</calcite-button
>
<calcite-button id="buttonTwo" onclick="document.querySelector('#second-open').setAttribute('open', '')"
>open alert</calcite-button
>
<calcite-button id="buttonThree" onclick="document.querySelector('#third-open').setAttribute('open', '')"
>open alert</calcite-button
>
<calcite-alert open id="first-open" icon="3d-glasses" scale="l">
<div slot="title">Title of alert Uno</div>
<div slot="message">Message text of the alert Uno</div>
<a slot="link" href="#">Retry</a>
</calcite-alert>
<calcite-alert id="second-open" icon scale="l">
<div slot="title">Title of alert Dos</div>
<div slot="message">Message text of the alert Dos</div>
<a slot="link" href="#">Retry</a>
</calcite-alert>
<calcite-alert id="third-open" icon scale="l">
<div slot="title">Title of alert Dos</div>
<div slot="message">Message text of the alert Dos</div>
<a slot="link" href="#">Retry</a>
</calcite-alert>
`);
const buttonOne = await page.find("#buttonOne");
const buttonTwo = await page.find("#buttonTwo");
const buttonThree = await page.find("#buttonThree");
const alertOne = await page.find("#first-open");
const alertTwo = await page.find("#second-open");
const alertThree = await page.find("#third-open");

await buttonOne.click();
await page.waitForTimeout(animationDurationInMs);
expect(await alertOne.isVisible()).toBe(true);

await buttonTwo.click();
expect(await alertTwo.isVisible()).toBe(true);

await buttonThree.click();
expect(await alertThree.isVisible()).toBe(true);

const chip = await page.find("calcite-alert[id='first-open'] >>> calcite-chip");
const chipQueueCount2 = "+2";
expect(await chip.getProperty("value")).toEqual(chipQueueCount2);
expect(chip.textContent).toEqual(chipQueueCount2);

await page.$eval("#third-open", (alert: HTMLCalciteAlertElement) => {
alert.remove();
});
await page.waitForChanges();

const chipQueueCount1 = "+1";
expect(await chip.getProperty("value")).toEqual(chipQueueCount1);
expect(chip.textContent).toEqual(chipQueueCount1);

await page.$eval("#second-open", (alert: HTMLCalciteAlertElement) => {
alert.remove();
});
await page.waitForChanges();

expect(await page.find("calcite-alert[id='first-open'] >>> calcite-chip")).toBeNull();
});

describe("auto-close behavior on queued items", () => {
it("should display number of queued alerts with a calcite-chip", async () => {
const page = await newE2EPage();
Expand Down
20 changes: 19 additions & 1 deletion packages/calcite-components/src/components/alert/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import {
import { Kind, Scale } from "../interfaces";
import { KindIcons } from "../resources";
import { AlertMessages } from "./assets/alert/t9n";
import { AlertDuration, Sync } from "./interfaces";
import { AlertDuration, Sync, Unregister } from "./interfaces";
import { CSS, DURATIONS, SLOTS } from "./resources";

/**
Expand Down Expand Up @@ -203,6 +203,11 @@ export class Alert implements OpenCloseComponent, LoadableComponent, T9nComponen
}

disconnectedCallback(): void {
window.dispatchEvent(
new CustomEvent<Unregister>("calciteInternalAlertUnregister", {
detail: { alert: this.el }
})
);
window.clearTimeout(this.autoCloseTimeoutId);
window.clearTimeout(this.queueTimeout);
disconnectOpenCloseComponent(this);
Expand Down Expand Up @@ -353,6 +358,19 @@ export class Alert implements OpenCloseComponent, LoadableComponent, T9nComponen
this.determineActiveAlert();
}

// Event is dispatched on the window because the element is not in the DOM so bubbling won't occur.
@Listen("calciteInternalAlertUnregister", { target: "window" })
alertUnregister(event: CustomEvent<Unregister>): void {
const queue = this.queue.filter((el) => el !== event.detail.alert);
this.queue = queue;

window.dispatchEvent(
new CustomEvent<Sync>("calciteInternalAlertSync", {
detail: { queue }
})
);
}

//--------------------------------------------------------------------------
//
// Public Methods
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
export type AlertDuration = "fast" | "medium" | "slow";

export interface Sync {
queue: HTMLCalciteAlertElement[];
}

export interface Unregister {
alert: HTMLCalciteAlertElement;
}

0 comments on commit edd59eb

Please sign in to comment.