Skip to content

Commit

Permalink
Add first version
Browse files Browse the repository at this point in the history
  • Loading branch information
jprodrigues70 committed Oct 20, 2020
0 parents commit 403f8cd
Show file tree
Hide file tree
Showing 17 changed files with 635 additions and 0 deletions.
59 changes: 59 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# http://git-scm.com/docs/gitignore

# different IDEs
.idea
.project
*.sublime-*
.brackets.json
.vscode

# logs and cache
/logs/
*.log
npm-debug.log*
.sass-cache
.cache
.php_cs.cache

# OS generated files
[Tt]humbs.db
ehthumbs.db
*~
.*~
._*
*.bak
*.save
*.swp

# Recycle bin folder used by different os
.Trash-*
$RECYCLE.BIN/

# Windows shortcuts
*.lnk

# Folder config file
[Dd]esktop.ini
*.DS_Store
.DS_Store?

# node packages
node_modules/

# Composer, exclude on root vendor folder
/vendor/
composer.phar

# Security tokens
*.pem
*.pub
*.crt
*.key

# Project related
*.tgz
/dist/
/demo/
/docs/
/tmp/
/coverage/
97 changes: 97 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Vue Toaster

Vue.js toast notification plugin for vue 3

## Installation
```bash
# yarn
yarn add @meforma/vue-toaster

# npm
npm install @meforma/vue-toaster
```

## Import
```js
// In you main.js
// ... considering that your app creation is here
import Toaster from '@meforma/vue-toaster';

createApp(App).use(Toaster).mount('#app')
```

## Usage
```js
// this.$toast.show(message, {/* options */});
this.$toast.show('You did it!');
this.$toast.success('You did it!');
this.$toast.error('You did it!');
this.$toast.warning('You did it!');
this.$toast.info('You did it!');

// Close all opened toast after 3000ms
setTimeout(this.$toast.clear, 3000)

```

## Available options
The API methods accepts these options:

| Attribute | Type | Default | Description |
| :--- | :---: | :---: | :--- |
| message | String | -- | Message text/html (required) |
| type | String | `default` | One of `success`, `info`, `warning`, `error`, `default` |
| position | String | `bottom-right` | One of `top`, `bottom`, `top-right`, `bottom-right`,`top-left`, `bottom-left` |
| duration | Number | `4000` | Visibility duration in milliseconds |
| dismissible | Boolean | `true` | Allow user close by clicking |
| onClick | Function | -- | Do something when user clicks |
| onClose | Function | -- | Do something after toast gets dismissed |
| queue | Boolean | `false` | Wait for existing to close before showing new |
| pauseOnHover | Boolean | `true` | Pause the timer when mouse on over a toast |
| useDefaultCss | Boolean | `true` | User default css styles |

## API methods
### `show(message, ?options)`
This is generic method, you can use this method to make any kind of toast.
```js
// Can accept a message as string and apply rest of options from defaults
this.$toast.show('Howdy!');

// Can accept an Object of options.
// If yout don't pass options, the default toast will be showed
this.$toast.show('Something went wrong!', {
type: 'error',
// all of other options may go here
});
```

### `success(message,?options)`
There are some proxy methods to make it more readable. The same rule for `error`, `info` and `warning` methods
```js
this.$toast.success('Profile saved.', {
// optional options Object
})
```

## Global options
You can set options for all the instances during plugin initialization
```js
app.use(Toaster, {
// One of the options
position: 'top'
})
```

Further you can override option when creating new instances
```js
this.$toast.success('Order placed.', {
// override the global option
position: 'bottom'
})
```

## Based on
* [vue-toast-notification](https://github.com/ankurk91/vue-toast-notification) plugin

## License
[MIT](LICENSE.txt) License
29 changes: 29 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "@meforma/vue-toaster",
"version": "1.0.0",
"description": "Vue.js toaster notification",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/MeForma/vue-toaster.git"
},
"keywords": [
"toast",
"toaster",
"notification",
"vue",
"vue",
"3",
"toastify",
"toaster"
],
"author": "@jprodrigues70",
"license": "MIT",
"bugs": {
"url": "https://github.com/MeForma/vue-toaster/issues"
},
"homepage": "https://github.com/MeForma/vue-toaster#readme"
}
180 changes: 180 additions & 0 deletions src/Toaster.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
<template>
<transition
:enter-active-class="transition.enter"
:leave-active-class="transition.leave"
>
<div
v-show="isActive"
:class="['c-toast', `c-toast--${type}`, `c-toast--${position}`]"
@mouseover="toggleTimer(true)"
@mouseleave="toggleTimer(false)"
@click="click"
role="alert"
v-html="message"
/>
</transition>
</template>

<script>
import { removeElement } from './helpers/remove-element'
import Timer from './helpers/timer'
import Positions, { definePosition } from './defaults/positions'
import eventBus from './helpers/event-bus'
export default {
name: 'toast',
props: {
message: {
type: String,
required: true
},
type: {
type: String,
default: 'default'
},
position: {
type: String,
default: Positions.BOTTOM_RIGHT,
validator(value) {
return Object.values(Positions).includes(value)
}
},
duration: {
type: Number,
default: 4000
},
dismissible: {
type: Boolean,
default: true
},
queue: {
type: Boolean,
default: false
},
pauseOnHover: {
type: Boolean,
default: true
},
useDefaultCss: {
type: Boolean,
default: true
},
onClose: {
type: Function,
default: () => {}
},
onClick: {
type: Function,
default: () => {}
}
},
data() {
return {
isActive: false,
parentTop: null,
parentBottom: null,
isHovered: false
}
},
beforeMount() {
this.createParents()
this.setupContainer()
},
mounted() {
this.showNotice()
if (this.useDefaultCss) {
require('./themes/default/index.styl')
}
eventBus.$on('toast-clear', this.close)
},
methods: {
createParents() {
this.parentTop = document.querySelector('.c-toast-container--top')
this.parentBottom = document.querySelector('.c-toast-container--bottom')
if (this.parentTop && this.parentBottom) return
if (!this.parentTop) {
this.parentTop = document.createElement('div')
this.parentTop.className = 'c-toast-container c-toast-container--top'
}
if (!this.parentBottom) {
this.parentBottom = document.createElement('div')
this.parentBottom.className =
'c-toast-container c-toast-container--bottom'
}
},
setupContainer() {
const container = document.body
container.appendChild(this.parentTop)
container.appendChild(this.parentBottom)
},
shouldQueue() {
if (!this.queue) return false
return (
this.parentTop.childElementCount > 0 ||
this.parentBottom.childElementCount > 0
)
},
showNotice() {
if (this.shouldQueue()) {
this.queueTimer = setTimeout(this.showNotice, 250)
return
}
this.correctParent.insertAdjacentElement('afterbegin', this.$el)
this.isActive = true
this.timer = new Timer(this.close, this.duration)
},
click() {
if (this.dismissible) {
this.onClick.apply(null, arguments)
this.close()
}
},
toggleTimer(newVal) {
if (this.pauseOnHover) {
newVal ? this.timer.pause() : this.timer.resume()
}
},
stopTimer() {
this.timer.stop()
clearTimeout(this.queueTimer)
},
close() {
this.stopTimer()
this.isActive = false
setTimeout(() => {
this.onClose.apply(null, arguments)
removeElement(this.$el)
}, 150)
}
},
computed: {
correctParent() {
return definePosition(this.position, this.parentTop, this.parentBottom)
},
transition() {
return definePosition(
this.position,
{
enter: 'fadeInDown',
leave: 'fadeOut'
},
{
enter: 'fadeInUp',
leave: 'fadeOut'
}
)
}
},
beforeUnmount() {
eventBus.$off('toast-clear', this.close)
}
}
</script>
Loading

0 comments on commit 403f8cd

Please sign in to comment.