Skip to content

Commit

Permalink
feat: add dismiss functionality for single notification (#63)
Browse files Browse the repository at this point in the history
* Implement dismiss functionality for single notification

Closes Issue #20
Create a `dismiss` method while keeping the `_removeNotification` method for backward compatibilty purposes (for people who might be relying on this method)

Also add .vscode to .gitignore

* style: prettier formatting

* adjust tests

Co-authored-by: Carlos Edinson Roso Espinosa <ce.roso398@gmail.com>
  • Loading branch information
bharatramnani94 and caroso1222 authored May 8, 2020
1 parent e804159 commit 2de6f70
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 111 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ testem.log
Thumbs.db

# Cypress files
cypress/screenshots
cypress/screenshots
.vscode
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ position | [`INotyfPosition`](#inotyfposition) | `{x:'right',y:'bottom'}` | View
dismissible | `boolean` | false | Whether to allow users to dismiss the notification with a button
types | [`INotyfNotificationOptions[]`](#inotyfnotificationoptions) | Success and error toasts | Array with individual configurations for each type of toast

### `dismiss(notification: NotyfNotification)`

Dismiss a specific notification.

```javascript
const notyf = new Notyf();
const notification = notyf.success('Address updated');
notyf.dismiss(notification);
```

### `dismissAll()`

Dismiss all the active notifications.
Expand Down
82 changes: 44 additions & 38 deletions cypress/integration/notyf_spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/// <reference types="Cypress" />

context('Notyf', () => {

function init(config) {
if (config) {
typeCode(config);
Expand All @@ -10,7 +9,7 @@ context('Notyf', () => {
}

function typeCode(obj) {
cy.get('#code').type(JSON.stringify(obj).replace(new RegExp('{', 'g'), '{{}'), {delay: 0});
cy.get('#code').type(JSON.stringify(obj).replace(new RegExp('{', 'g'), '{{}'), { delay: 0 });
}

const VIEWPORT_WIDTH = 800;
Expand Down Expand Up @@ -45,13 +44,12 @@ context('Notyf', () => {

it('should position the notification at the bottom right by default.', () => {
cy.get('#success-btn').click();
cy.get('.notyf__toast').then(button => {
cy.get('.notyf__toast').then((button) => {
const pos = button.position();
expect(pos.left).to.be.greaterThan(VIEWPORT_WIDTH/2)
expect(pos.top).to.be.greaterThan(VIEWPORT_HEIGHT/2)
expect(pos.left).to.be.greaterThan(VIEWPORT_WIDTH / 2);
expect(pos.top).to.be.greaterThan(VIEWPORT_HEIGHT / 2);
});
});

});

describe('Global custom configuration', () => {
Expand All @@ -78,7 +76,7 @@ context('Notyf', () => {
init(config);
cy.get('#error-btn').click();
cy.get('.notyf__dismiss-btn').should('exist').click();
cy.wait(duration/2); // if the notification was dismissed, then it should disappear before duration elapsed
cy.wait(duration / 2); // if the notification was dismissed, then it should disappear before duration elapsed
cy.get('.notyf__toast', { timeout: 10 }).should('not.exist');
});

Expand All @@ -92,63 +90,62 @@ context('Notyf', () => {
});

describe('Positioning', () => {

function openAt({x, y}) {
function openAt({ x, y }) {
const config = { position: { x, y } };
init(config);
cy.get('#success-btn').click();
}

it('should position the notification at the top left', () => {
openAt({ x: 'left', y: 'top' });
cy.get('.notyf__toast').then(button => {
cy.get('.notyf__toast').then((button) => {
const { left, top } = button.position();
expect(left).to.be.lessThan(VIEWPORT_WIDTH / 2)
expect(top).to.be.lessThan(VIEWPORT_HEIGHT / 2)
expect(left).to.be.lessThan(VIEWPORT_WIDTH / 2);
expect(top).to.be.lessThan(VIEWPORT_HEIGHT / 2);
});
});

it('should position the notification at the top center', () => {
openAt({ x: 'center', y: 'top' });
cy.get('.notyf__toast').then(button => {
cy.get('.notyf__toast').then((button) => {
const { left, top } = button.position();
expect(top).to.be.lessThan(VIEWPORT_HEIGHT / 2);
expect(left).to.be.lessThan(VIEWPORT_WIDTH / 2);
expect(left + button.width()).to.be.greaterThan(VIEWPORT_WIDTH / 2);
});
});

it('should position the notification at the top right', () => {
openAt({ x: 'right', y: 'top' });
cy.get('.notyf__toast').then(button => {
cy.get('.notyf__toast').then((button) => {
const { left, top } = button.position();
expect(top).to.be.lessThan(VIEWPORT_HEIGHT / 2);
expect(left).to.be.greaterThan(VIEWPORT_WIDTH / 2);
});
});

it('should position the notification at the bottom left', () => {
openAt({ x: 'left', y: 'bottom' });
cy.get('.notyf__toast').then(button => {
cy.get('.notyf__toast').then((button) => {
const { left, top } = button.position();
expect(top).to.be.greaterThan(VIEWPORT_HEIGHT / 2);
expect(left).to.be.lessThan(VIEWPORT_WIDTH / 2);
});
});

it('should position the notification at the bottom center', () => {
openAt({ x: 'center', y: 'bottom' });
cy.get('.notyf__toast').then(button => {
cy.get('.notyf__toast').then((button) => {
const { left, top } = button.position();
expect(top).to.be.greaterThan(VIEWPORT_HEIGHT / 2);
expect(left).to.be.lessThan(VIEWPORT_WIDTH / 2);
expect(left + button.width()).to.be.greaterThan(VIEWPORT_WIDTH / 2);
});
});

it('should position the notification at the bottom right', () => {
openAt({ x: 'right', y: 'bottom' });
cy.get('.notyf__toast').then(button => {
cy.get('.notyf__toast').then((button) => {
const { left, top } = button.position();
expect(top).to.be.greaterThan(VIEWPORT_HEIGHT / 2);
expect(left).to.be.greaterThan(VIEWPORT_WIDTH / 2);
Expand All @@ -168,9 +165,9 @@ context('Notyf', () => {
icon: {
className: 'custom-icon',
},
ripple: false
}
]
ripple: false,
},
],
};
init(config);
cy.get('#custom-id').type('warning');
Expand Down Expand Up @@ -204,7 +201,7 @@ context('Notyf', () => {
cy.get('.notyf__toast').then(([elem]) => {
expect(elem.style.backgroundColor).to.equal('orange');
});
})
});
});

describe('Overwriting configuration of existing types', () => {
Expand All @@ -217,10 +214,10 @@ context('Notyf', () => {
icon: {
className: 'custom-error-icon',
tagName: 'span',
text: 'fail icon'
text: 'fail icon',
},
}
]
},
],
};
init(config);
cy.get('#custom-id').type('warning');
Expand Down Expand Up @@ -291,7 +288,7 @@ context('Notyf', () => {
const config = { duration };
typeCode(config);
cy.get('#success-btn').click();
cy.get('.notyf__toast', { timeout: 10 })
cy.get('.notyf__toast', { timeout: 10 });
cy.wait(duration + 1500); // we need to account roughly 1500ms for the css animations to finish
cy.get('.notyf__toast').should('not.exist');
});
Expand Down Expand Up @@ -352,10 +349,7 @@ context('Notyf', () => {
const config = { icon };
typeCode(config);
cy.get('#success-btn').click();
cy.get('.notyf__icon')
.find(tagName)
.should('have.class', className)
.should('have.text', text);
cy.get('.notyf__icon').find(tagName).should('have.class', className).should('have.text', text);
});

it('should allow the notification to be dismissed manually', () => {
Expand All @@ -364,17 +358,29 @@ context('Notyf', () => {
typeCode(config);
cy.get('#success-btn').click();
cy.get('.notyf__dismiss-btn').should('exist').click();
cy.wait(duration/2); // if the notification was dismissed, then it should disappear before duration elapsed
cy.wait(duration / 2); // if the notification was dismissed, then it should disappear before duration elapsed
cy.get('.notyf__toast', { timeout: 10 }).should('not.exist');
});
});

describe('Public API', () => {

it('should dismiss one notification', () => {
const duration = 0; // Infinite duration so that dismissing manually can be verified
const config = { duration };
init(config);
cy.get('#success-btn').click();
cy.get('.notyf__toast').should('have.length', 1);

cy.get('#dismiss-idx').type('0');
cy.get('#dismiss-btn').click();
cy.wait(1500); // we need to account roughly 1500ms for the css animations to finish
cy.get('.notyf__toast', { timeout: 10 }).should('not.exist');
});

it('should dismiss all notifications', () => {
init();
const NUM_TOASTS = 5;
for (let i = 0; i< NUM_TOASTS; i++) {
for (let i = 0; i < NUM_TOASTS; i++) {
cy.get('#success-btn').click();
}
cy.get('.notyf__toast').should('have.length', NUM_TOASTS);
Expand Down
6 changes: 6 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
<button id="error-btn" type="button">Error</button>
<button id="custom-btn" type="button">Custom</button>
<button id="dismiss-all-btn" type="button">Dismiss All</button>
<br>
<div style="display: flex;">
<input type="text" id="dismiss-idx" placeholder="Notification index">
<button id="dismiss-btn" type="button">Dismiss</button>
</div>

<br>
<label>Message</label>
<input type="text" id="message">
Expand Down
63 changes: 36 additions & 27 deletions demo/scripts/script-test.js
Original file line number Diff line number Diff line change
@@ -1,58 +1,67 @@
var notyf;
var notyfNotifications = [];

document.getElementById('success-btn')
.addEventListener('click', function(){
show('success');
});
document.getElementById('success-btn').addEventListener('click', function () {
show('success');
});

document.getElementById('error-btn')
.addEventListener('click', function(){
show('error');
});
document.getElementById('error-btn').addEventListener('click', function () {
show('error');
});

document.getElementById('dismiss-all-btn')
.addEventListener('click', function(){
dismissAll();
});
document.getElementById('dismiss-all-btn').addEventListener('click', function () {
dismissAll();
});

document.getElementById('custom-btn')
.addEventListener('click', function(){
const customId = document.getElementById('custom-id').value;
show(customId);
});
document.getElementById('custom-btn').addEventListener('click', function () {
const customId = document.getElementById('custom-id').value;
show(customId);
});

document.getElementById('init-btn')
.addEventListener('click', function(){
init();
});
document.getElementById('init-btn').addEventListener('click', function () {
init();
});

document.getElementById('dismiss-btn').addEventListener('click', function () {
const idx = document.getElementById('dismiss-idx').value;
dismiss(idx);
});

function init() {
if (notyf) {
try {
try {
document.querySelector('.notyf-announcer').remove();
document.querySelector('.notyf').remove();
} catch(e) {}
} catch (e) {}
}
const code = JSON.parse(document.getElementById('code').value || '{}');
notyf = new Notyf(code);
}

function dismiss(idx) {
notyf.dismiss(notyfNotifications[idx]);
notyfNotifications.splice(idx, 1);
}

function dismissAll() {
notyf.dismissAll();
notyfNotifications.length = 0;
}

function show(type) {
const message = document.getElementById('message').value;
const options = JSON.parse(document.getElementById('code').value || '{}');
let input = message || options;
let notification;
// if message is non null then call notyf with the message
// otherwise open the notyf with the config object
if (type === 'success') {
notyf.success(input);
notification = notyf.success(input);
} else if (type === 'error') {
notyf.error(input);
notification = notyf.error(input);
} else {
const opts = Object.assign({}, {type}, {message: input});
notyf.open(opts);
const opts = Object.assign({}, { type }, { message: input });
notification = notyf.open(opts);
}
notyfNotifications.push(notification);
}
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
"typescript": "^3.8.3",
"webpack": "4.5.0"
},
"prettier": {
"printWidth": 110,
"singleQuote": true,
"trailingComma": "all"
},
"repository": {
"type": "git",
"url": "https://github.com/caroso1222/notyf.git"
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import Notyf from './notyf';
export * from './notyf.models';
export * from './notyf.options';
export * from './notyf.view';
export { Notyf };
export { Notyf };
5 changes: 3 additions & 2 deletions src/notyf.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export interface IRenderedNotification {
}

export enum NotyfArrayEvent {
Add, Remove,
Add,
Remove,
}

export type NotyfArrayEventFn<T> = (elem: T, event: NotyfArrayEvent, elems: T[]) => void;
Expand All @@ -19,7 +20,7 @@ export class NotyfArray<T> {
private notifications: T[] = [];
private updateFn!: NotyfArrayEventFn<T>;

public push(elem: T) {
public push(elem: T) {
this.notifications.push(elem);
this.updateFn(elem, NotyfArrayEvent.Add, this.notifications);
}
Expand Down
Loading

0 comments on commit 2de6f70

Please sign in to comment.