├── testem.yml
├── .gitignore
├── .travis.yml
├── .flowconfig
├── flow
├── lib.js
└── type.js
├── .eslintrc.yml
├── examples
├── basic
│ ├── main.js
│ ├── js
│ │ ├── store.js
│ │ └── App.vue
│ ├── index.html
│ └── main.scss
└── webpack.config.js
├── src
├── config.js
├── utils.js
├── index.js
├── module.js
└── Toast.vue
├── .babelrc
├── LICENSE
├── rollup.config.js
├── package.json
└── README.md
/testem.yml:
--------------------------------------------------------------------------------
1 | ---
2 | framework: mocha
3 | src_files:
4 | - .tmp/test.js
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
3 | /dist/
4 | /examples/*/__build__.js
5 | /.tmp/
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "6"
4 | script:
5 | - npm run test
6 | - npm run build
7 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | .*/node_modules/
3 |
4 | [include]
5 |
6 | [libs]
7 | flow
8 |
9 | [options]
10 | module.file_ext=.js
11 | module.file_ext=.vue
12 |
--------------------------------------------------------------------------------
/flow/lib.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | declare module vue {
4 | declare module.exports: any;
5 | }
6 |
7 | declare module vuex {
8 | declare module.exports: any;
9 | }
10 |
--------------------------------------------------------------------------------
/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | ---
2 | extends: eslint-config-ktsn
3 | parser: babel-eslint
4 | plugins:
5 | - html
6 | - flowtype
7 | rules:
8 | flowtype/define-flow-type: 1
9 | flowtype/use-flow-type: 1
10 |
--------------------------------------------------------------------------------
/examples/basic/main.js:
--------------------------------------------------------------------------------
1 | import './main.scss'
2 |
3 | import Vue from 'vue'
4 |
5 | import store from './js/store'
6 | import App from './js/App'
7 |
8 | new Vue({
9 | el: '#app',
10 | store,
11 | render: h => h(App)
12 | })
13 |
--------------------------------------------------------------------------------
/examples/basic/js/store.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import { createModule } from 'vuex-toast'
4 |
5 | Vue.use(Vuex)
6 |
7 | export default new Vuex.Store({
8 | modules: {
9 | toast: createModule()
10 | }
11 | })
12 |
--------------------------------------------------------------------------------
/examples/basic/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Vuex Toast basic example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 | export const DefaultTransition = {
2 | functional: true,
3 | render(h, { children }) {
4 | const data = {
5 | attrs: { tag: 'div', name: 'toast', type: 'transition' }
6 | }
7 | return h('transition-group', data, children)
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["es2015", { "modules": false }]
4 | ],
5 | "plugins": [
6 | "transform-flow-strip-types",
7 | "transform-object-rest-spread"
8 | ],
9 | "env": {
10 | "test": {
11 | "presets": ["power-assert"]
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/flow/type.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | interface ToastMessage {
4 | id: number;
5 | text: string;
6 | type: string;
7 | dismissAfter: number;
8 | }
9 |
10 | interface ToastState {
11 | messages: ToastMessage[];
12 | }
13 |
14 | interface ToastOptions {
15 | dismissInterval?: number;
16 | }
17 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | /**
4 | * Simple update without mutation
5 | */
6 | export function update(obj: Object, updater: Object): Object {
7 | const res = {}
8 | Object.keys(obj).forEach(key => {
9 | res[key] = updater[key] === undefined ? obj[key] : updater[key]
10 | })
11 | return res
12 | }
13 |
--------------------------------------------------------------------------------
/examples/basic/main.scss:
--------------------------------------------------------------------------------
1 | @charset 'utf-8';
2 |
3 | * {
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | background-color: #caf0f5;
9 | }
10 |
11 | body,
12 | input,
13 | select {
14 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
15 | font-weight: 300;
16 | }
17 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import Toast from './Toast.vue'
4 | import { update } from './utils'
5 |
6 | export function createComponent(options = {}) {
7 | const {
8 | transition
9 | } = options
10 |
11 | return update(Toast, {
12 | components: {
13 | toastTransition: transition
14 | }
15 | })
16 | }
17 |
18 | export { Toast }
19 | export * from './module'
20 |
--------------------------------------------------------------------------------
/examples/webpack.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | const path = require('path')
3 |
4 | module.exports = {
5 | entry: createEntry(['basic']),
6 | output: {
7 | path: __dirname,
8 | filename: '[name]/__build__.js'
9 | },
10 | resolve: {
11 | alias: {
12 | 'vuex-toast': path.resolve(__dirname, '../src/index.js')
13 | },
14 | extensions: ['.js', '.vue']
15 | },
16 | module: {
17 | rules: [
18 | { enforce: 'pre', test: /\.scss$/, loader: 'sass-loader' },
19 | { test: /\.vue$/, loader: 'vue-loader', options: {
20 | loaders: {
21 | scss: 'style-loader!css-loader!sass-loader'
22 | }
23 | }},
24 | { test: /\.s?css$/, loader: 'style-loader!css-loader' },
25 | { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }
26 | ]
27 | }
28 | }
29 |
30 | function createEntry(names) {
31 | const res = {}
32 | names.forEach(name => {
33 | res[name] = `./${name}/main.js`
34 | })
35 | return res
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 katashin
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/src/module.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | const PREFIX = '@@toast/'
4 |
5 | const ADD = `${PREFIX}ADD_TOAST_MESSAGE`
6 | const REMOVE = `${PREFIX}REMOVE_TOAST_MESSAGE`
7 |
8 | export {
9 | ADD as ADD_TOAST_MESSAGE,
10 | REMOVE as REMOVE_TOAST_MESSAGE
11 | }
12 |
13 | function createMessage(id: number, text: string, type: string, dismissAfter: number): ToastMessage {
14 | return {
15 | id,
16 | text,
17 | type,
18 | dismissAfter
19 | }
20 | }
21 |
22 | export function createModule(options: ToastOptions = {}) {
23 | const {
24 | dismissInterval = 5000
25 | } = options
26 |
27 | let maxToastId = 0
28 |
29 | const state: ToastState = {
30 | messages: []
31 | }
32 |
33 | const getters = {
34 | toastMessages: (state: ToastState) => state.messages
35 | }
36 |
37 | const actions = {
38 | [ADD] ({ commit }, { text, type = 'info', dismissAfter = dismissInterval }) {
39 | const id = ++maxToastId
40 |
41 | commit(ADD, createMessage(id, text, type, dismissAfter))
42 | setTimeout(() => commit(REMOVE, id), dismissAfter)
43 | },
44 |
45 | [REMOVE] ({ commit }, id) {
46 | commit(REMOVE, id)
47 | }
48 | }
49 |
50 | const mutations = {
51 | [ADD] (state: ToastState, data: ToastMessage) {
52 | state.messages.push(data)
53 | },
54 |
55 | [REMOVE] (state: ToastState, id: number) {
56 | state.messages = state.messages.filter(m => m.id !== id)
57 | }
58 | }
59 |
60 | return {
61 | state,
62 | getters,
63 | actions,
64 | mutations
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console: 0 */
2 | const fs = require('fs')
3 | const path = require('path')
4 | const babel = require('rollup-plugin-babel')
5 | const vue = require('rollup-plugin-vue')
6 | const replace = require('rollup-plugin-replace')
7 | const sass = require('node-sass')
8 | const autoprefixer = require('autoprefixer')
9 | const postcss = require('postcss')
10 | const meta = require('./package.json')
11 |
12 | if (!fs.existsSync('dist')) {
13 | fs.mkdirSync('dist')
14 | }
15 |
16 | const prefixer = postcss([
17 | autoprefixer({
18 | browsers: ['> 1%', 'last 2 versions', 'IE >= 9']
19 | })
20 | ])
21 |
22 | const banner = `/*!
23 | * ${meta.name} v${meta.version}
24 | * ${meta.homepage}
25 | *
26 | * @license
27 | * Copyright (c) 2016 ${meta.author}
28 | * Released under the MIT license
29 | * ${meta.homepage}/blob/master/LICENSE
30 | */`
31 |
32 | const name = 'VuexToast'
33 |
34 | const plugins = [
35 | vue({
36 | compileTemplate: true,
37 | css: !process.env.NODE_ENV && (styles => {
38 | const out = path.resolve(__dirname, './dist/vuex-toast.css')
39 |
40 | // compile scss
41 | sass.render({
42 | data: styles,
43 | outputStyle: 'expanded',
44 | outFile: out
45 | }, (error, result) => {
46 | if (error) {
47 | console.error(formatSassError(error))
48 | return
49 | }
50 |
51 | // autoprefixer
52 | prefixer.process(result.css, { from: undefined }).then(result => {
53 | result.warnings().forEach(warn => {
54 | console.warn(warn.toString())
55 | })
56 | fs.writeFile(out, result.css)
57 | })
58 | })
59 | })
60 | }),
61 | babel({
62 | exclude: 'node_modules/**'
63 | })
64 | ]
65 | if (process.env.NODE_ENV) {
66 | plugins.push(
67 | replace({
68 | 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
69 | })
70 | )
71 | }
72 |
73 | module.exports = {
74 | input: 'src/index.js',
75 | plugins,
76 | output: {
77 | name,
78 | banner,
79 | globals: {
80 | vuex: 'Vuex'
81 | }
82 | },
83 | external: [
84 | 'vuex'
85 | ]
86 | }
87 |
88 | function formatSassError(e) {
89 | return `[${e.line}:${e.column}] ${e.message} (${e.file})`
90 | }
91 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vuex-toast",
3 | "version": "0.1.3",
4 | "author": "katashin",
5 | "description": "Simple toast notification using Vuex",
6 | "keywords": [
7 | "UI",
8 | "Flux",
9 | "Vuex",
10 | "Vue",
11 | "toast"
12 | ],
13 | "license": "MIT",
14 | "main": "dist/vuex-toast.cjs.js",
15 | "files": [
16 | "dist"
17 | ],
18 | "homepage": "https://github.com/ktsn/vuex-toast",
19 | "bugs": "https://github.com/ktsn/vuex-toast/issues",
20 | "repository": {
21 | "type": "git",
22 | "url": "https://github.com/ktsn/vuex-toast.git"
23 | },
24 | "scripts": {
25 | "prepublishOnly": "npm run flow && npm run lint && npm run build",
26 | "build": "npm run build:cjs && npm run build:dev && npm run build:prod",
27 | "build:cjs": "rollup -c rollup.config.js -f cjs -o dist/vuex-toast.cjs.js",
28 | "build:dev": "cross-env NODE_ENV=development rollup -c rollup.config.js -f umd -o dist/vuex-toast.js",
29 | "build:prod": "cross-env NODE_ENV=production rollup -c rollup.config.js -f umd | uglifyjs -mc warnings=false --comments -o dist/vuex-toast.min.js",
30 | "build:example": "cd examples && webpack",
31 | "dev:example": "cd examples && webpack-dev-server --inline --hot",
32 | "test": "npm run flow && npm run lint",
33 | "flow": "flow check",
34 | "lint": "eslint --ext .js,.vue src test flow example",
35 | "lint:fix": "npm run lint -- --fix"
36 | },
37 | "devDependencies": {
38 | "autoprefixer": "^8.0.0",
39 | "babel-core": "^6.26.0",
40 | "babel-eslint": "^8.2.1",
41 | "babel-loader": "^7.1.2",
42 | "babel-plugin-transform-flow-strip-types": "^6.22.0",
43 | "babel-plugin-transform-object-rest-spread": "^6.26.0",
44 | "babel-preset-es2015": "^6.24.1",
45 | "babel-preset-power-assert": "^2.0.0",
46 | "cross-env": "^5.1.3",
47 | "css-loader": "^0.28.9",
48 | "eslint": "^4.17.0",
49 | "eslint-config-ktsn": "^1.0.3",
50 | "eslint-plugin-flowtype": "^2.44.0",
51 | "eslint-plugin-html": "^4.0.2",
52 | "flow-bin": "^0.65.0",
53 | "node-sass": "^4.7.2",
54 | "postcss": "^6.0.18",
55 | "power-assert": "^1.4.4",
56 | "rollup": "^0.56.0",
57 | "rollup-plugin-babel": "^3.0.3",
58 | "rollup-plugin-replace": "^2.0.0",
59 | "rollup-plugin-vue": "^3.0.0",
60 | "sass-loader": "^6.0.6",
61 | "style-loader": "^0.20.2",
62 | "uglifyjs": "^2.4.11",
63 | "vue": "^2.5.13",
64 | "vue-loader": "^14.1.1",
65 | "vue-template-compiler": "^2.5.13",
66 | "vuex": "^3.0.1",
67 | "webpack": "^3.11.0",
68 | "webpack-dev-server": "^2.11.1"
69 | },
70 | "peerDependencies": {
71 | "vue": "^2.0.0",
72 | "vuex": "^2.0.0 || ^3.0.0"
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/examples/basic/js/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Vuex Toast Demo
4 |
5 |
6 |
7 |
16 |
17 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
62 |
63 |
116 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Vuex Toast
2 |
3 | Simple toast notification using Vuex
4 |
5 | ## Requirements
6 |
7 | - Vue >= 2.0
8 | - Vuex >= 2.0
9 |
10 | ## Demo
11 |
12 | http://codepen.io/ktsn/pen/Bzxkjd
13 |
14 | ## Install
15 |
16 | ```npm install vuex-toast --save```
17 |
18 |
19 | ## Example
20 |
21 | First, you should register a toast module to your Vuex store. You can use a default style at `dist/vuex-toast.css`.
22 |
23 | ```js
24 | import Vue from 'vue'
25 | import Vuex from 'vuex'
26 | import { createModule } from 'vuex-toast'
27 |
28 | // If you want to use the default style (with webpack css-loader)
29 | import 'vuex-toast/dist/vuex-toast.css'
30 |
31 | Vue.use(Vuex)
32 |
33 | export default new Vuex.Store({
34 | modules: {
35 | // ...
36 | toast: createModule({
37 | dismissInterval: 8000
38 | })
39 | // ...
40 | }
41 | })
42 | ```
43 |
44 | Put `Toast` component anywhere in your application.
45 |
46 | ```html
47 |
48 |
52 |
53 |
54 |
65 | ```
66 |
67 | You can send notifications to the toast component with toast type.
68 |
69 | ```js
70 | import { mapActions } from 'vuex'
71 | import { ADD_TOAST_MESSAGE } from 'vuex-toast'
72 |
73 | export default {
74 | methods: {
75 | ...mapActions({
76 | addToast: ADD_TOAST_MESSAGE
77 | }),
78 |
79 | sendNotification(text) {
80 | this.addToast({
81 | text,
82 | type: 'success',
83 | dismissAfter: 10000
84 | })
85 | }
86 | }
87 | }
88 | ```
89 |
90 | ## API
91 | ### `Toast`
92 | A Vue component that shows toast messages.
93 |
94 | - props
95 | - `position`
96 | - `html`
97 | - `namespace`
98 | - Vuex module's namespace if you install toast module into some namespaced module.
99 |
100 | ### `createModule(options): VuexModule`
101 | Create Vuex module for managing toast messages.
102 |
103 | - options
104 | - dismissInterval
105 |
106 | ### `createComponent(options): VueComponent`
107 | Create customized toast component.
108 |
109 | - options
110 | - transition
111 |
112 | ### Action Types
113 | - ADD_TOAST_MESSAGE
114 | - `dispatch(ADD_TOAST_MESSAGE, { text, type, dismissAfter })`
115 | - REMOVE_TOAST_MESSAGE
116 | - `dispatch(REMOVE_TOAST_MESSAGE, messageId)`
117 |
118 | ### Getters
119 | - toastMessage
120 | - get all toast messages.
121 |
122 | ### Toast Message Type
123 | - `id` Auto generated message ID
124 | - `text` Text of the toast message
125 | - `type` Type of the toast message
126 | - You can use any value for styling purpose.
127 | - There are default styles for `info`, `success`, `warning`, and `danger`
128 | - `dismissAfter` Milli-second that indicates the message dismiss after this time
129 |
130 | ## License
131 |
132 | MIT
133 |
--------------------------------------------------------------------------------
/src/Toast.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
{{ m.text }}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
74 |
75 |
206 |
--------------------------------------------------------------------------------