Skip to content

Commit

Permalink
feat( default behaviour ): pause notification kill-duration on mouseo…
Browse files Browse the repository at this point in the history
…ver 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 caroso1222#110
  • Loading branch information
AbrahemAlhofe committed Jun 15, 2021
1 parent d19f0ab commit 1189430
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 5 deletions.
26 changes: 26 additions & 0 deletions cypress/integration/notyf_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,32 @@ context('Notyf', () => {
expect(pos.top).to.be.greaterThan(VIEWPORT_HEIGHT / 2);
});
});

it('should pause on mouseover', () => {

setConfiguration({ message: 'Notyf 1' })
cy.get('#success-btn').click()

setConfiguration({ message: 'Notyf 2' })
cy.get('#success-btn').click()

setConfiguration({ message: 'Notyf 3' })
cy.get('#success-btn').click()

cy.get('.notyf__toast:nth-child(2)').trigger('mouseover')

cy.wait(2000)

cy.get('.notyf').children().should('have.length', 1)

cy.get('.notyf__toast').trigger('mouseleave')

cy.wait(2000)

cy.get('.notyf__toast').should('not.be.exist')

})

});

describe('Global custom configuration', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/notyf.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class NotyfNotification {
this.listeners[eventType] = callbacks.concat([cb]);
}

private triggerEvent(eventType: NotyfEvent, event?: Event) {
triggerEvent(eventType: NotyfEvent, event?: Event) {
const callbacks = this.listeners[eventType] || [];
callbacks.forEach((cb) => cb({ target: this, event }));
}
Expand Down
2 changes: 2 additions & 0 deletions src/notyf.options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export interface INotyfPosition {
export enum NotyfEvent {
Dismiss = 'dismiss',
Click = 'click',
MouseOver = 'mouseover',
MouseLeave = 'mouseleave'
}

export interface INotyfIcon {
Expand Down
19 changes: 15 additions & 4 deletions src/notyf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
NotyfEvent,
} from './notyf.options';
import { NotyfView } from './notyf.view';
import Timer from './utils/classes/timer';

/**
* Main controller class. Defines the main Notyf API.
Expand Down Expand Up @@ -82,12 +83,22 @@ export default class Notyf {
}

private _pushNotification(notification: NotyfNotification) {
this.notifications.push(notification);

this.notifications.push( notification );

const duration =
notification.options.duration !== undefined ? notification.options.duration : this.options.duration;
if (duration) {
setTimeout(() => this._removeNotification(notification), duration);
}

if ( !duration ) return

const timer = new Timer( duration );

notification.on(NotyfEvent.MouseOver, () => timer.pause());

notification.on(NotyfEvent.MouseLeave, () => timer.resume());

timer.on('finished', () => this._removeNotification(notification) )

}

private _removeNotification(notification: NotyfNotification) {
Expand Down
8 changes: 8 additions & 0 deletions src/notyf.view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,14 @@ export class NotyfView {
this.events[NotyfEvent.Click]?.({ target: notification, event }),
);

notificationElem.addEventListener('mouseover', event =>
notification.triggerEvent(NotyfEvent.MouseOver, event)
)

notificationElem.addEventListener('mouseleave', event =>
notification.triggerEvent(NotyfEvent.MouseLeave, event)
)

// Adjust margins depending on whether its an upper or lower notification
const className = this.getYPosition(options) === 'top' ? 'upper' : 'lower';
notificationElem.classList.add(`notyf__toast--${className}`);
Expand Down
17 changes: 17 additions & 0 deletions src/utils/classes/eventListener.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
type EventCallback = (event: any) => void;

export default class EventeListener {
protected listeners: Partial<Record<string, EventCallback[]>> = {};

constructor() {}

public on(eventType: string, cb: EventCallback) {
const callbacks = this.listeners[eventType] || [];
this.listeners[eventType] = callbacks.concat([cb]);
}

protected triggerEvent(eventType: string, event?: any) {
const callbacks = this.listeners[eventType] || [];
callbacks.forEach((callback: EventCallback) => callback(event));
}
}
45 changes: 45 additions & 0 deletions src/utils/classes/timer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import EventListener from './eventListener';

export default class Timer extends EventListener {

private startTime: number = Date.now();

private timer: ReturnType<typeof setTimeout>;

private lastTime: number = Date.now();

get leftTime() {
return this.duration - (this.lastTime - this.startTime);
}

constructor(public duration: number) {
super();

this.timer = setTimeout(() => {
this.triggerEvent('finished');

this.lastTime = Date.now();
}, duration);
}

pause() {
this.triggerEvent('pause');

clearTimeout(this.timer);

this.lastTime = Date.now();
}

resume() {
this.triggerEvent('resume');

clearTimeout(this.timer);

this.timer = setTimeout(() => {
this.triggerEvent('finished');

this.lastTime = Date.now();
}, this.leftTime);
}

}

0 comments on commit 1189430

Please sign in to comment.