Skip to content

Commit fa9a829

Browse files
authored
fix(alert): pause auto-close alert when link focused (#9503)
**Related Issue:** #5960 ## Summary Paused auto close when the focus is in the link or close buton or when the mouse is hovered over the alert dialog.
1 parent 4faa160 commit fa9a829

File tree

4 files changed

+61
-4
lines changed

4 files changed

+61
-4
lines changed

packages/calcite-components/src/components/alert/alert.e2e.ts

+14
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,20 @@ describe("calcite-alert", () => {
457457
await page.waitForTimeout(DURATIONS.medium + animationDurationInMs);
458458
await page.waitForSelector("#alert", { visible: false });
459459
});
460+
461+
it("pauses on focus and resumes on blur", async () => {
462+
await button.click();
463+
expect(await alert.isVisible()).toBe(true);
464+
expect(await alert.getProperty("autoCloseDuration")).toEqual("medium");
465+
expect(playState).toEqual("running");
466+
buttonClose = await page.find(`#alert >>> .${CSS.close}`);
467+
buttonClose.focus();
468+
await page.waitForTimeout(DURATIONS.medium);
469+
expect(await alert.isVisible()).toBe(true);
470+
await button.focus();
471+
await page.waitForTimeout(DURATIONS.medium + animationDurationInMs);
472+
await page.waitForSelector("#alert", { visible: false });
473+
});
460474
});
461475

462476
describe("translation support", () => {

packages/calcite-components/src/components/alert/alert.scss

+6-1
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,16 @@ $alertDurations:
293293
:host([auto-close-duration="#{$name}"]) .dismiss-progress:after {
294294
animation: dismissProgress $duration ease-out;
295295
}
296-
:host(:hover[auto-close-duration="#{$name}"]) .dismiss-progress:after {
296+
:host(:hover[auto-close-duration="#{$name}"]) .dismiss-progress:after,
297+
:host(:focus[auto-close-duration="#{$name}"]) .dismiss-progress:after {
297298
animation-play-state: paused;
298299
}
299300
}
300301

302+
.container.focused .dismiss-progress:after {
303+
animation-play-state: paused;
304+
}
305+
301306
@keyframes dismissProgress {
302307
0% {
303308
@apply w-0 opacity-75;

packages/calcite-components/src/components/alert/alert.tsx

+40-3
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ export class Alert implements OpenCloseComponent, LoadableComponent, T9nComponen
200200
}),
201201
);
202202
window.clearTimeout(this.autoCloseTimeoutId);
203+
this.autoCloseTimeoutId = null;
203204
window.clearTimeout(this.queueTimeout);
204205
disconnectLocalized(this);
205206
disconnectMessages(this);
@@ -226,13 +227,18 @@ export class Alert implements OpenCloseComponent, LoadableComponent, T9nComponen
226227
[CSS.containerQueued]: queued,
227228
[`${CSS.container}--${placement}`]: true,
228229
[CSS.containerSlottedInShell]: this.slottedInShell,
230+
[CSS.focused]: this.keyBoardFocus,
229231
}}
230232
onPointerEnter={this.autoClose && this.autoCloseTimeoutId ? this.handleMouseOver : null}
231-
onPointerLeave={this.autoClose && this.autoCloseTimeoutId ? this.handleMouseLeave : null}
233+
onPointerLeave={this.autoClose ? this.handleMouseLeave : null}
232234
ref={this.setTransitionEl}
233235
>
234236
{effectiveIcon && this.renderIcon(effectiveIcon)}
235-
<div class={CSS.textContainer}>
237+
<div
238+
class={CSS.textContainer}
239+
onFocusin={this.autoClose && this.autoCloseTimeoutId ? this.handleKeyBoardFocus : null}
240+
onFocusout={this.autoClose ? this.handleKeyBoardBlur : null}
241+
>
236242
<slot name={SLOTS.title} />
237243
<slot name={SLOTS.message} />
238244
<slot name={SLOTS.link} />
@@ -246,13 +252,27 @@ export class Alert implements OpenCloseComponent, LoadableComponent, T9nComponen
246252
);
247253
}
248254

255+
private handleKeyBoardFocus = (): void => {
256+
this.keyBoardFocus = true;
257+
this.handleFocus();
258+
};
259+
260+
private handleKeyBoardBlur = (): void => {
261+
this.keyBoardFocus = false;
262+
if (!this.mouseFocus) {
263+
this.handleBlur();
264+
}
265+
};
266+
249267
private renderCloseButton(): VNode {
250268
return (
251269
<button
252270
aria-label={this.messages.close}
253271
class={CSS.close}
254272
key="close"
255273
onClick={this.closeAlert}
274+
onFocusin={this.autoClose ? this.handleKeyBoardFocus : null}
275+
onFocusout={this.autoClose ? this.handleKeyBoardBlur : null}
256276
ref={(el) => (this.closeButton = el)}
257277
type="button"
258278
>
@@ -429,6 +449,8 @@ export class Alert implements OpenCloseComponent, LoadableComponent, T9nComponen
429449
/** is the alert queued */
430450
@State() queued = false;
431451

452+
@State() keyBoardFocus = false;
453+
432454
private autoCloseTimeoutId: number = null;
433455

434456
private closeButton: HTMLButtonElement;
@@ -447,6 +469,8 @@ export class Alert implements OpenCloseComponent, LoadableComponent, T9nComponen
447469

448470
transitionEl: HTMLDivElement;
449471

472+
mouseFocus: boolean;
473+
450474
//--------------------------------------------------------------------------
451475
//
452476
// Private Methods
@@ -510,12 +534,25 @@ export class Alert implements OpenCloseComponent, LoadableComponent, T9nComponen
510534
};
511535

512536
private handleMouseOver = (): void => {
537+
this.mouseFocus = true;
538+
this.handleFocus();
539+
};
540+
541+
private handleMouseLeave = (): void => {
542+
this.mouseFocus = false;
543+
if (!this.keyBoardFocus) {
544+
this.handleBlur();
545+
}
546+
};
547+
548+
private handleFocus = (): void => {
513549
window.clearTimeout(this.autoCloseTimeoutId);
550+
this.autoCloseTimeoutId = null;
514551
this.totalOpenTime = Date.now() - this.initialOpenTime;
515552
this.lastMouseOverBegin = Date.now();
516553
};
517554

518-
private handleMouseLeave = (): void => {
555+
private handleBlur = (): void => {
519556
const hoverDuration = Date.now() - this.lastMouseOverBegin;
520557
const timeRemaining =
521558
DURATIONS[this.autoCloseDuration] - this.totalOpenTime + this.totalHoverTime;

packages/calcite-components/src/components/alert/resources.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ export const CSS = {
3131
queueCount: "queue-count",
3232
queueCountActive: "queue-count--active",
3333
textContainer: "text-container",
34+
focused: "focused",
3435
};

0 commit comments

Comments
 (0)