├── .gitignore ├── .npmrc ├── .travis.yml ├── README.md ├── cypress.json ├── cypress ├── fixtures │ └── example.json ├── integration │ ├── page.html │ └── tiny-toast-spec.js └── support │ ├── commands.js │ └── defaults.js ├── deploy.json ├── dist ├── index.html └── tiny-toast.js ├── images └── cypress-test.png ├── index.js ├── package.json ├── tiny-toast.png └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .grunt/ 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=http://registry.npmjs.org/ 2 | save-exact=true 3 | progress=false 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | cache: 4 | directories: 5 | - node_modules 6 | notifications: 7 | email: false 8 | node_js: 9 | - '6' 10 | before_script: 11 | - npm prune 12 | - npm install -g cypress-cli 13 | script: 14 | - npm test 15 | - cypress ci 16 | after_success: 17 | - npm run semantic-release 18 | branches: 19 | except: 20 | - "/^v\\d+\\.\\d+\\.\\d+$/" 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tiny-toast 2 | > Tiny library for JavaScript only message popups 3 | 4 | [![NPM][tiny-toast-icon] ][tiny-toast-url] 5 | 6 | [![Build status][tiny-toast-ci-image] ][tiny-toast-ci-url] 7 | [![semantic-release][semantic-image] ][semantic-url] 8 | [![manpm](https://img.shields.io/badge/manpm-%E2%9C%93-3399ff.svg)](https://github.com/bahmutov/manpm) 9 | 10 | [demo](http://glebbahmutov.com/tiny-toast/) 11 | 12 | ![tiny toast screenshot](tiny-toast.png) 13 | 14 | ## Install and use 15 | 16 | `npm install tiny-toast` 17 | 18 | Include `dist/tiny-toast.js` script 19 | 20 | ```html 21 | 22 | 29 | ``` 30 | 31 | You can also use this library via [RawGit CDN](https://rawgit.com/) by grabbing the 32 | CDN path to the `https://github.com/bahmutov/tiny-toast/blob/master/dist/tiny-toast.js` or 33 | specific tag. 34 | 35 | ## Custom style 36 | 37 | You can adjust the element's CSS style by providing your own rules. Just 38 | mark them "important". 39 | 40 | ``` 41 | 47 | ``` 48 | 49 | ### Small print 50 | 51 | Author: Gleb Bahmutov © 2015 52 | 53 | * [@bahmutov](https://twitter.com/bahmutov) 54 | * [glebbahmutov.com](http://glebbahmutov.com) 55 | * [blog](http://glebbahmutov.com/blog/) 56 | 57 | License: MIT - do anything with the code, but don't blame me if it does not work. 58 | 59 | Spread the word: tweet, star on github, etc. 60 | 61 | Support: if you find any problems with this module, email / tweet / 62 | [open issue](https://github.com/bahmutov/tiny-toast/issues) on Github 63 | 64 | ## MIT License 65 | 66 | Copyright (c) 2015 Gleb Bahmutov 67 | 68 | Permission is hereby granted, free of charge, to any person 69 | obtaining a copy of this software and associated documentation 70 | files (the "Software"), to deal in the Software without 71 | restriction, including without limitation the rights to use, 72 | copy, modify, merge, publish, distribute, sublicense, and/or sell 73 | copies of the Software, and to permit persons to whom the 74 | Software is furnished to do so, subject to the following 75 | conditions: 76 | 77 | The above copyright notice and this permission notice shall be 78 | included in all copies or substantial portions of the Software. 79 | 80 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 81 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 82 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 83 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 84 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 85 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 86 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 87 | OTHER DEALINGS IN THE SOFTWARE. 88 | 89 | [tiny-toast-icon]: https://nodei.co/npm/tiny-toast.svg?downloads=true 90 | [tiny-toast-url]: https://npmjs.org/package/tiny-toast 91 | [tiny-toast-ci-image]: https://travis-ci.org/bahmutov/tiny-toast.svg?branch=master 92 | [tiny-toast-ci-url]: https://travis-ci.org/bahmutov/tiny-toast 93 | [semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg 94 | [semantic-url]: https://github.com/semantic-release/semantic-release 95 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectId": "c7215ca8-b515-4281-8178-ed21402c9a34" 3 | } 4 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /cypress/integration/page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Tiny toast test page 5 | 6 | 7 | 8 |

Tiny toast test page

9 | 10 | 11 | -------------------------------------------------------------------------------- /cypress/integration/tiny-toast-spec.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, beforeEach, cy, Cypress, expect */ 2 | describe('tiny toast', () => { 3 | it('works', () => { 4 | expect(true).to.be.true 5 | }) 6 | 7 | it('opens dist page as file', () => { 8 | cy.visit('dist/index.html') 9 | }) 10 | 11 | it('opens simple test page', () => { 12 | cy.visit('cypress/integration/page.html') 13 | }) 14 | 15 | describe('shows and hides fluent API', () => { 16 | beforeEach(() => { 17 | cy.visit('cypress/integration/page.html') 18 | }) 19 | 20 | it('has tinyToast api', () => { 21 | cy 22 | .window().should('have.property', 'tinyToast') 23 | .window().then((w) => w.tinyToast) 24 | .then((tinyToast) => { 25 | expect(tinyToast).to.be.a('object') 26 | expect(tinyToast.show).to.be.a('function') 27 | expect(tinyToast.hide).to.be.a('function') 28 | }) 29 | }) 30 | 31 | it('gets tinyToast using _', () => { 32 | cy 33 | .window().then(Cypress._.property('tinyToast')) 34 | .then((tinyToast) => { 35 | expect(tinyToast).to.be.a('object') 36 | expect(tinyToast.show).to.be.a('function') 37 | expect(tinyToast.hide).to.be.a('function') 38 | }) 39 | }) 40 | 41 | it('does not exist by default', () => { 42 | cy.get('h3').should('not.exist') 43 | }) 44 | 45 | it('can show and hide message', () => { 46 | cy 47 | .window().then((w) => w.tinyToast) 48 | .then((tinyToast) => { 49 | tinyToast.show('test message') 50 | }) 51 | .contains('h3', 'test message').should('be.visible') 52 | .window().then((w) => w.tinyToast) 53 | .then((tinyToast) => { 54 | tinyToast.hide() 55 | }) 56 | .contains('h3', 'test message').should('not.be.visible') 57 | }) 58 | 59 | it('can show and hide message with fluent api', () => { 60 | cy 61 | .window().then((w) => w.tinyToast) 62 | .then((tinyToast) => { 63 | tinyToast.show('test message').hide(2000) 64 | }) 65 | .contains('h3', 'test message').should('be.visible') 66 | .get('h3').should('not.exist') // will automatically wait up to 10 seconds 67 | }) 68 | }) 69 | }) 70 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create the custom command: 'login'. 4 | // 5 | // The commands.js file is a great place to 6 | // modify existing commands and create custom 7 | // commands for use throughout your tests. 8 | // 9 | // You can read more about custom commands here: 10 | // https://on.cypress.io/api/commands 11 | // *********************************************** 12 | // 13 | // Cypress.addParentCommand("login", function(email, password){ 14 | // var email = email || "joe@example.com" 15 | // var password = password || "foobar" 16 | // 17 | // var log = Cypress.Log.command({ 18 | // name: "login", 19 | // message: [email, password], 20 | // onConsole: function(){ 21 | // return { 22 | // email: email, 23 | // password: password 24 | // } 25 | // } 26 | // }) 27 | // 28 | // cy 29 | // .visit("/login", {log: false}) 30 | // .contains("Log In", {log: false}) 31 | // .get("#email", {log: false}).type(email, {log: false}) 32 | // .get("#password", {log: false}).type(password, {log: false}) 33 | // .get("button", {log: false}).click({log: false}) //this should submit the form 34 | // .get("h1", {log: false}).contains("Dashboard", {log: false}) //we should be on the dashboard now 35 | // .url({log: false}).should("match", /dashboard/, {log: false}) 36 | // .then(function(){ 37 | // log.snapshot().end() 38 | // }) 39 | // }) -------------------------------------------------------------------------------- /cypress/support/defaults.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example defaults.js shows you how to 3 | // customize the internal behavior of Cypress. 4 | // 5 | // The defaults.js file is a great place to 6 | // override defaults used throughout all tests. 7 | // 8 | // *********************************************** 9 | // 10 | // Cypress.Server.defaults({ 11 | // delay: 500, 12 | // whitelist: function(xhr){} 13 | // }) 14 | 15 | // Cypress.Cookies.defaults({ 16 | // whitelist: ["session_id", "remember_token"] 17 | // }) -------------------------------------------------------------------------------- /deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "gh-pages": { 3 | "options": { 4 | "base": "dist" 5 | }, 6 | "src": [ 7 | "index.html", 8 | "*.js" 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Tiny toast demo 5 | 6 | 7 | 13 | 14 | 15 | 16 | 17 |

Tiny toast demo

18 |

19 | Tiny JavaScript only popup messages. 20 |

Install and use

21 |
npm install --save tiny-toast
22 |

Example

23 |
tinyToast.show('Hello from tiny toast')
24 | // timeout (ms) is optional
25 | tinyToast.hide(2000)
26 |

27 |

Repo bahmutov/tiny-toast

28 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /dist/tiny-toast.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(); 4 | else if(typeof define === 'function' && define.amd) 5 | define([], factory); 6 | else if(typeof exports === 'object') 7 | exports["tinyToast"] = factory(); 8 | else 9 | root["tinyToast"] = factory(); 10 | })(this, function() { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) 20 | /******/ return installedModules[moduleId].exports; 21 | 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ exports: {}, 25 | /******/ id: moduleId, 26 | /******/ loaded: false 27 | /******/ }; 28 | 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | 32 | /******/ // Flag the module as loaded 33 | /******/ module.loaded = true; 34 | 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | 39 | 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | 46 | /******/ // __webpack_public_path__ 47 | /******/ __webpack_require__.p = ""; 48 | 49 | /******/ // Load entry module and return exports 50 | /******/ return __webpack_require__(0); 51 | /******/ }) 52 | /************************************************************************/ 53 | /******/ ([ 54 | /* 0 */ 55 | /***/ function(module, exports) { 56 | 57 | 'use strict' 58 | 59 | var tinyToast 60 | 61 | function createCssStyleSheet () { 62 | // code taken from 63 | // https://davidwalsh.name/add-rules-stylesheets 64 | const style = document.createElement('style') 65 | // WebKit hack :( 66 | // style.appendChild(document.createTextNode('')) 67 | document.head.appendChild(style) 68 | return style.sheet 69 | } 70 | 71 | function insertStyle (className, sheet, style) { 72 | // insert a rule for each style property 73 | Object.keys(style).forEach((key) => { 74 | const value = style[key] 75 | sheet.insertRule(`.${className} { ${key}: ${value} }`, 0) 76 | }) 77 | } 78 | 79 | function createTinyToastStyle () { 80 | const className = 'tinyToast' 81 | const style = { 82 | color: '#333', 83 | position: 'fixed', 84 | bottom: '0em', 85 | right: '1em', 86 | 'background-color': '#7FFFD4', 87 | 'border-radius': '5px', 88 | 'border-width': '1px', 89 | 'border-color': '#73E1BC', 90 | 'border-style': 'solid', 91 | padding: '1em 2em', 92 | 'z-index': 1000 93 | } 94 | 95 | const sheet = createCssStyleSheet() 96 | insertStyle(className, sheet, style) 97 | return className 98 | } 99 | 100 | function createDom () { 101 | if (tinyToast) { 102 | return tinyToast 103 | } 104 | 105 | const className = createTinyToastStyle() 106 | 107 | tinyToast = document.createElement('h3') 108 | tinyToast.classList.add(className) 109 | document.body.appendChild(tinyToast) 110 | return tinyToast 111 | } 112 | 113 | function createMessage (text) { 114 | createDom().textContent = text 115 | } 116 | 117 | function closeMessage () { 118 | if (tinyToast) { 119 | document.body.removeChild(tinyToast) 120 | tinyToast = null 121 | } 122 | } 123 | 124 | function maybeDefer (fn, timeoutMs) { 125 | if (timeoutMs) { 126 | setTimeout(fn, timeoutMs) 127 | } else { 128 | fn() 129 | } 130 | } 131 | 132 | function hide (timeoutMs) { 133 | maybeDefer(closeMessage, timeoutMs) 134 | } 135 | 136 | var tinyToastApi = { 137 | show: function show (text) { 138 | createMessage(text) 139 | return tinyToastApi 140 | }, 141 | hide: hide 142 | } 143 | 144 | module.exports = tinyToastApi 145 | 146 | 147 | /***/ } 148 | /******/ ]) 149 | }); 150 | ; -------------------------------------------------------------------------------- /images/cypress-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahmutov/tiny-toast/8ab63c4ab8ca85aea91a0910a3af92da8e82e090/images/cypress-test.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var tinyToast 4 | 5 | function createCssStyleSheet () { 6 | // code taken from 7 | // https://davidwalsh.name/add-rules-stylesheets 8 | const style = document.createElement('style') 9 | // WebKit hack :( 10 | // style.appendChild(document.createTextNode('')) 11 | document.head.appendChild(style) 12 | return style.sheet 13 | } 14 | 15 | function insertStyle (className, sheet, style) { 16 | // insert a rule for each style property 17 | Object.keys(style).forEach((key) => { 18 | const value = style[key] 19 | sheet.insertRule(`.${className} { ${key}: ${value} }`, 0) 20 | }) 21 | } 22 | 23 | function createTinyToastStyle () { 24 | const className = 'tinyToast' 25 | const style = { 26 | color: '#333', 27 | position: 'fixed', 28 | bottom: '0em', 29 | right: '1em', 30 | 'background-color': '#7FFFD4', 31 | 'border-radius': '5px', 32 | 'border-width': '1px', 33 | 'border-color': '#73E1BC', 34 | 'border-style': 'solid', 35 | padding: '1em 2em', 36 | 'z-index': 1000 37 | } 38 | 39 | const sheet = createCssStyleSheet() 40 | insertStyle(className, sheet, style) 41 | return className 42 | } 43 | 44 | function createDom () { 45 | if (tinyToast) { 46 | return tinyToast 47 | } 48 | 49 | const className = createTinyToastStyle() 50 | 51 | tinyToast = document.createElement('h3') 52 | tinyToast.classList.add(className) 53 | document.body.appendChild(tinyToast) 54 | return tinyToast 55 | } 56 | 57 | function createMessage (text) { 58 | createDom().textContent = text 59 | } 60 | 61 | function closeMessage () { 62 | if (tinyToast) { 63 | document.body.removeChild(tinyToast) 64 | tinyToast = null 65 | } 66 | } 67 | 68 | function maybeDefer (fn, timeoutMs) { 69 | if (timeoutMs) { 70 | setTimeout(fn, timeoutMs) 71 | } else { 72 | fn() 73 | } 74 | } 75 | 76 | function hide (timeoutMs) { 77 | maybeDefer(closeMessage, timeoutMs) 78 | } 79 | 80 | var tinyToastApi = { 81 | show: function show (text) { 82 | createMessage(text) 83 | return tinyToastApi 84 | }, 85 | hide: hide 86 | } 87 | 88 | module.exports = tinyToastApi 89 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiny-toast", 3 | "description": "Tiny library for JavaScript only message popups", 4 | "version": "0.0.0-semantic-release", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "npm run lint", 8 | "lint": "standard --verbose --fix *.js cypress/integration/*.js", 9 | "commit": "commit-wizard", 10 | "build": "webpack --verbose", 11 | "semantic-release": "semantic-release pre && npm publish && semantic-release post", 12 | "deploy": "grunty grunt-gh-pages gh-pages deploy.json", 13 | "size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";", 14 | "issues": "git-issues" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/bahmutov/tiny-toast.git" 19 | }, 20 | "files": [ 21 | "index.js", 22 | "dist" 23 | ], 24 | "keywords": [ 25 | "message", 26 | "popup", 27 | "alert", 28 | "javascript", 29 | "micro", 30 | "tiny", 31 | "ui" 32 | ], 33 | "author": "Gleb Bahmutov ", 34 | "license": "MIT", 35 | "bugs": { 36 | "url": "https://github.com/bahmutov/tiny-toast/issues" 37 | }, 38 | "homepage": "https://github.com/bahmutov/tiny-toast#readme", 39 | "devDependencies": { 40 | "git-issues": "1.3.1", 41 | "grunt": "0.4.5", 42 | "grunt-gh-pages": "1.0.0", 43 | "grunty": "0.3.0", 44 | "pre-git": "3.11.1", 45 | "semantic-release": "^4.3.5", 46 | "standard": "8.5.0", 47 | "webpack": "1.12.9" 48 | }, 49 | "config": { 50 | "pre-git": { 51 | "commit-msg": [ 52 | "simple" 53 | ], 54 | "pre-commit": [ 55 | "npm run lint", 56 | "npm run test" 57 | ], 58 | "pre-push": [ 59 | "npm run size" 60 | ], 61 | "post-commit": [], 62 | "post-merge": [] 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tiny-toast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahmutov/tiny-toast/8ab63c4ab8ca85aea91a0910a3af92da8e82e090/tiny-toast.png -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | output: { 3 | library: 'tinyToast', 4 | libraryTarget: 'umd', 5 | path: './dist', 6 | filename: 'tiny-toast.js' 7 | }, 8 | entry: { 9 | library: './index' 10 | } 11 | } 12 | --------------------------------------------------------------------------------