Skip to content

Commit 1189430

Browse files
committed
feat( default behaviour ): pause notification kill-duration on mouseover and resume on mouseleave
- add "should pause on mouseover" test - add "EventListener", "Timer" utilities' classes - public "NotyfNotification.triggerEvent" | to make "NotyfView" trigger "mouseover" event on "NotyfNotification" - add "NotyfEvent.MouseOver" - add "NotyfEvent.MouseLeave" - update "Notyf._pushNotification" = pause "NotyfNotification" timer and resume timer on "mouseleave" = remove "NotyfNotification" on timer "finished" event - trigger "mouseover" event on "NotyfNotification" by "NotyfView" - trigger "mouseleave" event on "NotyfNotification" by "NotyfView" close #110
1 parent d19f0ab commit 1189430

File tree

7 files changed

+114
-5
lines changed

7 files changed

+114
-5
lines changed

cypress/integration/notyf_spec.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,32 @@ context('Notyf', () => {
5454
expect(pos.top).to.be.greaterThan(VIEWPORT_HEIGHT / 2);
5555
});
5656
});
57+
58+
it('should pause on mouseover', () => {
59+
60+
setConfiguration({ message: 'Notyf 1' })
61+
cy.get('#success-btn').click()
62+
63+
setConfiguration({ message: 'Notyf 2' })
64+
cy.get('#success-btn').click()
65+
66+
setConfiguration({ message: 'Notyf 3' })
67+
cy.get('#success-btn').click()
68+
69+
cy.get('.notyf__toast:nth-child(2)').trigger('mouseover')
70+
71+
cy.wait(2000)
72+
73+
cy.get('.notyf').children().should('have.length', 1)
74+
75+
cy.get('.notyf__toast').trigger('mouseleave')
76+
77+
cy.wait(2000)
78+
79+
cy.get('.notyf__toast').should('not.be.exist')
80+
81+
})
82+
5783
});
5884

5985
describe('Global custom configuration', () => {

src/notyf.models.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class NotyfNotification {
1717
this.listeners[eventType] = callbacks.concat([cb]);
1818
}
1919

20-
private triggerEvent(eventType: NotyfEvent, event?: Event) {
20+
triggerEvent(eventType: NotyfEvent, event?: Event) {
2121
const callbacks = this.listeners[eventType] || [];
2222
callbacks.forEach((cb) => cb({ target: this, event }));
2323
}

src/notyf.options.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ export interface INotyfPosition {
1111
export enum NotyfEvent {
1212
Dismiss = 'dismiss',
1313
Click = 'click',
14+
MouseOver = 'mouseover',
15+
MouseLeave = 'mouseleave'
1416
}
1517

1618
export interface INotyfIcon {

src/notyf.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
NotyfEvent,
88
} from './notyf.options';
99
import { NotyfView } from './notyf.view';
10+
import Timer from './utils/classes/timer';
1011

1112
/**
1213
* Main controller class. Defines the main Notyf API.
@@ -82,12 +83,22 @@ export default class Notyf {
8283
}
8384

8485
private _pushNotification(notification: NotyfNotification) {
85-
this.notifications.push(notification);
86+
87+
this.notifications.push( notification );
88+
8689
const duration =
8790
notification.options.duration !== undefined ? notification.options.duration : this.options.duration;
88-
if (duration) {
89-
setTimeout(() => this._removeNotification(notification), duration);
90-
}
91+
92+
if ( !duration ) return
93+
94+
const timer = new Timer( duration );
95+
96+
notification.on(NotyfEvent.MouseOver, () => timer.pause());
97+
98+
notification.on(NotyfEvent.MouseLeave, () => timer.resume());
99+
100+
timer.on('finished', () => this._removeNotification(notification) )
101+
91102
}
92103

93104
private _removeNotification(notification: NotyfNotification) {

src/notyf.view.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,14 @@ export class NotyfView {
196196
this.events[NotyfEvent.Click]?.({ target: notification, event }),
197197
);
198198

199+
notificationElem.addEventListener('mouseover', event =>
200+
notification.triggerEvent(NotyfEvent.MouseOver, event)
201+
)
202+
203+
notificationElem.addEventListener('mouseleave', event =>
204+
notification.triggerEvent(NotyfEvent.MouseLeave, event)
205+
)
206+
199207
// Adjust margins depending on whether its an upper or lower notification
200208
const className = this.getYPosition(options) === 'top' ? 'upper' : 'lower';
201209
notificationElem.classList.add(`notyf__toast--${className}`);

src/utils/classes/eventListener.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
type EventCallback = (event: any) => void;
2+
3+
export default class EventeListener {
4+
protected listeners: Partial<Record<string, EventCallback[]>> = {};
5+
6+
constructor() {}
7+
8+
public on(eventType: string, cb: EventCallback) {
9+
const callbacks = this.listeners[eventType] || [];
10+
this.listeners[eventType] = callbacks.concat([cb]);
11+
}
12+
13+
protected triggerEvent(eventType: string, event?: any) {
14+
const callbacks = this.listeners[eventType] || [];
15+
callbacks.forEach((callback: EventCallback) => callback(event));
16+
}
17+
}

src/utils/classes/timer.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import EventListener from './eventListener';
2+
3+
export default class Timer extends EventListener {
4+
5+
private startTime: number = Date.now();
6+
7+
private timer: ReturnType<typeof setTimeout>;
8+
9+
private lastTime: number = Date.now();
10+
11+
get leftTime() {
12+
return this.duration - (this.lastTime - this.startTime);
13+
}
14+
15+
constructor(public duration: number) {
16+
super();
17+
18+
this.timer = setTimeout(() => {
19+
this.triggerEvent('finished');
20+
21+
this.lastTime = Date.now();
22+
}, duration);
23+
}
24+
25+
pause() {
26+
this.triggerEvent('pause');
27+
28+
clearTimeout(this.timer);
29+
30+
this.lastTime = Date.now();
31+
}
32+
33+
resume() {
34+
this.triggerEvent('resume');
35+
36+
clearTimeout(this.timer);
37+
38+
this.timer = setTimeout(() => {
39+
this.triggerEvent('finished');
40+
41+
this.lastTime = Date.now();
42+
}, this.leftTime);
43+
}
44+
45+
}

0 commit comments

Comments
 (0)