├── .babelrc ├── .editorconfig ├── .gitignore ├── CONTRIBUTING.md ├── Demo_Original.gif ├── Demo_Props.gif ├── LICENSE ├── README.md ├── build ├── notification-service-module.js └── notification-service.js ├── package-lock.json ├── package.json ├── src ├── notification-service-module.js ├── notification-service.js └── notification-service.template.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "env" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = tab 9 | indent_size = 4 10 | 11 | [*.md] 12 | indent_style = space 13 | indent_size = 4 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ✨ Thank you for contributing ✨ 4 | 5 | This is just guidelines. 6 | 7 | Please feel free to contribute by submitting PR's for improvements to code snippets, explanations, etc. 8 | 9 | ## Submitting an issue 10 | 11 | Found a problem? Have an enhancement? 12 | 13 | First of all see if your issue or idea has already been [reported](https://github.com/shystruk/notification-service-js/issues). 14 | 15 | If do not, open a [new one](https://github.com/shystruk/notification-service-js/issues/new). 16 | 17 | 18 | ## Submitting a pull request 19 | 20 | - Fork this repository 21 | - Clone fork `git clone ...` 22 | - Navigate to the cloned directory 23 | - Install all dependencies `npm install` 24 | - Crate a new branch for the feature `git checkout -b new-feature` 25 | - Make changes 26 | - Run webpack for making bundles `npm run build` 27 | - Commit changes `git commit -am 'What is feature about? :)'` 28 | - Push to the branch `git push origin new-feature` 29 | - Submit a PR 30 | -------------------------------------------------------------------------------- /Demo_Original.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shystruk/notification-service-js/177127be2285ef5018f56b469a4ed71920483a74/Demo_Original.gif -------------------------------------------------------------------------------- /Demo_Props.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shystruk/notification-service-js/177127be2285ef5018f56b469a4ed71920483a74/Demo_Props.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Vasyl Stokolosa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Notification Service [![Twitter URL](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?hashtags=javascript%20%23webcomponents&original_referer=https%3A%2F%2Fpublish.twitter.com%2F%3FbuttonHashtag%3Djavascript%2520%2523webcomponents%26buttonText%3DNotification%2520Service%2520based%2520on%2520Custom%2520Elements.%2520Integrate%2520everywhere.%26buttonType%3DTweetButton%26buttonUrl%3Dhttps%253A%252F%252Fgithub.com%252Fshystruk%252Fnotification-service-js%26buttonVia%3Dshystrukk%26widget%3DButton&ref_src=twsrc%5Etfw&text=Notification%20Service%20based%20on%20Custom%20Elements.%20Integrate%20everywhere.&tw_p=tweetbutton&url=https%3A%2F%2Fgithub.com%2Fshystruk%2Fnotification-service-js&via=shystrukk) # 2 | [![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/notification-service-js) [![MIT Licence](https://badges.frapsoft.com/os/mit/mit.svg?v=103)](https://opensource.org/licenses/mit-license.php) [![npm version](https://badge.fury.io/js/notification-service-js.svg)](https://badge.fury.io/js/notification-service-js) [![Known Vulnerabilities](https://snyk.io/test/github/shystruk/notification-service-js/badge.svg?targetFile=package.json)](https://snyk.io/test/github/shystruk/notification-service-js?targetFile=package.json) 3 | 4 | 5 | Notification Service provides a simple show/hide message. It is based on [CustomElements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) and may be integrated with any framework. Push notification works through [CustomEvent](https://www.npmjs.com/package/custom-event-js) dispatcher. 6 | **Notification Service supports all popular browsers, including Internet Explorer 11, although some polyfills are required for IE 11. Please see [here](https://www.webcomponents.org/polyfills).** 7 | 8 | 9 | ![](Demo_Original.gif) 10 | 11 | 12 | ## Installation ## 13 | #### npm 14 | `npm install notification-service-js` 15 | 16 | #### yarn 17 | `yarn add notification-service-js` 18 | 19 | ## Usage ## 20 | ```javascript 21 | // As a module 22 | import 'notification-service-js' 23 | 24 | // As a 26 | 27 | // Insert web component into the DOM 28 | 29 | ``` 30 | 31 | ### Push notification 32 | ```javascript 33 | CustomEvent.DISPATCH('WEB_COMP_SHOW_NOTIFICATION', { 34 | type: 'success', // success, error, warning 35 | message: 'Your message has been sent', 36 | timer: 3000 // default 5000, not required 37 | }) 38 | ``` 39 | 40 | ## Options 41 | ```javascript 42 | CustomEvent.DISPATCH('EVENT_NAME', options) 43 | ``` 44 | 45 | ### type ### 46 | Type: `string`
47 | Values: `success, error, warning`
48 | 49 | A class which will be added to the notification content `.web-nc-content.`. Depends on the class CSS styles will be applied to the content. You can add your own type and add styles through the prop `cross-img-src`. 50 | 51 | ### message ### 52 | Type: `string`
53 | 54 | Content which will be displayed inside notification. 55 | 56 | ### timer ### 57 | Type: `number`
58 | Default: 5000
59 | 60 | Time in milliseconds how long notification will be showing. 61 | 62 | 63 | ## Props 64 | ### cross-img-src ### 65 | The path to an image (png/svg/jpg) file, which will be used for a cross icon. 66 | ```html 67 | 68 | ``` 69 | 70 | ### style-src ### 71 | The path to .css file, which will be pasted after common styles. 72 | 73 | ```html 74 | 75 | ``` 76 | ![](Demo_Props.gif) 77 | 78 | ## Contributing 79 | 80 | Any contributions you make **are greatly appreciated**. 81 | 82 | Please read the [Contributions Guidelines](CONTRIBUTING.md) before submitting a PR. 83 | 84 | ## License 85 | 86 | MIT © [Vasyl Stokolosa](https://about.me/shystruk) 87 | -------------------------------------------------------------------------------- /build/notification-service-module.js: -------------------------------------------------------------------------------- 1 | !function(e){var t={};function n(o){if(t[o])return t[o].exports;var i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(o,i,function(t){return e[t]}.bind(null,i));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=2)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=document.createElement("template");o.innerHTML='\n \n\n
\n',t.default=o},function(e,t){!function(){if("function"==typeof window.CustomEvent)return;function e(e,t){var n=document.createEvent("CustomEvent");return t=t||{bubbles:!1,cancelable:!1,detail:void 0},n.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),n}e.prototype=window.Event.prototype,window.CustomEvent=e}();var n=document,o={};e.exports={on:function(e,t){o[e]=t,n.addEventListener(e,t)},off:function(e){n.removeEventListener(e,o[e]),delete o[e]},dispatch:function(e,t){!function(e,t){var o=new CustomEvent(e,{detail:t});n.dispatchEvent(o)}(e,t||null)}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(e,t){for(var n=0;n",t=this.rootNode.appendChild(n),this.crossImg){var o=document.createElement("img");o.setAttribute("src",this.crossImg),o.setAttribute("alt",""),o.addEventListener("click",function(){return t.parentNode.removeChild(t)}),t.appendChild(o)}setTimeout(function(){t.className+=" fadeout",setTimeout(function(){return t.parentNode&&t.parentNode.removeChild(t)},1200)},e.timer||5e3)}}},{key:"attachLink",value:function(){var e=document.createElement("link");e.setAttribute("rel","stylesheet"),e.setAttribute("href",this.getAttribute("style-src")),this.rootNode.parentNode.insertBefore(e,this.rootNode)}},{key:"crossImgSrc",get:function(){return this.hasAttribute("cross-img-src")}},{key:"styleSrc",get:function(){return this.hasAttribute("style-src")}}],[{key:"observedAttributes",get:function(){return["style-src","cross-img-src"]}}]),t}();t.default=customElements.define("notification-service",c)}]); -------------------------------------------------------------------------------- /build/notification-service.js: -------------------------------------------------------------------------------- 1 | !function(e){var t={};function n(o){if(t[o])return t[o].exports;var i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(o,i,function(t){return e[t]}.bind(null,i));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=3)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=document.createElement("template");o.innerHTML='\n \n\n
\n',t.default=o},function(e,t){!function(){if("function"==typeof window.CustomEvent)return;function e(e,t){var n=document.createEvent("CustomEvent");return t=t||{bubbles:!1,cancelable:!1,detail:void 0},n.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),n}e.prototype=window.Event.prototype,window.CustomEvent=e}();var n=document,o={};e.exports={on:function(e,t){o[e]=t,n.addEventListener(e,t)},off:function(e){n.removeEventListener(e,o[e]),delete o[e]},dispatch:function(e,t){!function(e,t){var o=new CustomEvent(e,{detail:t});n.dispatchEvent(o)}(e,t||null)}}},,function(e,t,n){"use strict";var o=function(){function e(e,t){for(var n=0;n",t=this.rootNode.appendChild(n),this.crossImg){var o=document.createElement("img");o.setAttribute("src",this.crossImg),o.setAttribute("alt",""),o.addEventListener("click",function(){return t.parentNode.removeChild(t)}),t.appendChild(o)}setTimeout(function(){t.className+=" fadeout",setTimeout(function(){return t.parentNode&&t.parentNode.removeChild(t)},1200)},e.timer||5e3)}}},{key:"attachLink",value:function(){var e=document.createElement("link");e.setAttribute("rel","stylesheet"),e.setAttribute("href",this.getAttribute("style-src")),this.rootNode.parentNode.insertBefore(e,this.rootNode)}},{key:"crossImgSrc",get:function(){return this.hasAttribute("cross-img-src")}},{key:"styleSrc",get:function(){return this.hasAttribute("style-src")}}],[{key:"observedAttributes",get:function(){return["style-src","cross-img-src"]}}]),t}();customElements.define("notification-service",c)}]); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "notification-service-js", 3 | "version": "0.6.3", 4 | "license": "MIT", 5 | "description": "Notification Service based on Custom Elements", 6 | "main": "./build/notification-service-module.js", 7 | "directories": { 8 | "src": "build" 9 | }, 10 | "scripts": { 11 | "build": "webpack --mode=production" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/shystruk/notification-service" 16 | }, 17 | "keywords": [ 18 | "notification", 19 | "notification service", 20 | "web component", 21 | "custom element" 22 | ], 23 | "author": { 24 | "name": "Vasyl Stokolosa", 25 | "email": "v.stokol@gmail.com", 26 | "url": "https://github.com/shystruk" 27 | }, 28 | "dependencies": { 29 | "custom-event-js": "^1.0.2" 30 | }, 31 | "devDependencies": { 32 | "babel-cli": "^6.26.0", 33 | "babel-loader": "^7.1.5", 34 | "babel-preset-env": "^1.7.0", 35 | "uglifyjs-webpack-plugin": "^1.2.7", 36 | "webpack": "^4.16.5", 37 | "webpack-cli": "^3.1.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/notification-service-module.js: -------------------------------------------------------------------------------- 1 | import template from './notification-service.template' 2 | import CustomEvent from 'custom-event-js' 3 | 4 | class Notification_Service extends HTMLElement { 5 | constructor() { 6 | super() 7 | 8 | this.attachShadow({ mode: 'open' }) 9 | this.shadowRoot.appendChild(template.content.cloneNode(true)) 10 | 11 | this.rootNode = this.shadowRoot.querySelector('.web-nc') 12 | this.crossImg = '' 13 | } 14 | 15 | connectedCallback() { 16 | CustomEvent.ON('WEB_COMP_SHOW_NOTIFICATION', (data) => { 17 | this.renderNotification(data && data.detail) 18 | }) 19 | } 20 | 21 | disconnectedCallback() { 22 | CustomEvent.OFF('WEB_COMP_SHOW_NOTIFICATION') 23 | } 24 | 25 | attributeChangedCallback(attrName, oldVal, newVal) { 26 | if (this.styleSrc) { 27 | this.attachLink() 28 | } 29 | 30 | if (this.crossImgSrc) { 31 | this.crossImg = this.getAttribute('cross-img-src') 32 | } 33 | } 34 | 35 | static get observedAttributes() { 36 | return ['style-src', 'cross-img-src'] 37 | } 38 | 39 | get crossImgSrc() { 40 | return this.hasAttribute('cross-img-src') 41 | } 42 | 43 | get styleSrc() { 44 | return this.hasAttribute('style-src') 45 | } 46 | 47 | renderNotification(data) { 48 | var divNode 49 | 50 | if (data) { 51 | var div = document.createElement('div') 52 | div.setAttribute('class', `web-nc-content fadein ${data.type}`) 53 | div.innerHTML = `${data.message}` 54 | 55 | divNode = this.rootNode.appendChild(div) 56 | 57 | if (this.crossImg) { 58 | var img = document.createElement('img') 59 | img.setAttribute('src', this.crossImg) 60 | img.setAttribute('alt', '') 61 | img.addEventListener('click', () => divNode.parentNode.removeChild(divNode)) 62 | 63 | divNode.appendChild(img) 64 | } 65 | 66 | setTimeout(() => { 67 | divNode.className += ' fadeout' 68 | setTimeout(() => divNode.parentNode && divNode.parentNode.removeChild(divNode), 1200) 69 | }, data.timer || 5000) 70 | } 71 | } 72 | 73 | attachLink() { 74 | var link = document.createElement('link') 75 | link.setAttribute('rel', 'stylesheet') 76 | link.setAttribute('href', this.getAttribute('style-src')) 77 | this.rootNode.parentNode.insertBefore(link, this.rootNode) 78 | } 79 | } 80 | 81 | export default customElements.define('notification-service', Notification_Service) 82 | -------------------------------------------------------------------------------- /src/notification-service.js: -------------------------------------------------------------------------------- 1 | import template from './notification-service.template' 2 | import CustomEvent from 'custom-event-js' 3 | 4 | class Notification_Service extends HTMLElement { 5 | constructor() { 6 | super() 7 | 8 | this.attachShadow({ mode: 'open' }) 9 | this.shadowRoot.appendChild(template.content.cloneNode(true)) 10 | 11 | this.rootNode = this.shadowRoot.querySelector('.web-nc') 12 | this.crossImg = '' 13 | } 14 | 15 | connectedCallback() { 16 | CustomEvent.ON('WEB_COMP_SHOW_NOTIFICATION', (data) => { 17 | this.renderNotification(data && data.detail) 18 | }) 19 | } 20 | 21 | disconnectedCallback() { 22 | CustomEvent.OFF('WEB_COMP_SHOW_NOTIFICATION') 23 | } 24 | 25 | attributeChangedCallback(attrName, oldVal, newVal) { 26 | if (this.styleSrc) { 27 | this.attachLink() 28 | } 29 | 30 | if (this.crossImgSrc) { 31 | this.crossImg = this.getAttribute('cross-img-src') 32 | } 33 | } 34 | 35 | static get observedAttributes() { 36 | return ['style-src', 'cross-img-src'] 37 | } 38 | 39 | get crossImgSrc() { 40 | return this.hasAttribute('cross-img-src') 41 | } 42 | 43 | get styleSrc() { 44 | return this.hasAttribute('style-src') 45 | } 46 | 47 | renderNotification(data) { 48 | var divNode 49 | 50 | if (data) { 51 | var div = document.createElement('div') 52 | div.setAttribute('class', `web-nc-content fadein ${data.type}`) 53 | div.innerHTML = `${data.message}` 54 | 55 | divNode = this.rootNode.appendChild(div) 56 | 57 | if (this.crossImg) { 58 | var img = document.createElement('img') 59 | img.setAttribute('src', this.crossImg) 60 | img.setAttribute('alt', '') 61 | img.addEventListener('click', () => divNode.parentNode.removeChild(divNode)) 62 | 63 | divNode.appendChild(img) 64 | } 65 | 66 | setTimeout(() => { 67 | divNode.className += ' fadeout' 68 | setTimeout(() => divNode.parentNode && divNode.parentNode.removeChild(divNode), 1200) 69 | }, data.timer || 5000) 70 | } 71 | } 72 | 73 | attachLink() { 74 | var link = document.createElement('link') 75 | link.setAttribute('rel', 'stylesheet') 76 | link.setAttribute('href', this.getAttribute('style-src')) 77 | this.rootNode.parentNode.insertBefore(link, this.rootNode) 78 | } 79 | } 80 | 81 | customElements.define('notification-service', Notification_Service) 82 | -------------------------------------------------------------------------------- /src/notification-service.template.js: -------------------------------------------------------------------------------- 1 | const template = document.createElement('template') 2 | 3 | template.innerHTML = ` 4 | 97 | 98 |
99 | ` 100 | 101 | export default template 102 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin') 4 | const PATHS = { 5 | src: path.join(__dirname, 'src'), 6 | build: path.join(__dirname, 'build') 7 | } 8 | 9 | const common = { 10 | entry: { 11 | 'notification-service-module': `${PATHS.src}/notification-service-module.js`, 12 | 'notification-service': `${PATHS.src}/notification-service.js` 13 | }, 14 | resolve: { 15 | extensions: ['.js'] 16 | }, 17 | output: { 18 | path: PATHS.build, 19 | filename: '[name].js' 20 | }, 21 | module: { 22 | rules: [ 23 | { 24 | test: /\.js$/, 25 | use: 'babel-loader', 26 | exclude: /node_modules/, 27 | include: PATHS.src 28 | } 29 | ] 30 | }, 31 | optimization: { 32 | minimize: true, 33 | minimizer: [ 34 | new UglifyJsPlugin({ 35 | sourceMap: false 36 | }) 37 | ] 38 | }, 39 | plugins: [ 40 | new webpack.DefinePlugin({ 41 | 'process.env': { 42 | 'NODE_ENV': JSON.stringify('production') 43 | } 44 | }) 45 | ] 46 | } 47 | 48 | module.exports = common 49 | --------------------------------------------------------------------------------