├── .babelrc
├── .gitignore
├── LICENSE
├── README.md
├── build
└── index.js
├── package.json
├── src
├── ReactNotifications.js
└── index.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env"],
3 | "plugins": [
4 | "transform-object-rest-spread",
5 | "transform-react-jsx"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 |
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Kaushik Nagaraj
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 | # react-browser-notifications
2 | React component for the [Javascript Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API). The Notifications API allows web pages to control the display of system notifications to the end user. These are outside the top-level browsing context viewport, so therefore can be displayed even when the user has switched tabs or moved to a different app. This component is supported in modern web browsers such as Chrome, Safari, Firefox, Opera, and Edge.
3 |
4 |
5 | ## Demo
6 | [Live Demo](https://react-notif-demo.herokuapp.com/)
7 |
8 |
9 | ## Installation
10 | Using [npm](https://www.npmjs.com/):
11 | ```
12 | npm install --save react-browser-notifications
13 | ```
14 |
15 |
16 | ## Usage
17 | ```javascript
18 | import React from 'react';
19 | import ReactNotifications from 'react-browser-notifications';
20 |
21 | class Example extends React.Component {
22 | constructor() {
23 | super();
24 | this.showNotifications = this.showNotifications.bind(this);
25 | this.handleClick = this.handleClick.bind(this);
26 | }
27 |
28 | showNotifications() {
29 | // If the Notifications API is supported by the browser
30 | // then show the notification
31 | if(this.n.supported()) this.n.show();
32 | }
33 |
34 | handleClick(event) {
35 | // Do something here such as
36 | // console.log("Notification Clicked") OR
37 | // window.focus() OR
38 | // window.open("http://www.google.com")
39 |
40 | // Lastly, Close the notification
41 | this.n.close(event.target.tag);
42 | }
43 |
44 | render() {
45 | return (
46 |
47 |
48 | (this.n = ref)} // Required
50 | title="Hey There!" // Required
51 | body="This is the body"
52 | icon="icon.png"
53 | tag="abcdef"
54 | timeout="2000"
55 | onClick={event => this.handleClick(event)}
56 | />
57 |
58 |
59 | Notify Me!
60 |
61 |
62 |
63 | )
64 | }
65 | }
66 | ```
67 |
68 |
69 | ## Methods
70 | Once you have the reference of `ReactNotifications` by including the `onRef={ref => (this.n = ref)}` prop, you can call the below methods
71 |
72 | ```javascript
73 | // Returns true if the Notifications API is supported by the browser
74 | this.n.supported()
75 |
76 | // Triggers the browser notification
77 | this.n.show()
78 |
79 | // Close the notification, which is ID'ed by the tag prop
80 | this.n.close(tag)
81 | ```
82 |
83 |
84 | ## Properties
85 | The `ReactNotifications` component accepts the following props
86 |
87 | Name | Type | Req/Opt | Description
88 | --- | --- | --- | ---
89 | `onRef` | function | **Required** | This is required to [reference](https://reactjs.org/docs/refs-and-the-dom.html) the `ReactNotifications` component. **Recommended:** `onRef={ref => (this.n = ref)}`, where n is any variable name
90 | `title` | string | **Required** | Title of the notification
91 | `body` | string | Optional | Text to display in the body of the notification
92 | `icon` | string | Optional | Link to image to be displayed as the icon
93 | `tag` | string | Optional | Unique identifier for the notification. If this is not provided as a prop, an unique [shortid](https://www.npmjs.com/package/shortid) is automatically generated for the notification
94 | `timeout` | string | Optional | Indicates, in milliseconds, the duration for which the notification will remain displayed, if less than the default timeout. Default timeout is dependent on the browser (typically 4s or 5s). Maximum duration is the default timeout
95 | `interaction` | boolean | Optional | *Only available in Chrome*. Setting this to `true` makes the notification remain displayed until the user interacts with the notification (clicks the *Close* button). `timeout` overrides `interaction` if both props are provided
96 | `onClick` | function | Optional | Fired when the notification is clicked
97 |
98 |
99 | ## Browser Support
100 | For up-to-date details on browser compatibility, please visit [caniuse](https://caniuse.com/#search=notifications)
101 |
102 |
103 | ## License
104 | MIT
105 |
106 |
107 | ## Credits
108 | Dependency: [Push.js](https://github.com/Nickersoft/push.js) by [Nickersoft](https://github.com/Nickersoft)
109 |
--------------------------------------------------------------------------------
/build/index.js:
--------------------------------------------------------------------------------
1 | module.exports =
2 | /******/ (function(modules) { // webpackBootstrap
3 | /******/ // The module cache
4 | /******/ var installedModules = {};
5 | /******/
6 | /******/ // The require function
7 | /******/ function __webpack_require__(moduleId) {
8 | /******/
9 | /******/ // Check if module is in cache
10 | /******/ if(installedModules[moduleId]) {
11 | /******/ return installedModules[moduleId].exports;
12 | /******/ }
13 | /******/ // Create a new module (and put it into the cache)
14 | /******/ var module = installedModules[moduleId] = {
15 | /******/ i: moduleId,
16 | /******/ l: false,
17 | /******/ exports: {}
18 | /******/ };
19 | /******/
20 | /******/ // Execute the module function
21 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
22 | /******/
23 | /******/ // Flag the module as loaded
24 | /******/ module.l = true;
25 | /******/
26 | /******/ // Return the exports of the module
27 | /******/ return module.exports;
28 | /******/ }
29 | /******/
30 | /******/
31 | /******/ // expose the modules object (__webpack_modules__)
32 | /******/ __webpack_require__.m = modules;
33 | /******/
34 | /******/ // expose the module cache
35 | /******/ __webpack_require__.c = installedModules;
36 | /******/
37 | /******/ // identity function for calling harmony imports with the correct context
38 | /******/ __webpack_require__.i = function(value) { return value; };
39 | /******/
40 | /******/ // define getter function for harmony exports
41 | /******/ __webpack_require__.d = function(exports, name, getter) {
42 | /******/ if(!__webpack_require__.o(exports, name)) {
43 | /******/ Object.defineProperty(exports, name, {
44 | /******/ configurable: false,
45 | /******/ enumerable: true,
46 | /******/ get: getter
47 | /******/ });
48 | /******/ }
49 | /******/ };
50 | /******/
51 | /******/ // getDefaultExport function for compatibility with non-harmony modules
52 | /******/ __webpack_require__.n = function(module) {
53 | /******/ var getter = module && module.__esModule ?
54 | /******/ function getDefault() { return module['default']; } :
55 | /******/ function getModuleExports() { return module; };
56 | /******/ __webpack_require__.d(getter, 'a', getter);
57 | /******/ return getter;
58 | /******/ };
59 | /******/
60 | /******/ // Object.prototype.hasOwnProperty.call
61 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
62 | /******/
63 | /******/ // __webpack_public_path__
64 | /******/ __webpack_require__.p = "";
65 | /******/
66 | /******/ // Load entry module and return exports
67 | /******/ return __webpack_require__(__webpack_require__.s = 3);
68 | /******/ })
69 | /************************************************************************/
70 | /******/ ([
71 | /* 0 */
72 | /***/ (function(module, exports, __webpack_require__) {
73 |
74 | "use strict";
75 |
76 |
77 | var randomFromSeed = __webpack_require__(11);
78 |
79 | var ORIGINAL = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-';
80 | var alphabet;
81 | var previousSeed;
82 |
83 | var shuffled;
84 |
85 | function reset() {
86 | shuffled = false;
87 | }
88 |
89 | function setCharacters(_alphabet_) {
90 | if (!_alphabet_) {
91 | if (alphabet !== ORIGINAL) {
92 | alphabet = ORIGINAL;
93 | reset();
94 | }
95 | return;
96 | }
97 |
98 | if (_alphabet_ === alphabet) {
99 | return;
100 | }
101 |
102 | if (_alphabet_.length !== ORIGINAL.length) {
103 | throw new Error('Custom alphabet for shortid must be ' + ORIGINAL.length + ' unique characters. You submitted ' + _alphabet_.length + ' characters: ' + _alphabet_);
104 | }
105 |
106 | var unique = _alphabet_.split('').filter(function(item, ind, arr){
107 | return ind !== arr.lastIndexOf(item);
108 | });
109 |
110 | if (unique.length) {
111 | throw new Error('Custom alphabet for shortid must be ' + ORIGINAL.length + ' unique characters. These characters were not unique: ' + unique.join(', '));
112 | }
113 |
114 | alphabet = _alphabet_;
115 | reset();
116 | }
117 |
118 | function characters(_alphabet_) {
119 | setCharacters(_alphabet_);
120 | return alphabet;
121 | }
122 |
123 | function setSeed(seed) {
124 | randomFromSeed.seed(seed);
125 | if (previousSeed !== seed) {
126 | reset();
127 | previousSeed = seed;
128 | }
129 | }
130 |
131 | function shuffle() {
132 | if (!alphabet) {
133 | setCharacters(ORIGINAL);
134 | }
135 |
136 | var sourceArray = alphabet.split('');
137 | var targetArray = [];
138 | var r = randomFromSeed.nextValue();
139 | var characterIndex;
140 |
141 | while (sourceArray.length > 0) {
142 | r = randomFromSeed.nextValue();
143 | characterIndex = Math.floor(r * sourceArray.length);
144 | targetArray.push(sourceArray.splice(characterIndex, 1)[0]);
145 | }
146 | return targetArray.join('');
147 | }
148 |
149 | function getShuffled() {
150 | if (shuffled) {
151 | return shuffled;
152 | }
153 | shuffled = shuffle();
154 | return shuffled;
155 | }
156 |
157 | /**
158 | * lookup shuffled letter
159 | * @param index
160 | * @returns {string}
161 | */
162 | function lookup(index) {
163 | var alphabetShuffled = getShuffled();
164 | return alphabetShuffled[index];
165 | }
166 |
167 | module.exports = {
168 | characters: characters,
169 | seed: setSeed,
170 | lookup: lookup,
171 | shuffled: getShuffled
172 | };
173 |
174 |
175 | /***/ }),
176 | /* 1 */
177 | /***/ (function(module, exports, __webpack_require__) {
178 |
179 | "use strict";
180 |
181 |
182 | var randomByte = __webpack_require__(10);
183 |
184 | function encode(lookup, number) {
185 | var loopCounter = 0;
186 | var done;
187 |
188 | var str = '';
189 |
190 | while (!done) {
191 | str = str + lookup( ( (number >> (4 * loopCounter)) & 0x0f ) | randomByte() );
192 | done = number < (Math.pow(16, loopCounter + 1 ) );
193 | loopCounter++;
194 | }
195 | return str;
196 | }
197 |
198 | module.exports = encode;
199 |
200 |
201 | /***/ }),
202 | /* 2 */
203 | /***/ (function(module, exports, __webpack_require__) {
204 |
205 | "use strict";
206 |
207 |
208 | Object.defineProperty(exports, "__esModule", {
209 | value: true
210 | });
211 |
212 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
213 |
214 | var _react = __webpack_require__(13);
215 |
216 | var _react2 = _interopRequireDefault(_react);
217 |
218 | var _push = __webpack_require__(4);
219 |
220 | var _push2 = _interopRequireDefault(_push);
221 |
222 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
223 |
224 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
225 |
226 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
227 |
228 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
229 |
230 | var shortid = __webpack_require__(5);
231 |
232 | var ReactNotifications = function (_React$Component) {
233 | _inherits(ReactNotifications, _React$Component);
234 |
235 | function ReactNotifications() {
236 | _classCallCheck(this, ReactNotifications);
237 |
238 | var _this = _possibleConstructorReturn(this, (ReactNotifications.__proto__ || Object.getPrototypeOf(ReactNotifications)).call(this));
239 |
240 | _this.supported = _this.supported.bind(_this);
241 | _this.show = _this.show.bind(_this);
242 | _this.close = _this.close.bind(_this);
243 | return _this;
244 | }
245 |
246 | _createClass(ReactNotifications, [{
247 | key: 'componentDidMount',
248 | value: function componentDidMount() {
249 | this.props.onRef(this);
250 | }
251 | }, {
252 | key: 'componentWillUnmount',
253 | value: function componentWillUnmount() {
254 | this.props.onRef(undefined);
255 | }
256 | }, {
257 | key: 'supported',
258 | value: function supported() {
259 | if ('Notification' in window) return true;else return false;
260 | }
261 | }, {
262 | key: 'show',
263 | value: function show() {
264 | _push2.default.create(this.props.title, {
265 | body: this.props.body ? this.props.body : null,
266 | icon: this.props.icon ? this.props.icon : null,
267 | tag: this.props.tag ? this.props.tag : shortid.generate(),
268 | timeout: this.props.timeout ? this.props.timeout : null,
269 | requireInteraction: this.props.interaction ? this.props.interaction : false,
270 | onClick: this.props.onClick ? this.props.onClick : null
271 | });
272 | }
273 | }, {
274 | key: 'close',
275 | value: function close(tag) {
276 | _push2.default.close(tag);
277 | }
278 | }, {
279 | key: 'render',
280 | value: function render() {
281 | return _react2.default.createElement('div', null);
282 | }
283 | }]);
284 |
285 | return ReactNotifications;
286 | }(_react2.default.Component);
287 |
288 | exports.default = ReactNotifications;
289 |
290 | /***/ }),
291 | /* 3 */
292 | /***/ (function(module, exports, __webpack_require__) {
293 |
294 | "use strict";
295 |
296 |
297 | Object.defineProperty(exports, "__esModule", {
298 | value: true
299 | });
300 |
301 | var _ReactNotifications = __webpack_require__(2);
302 |
303 | var _ReactNotifications2 = _interopRequireDefault(_ReactNotifications);
304 |
305 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
306 |
307 | exports.default = _ReactNotifications2.default;
308 |
309 | /***/ }),
310 | /* 4 */
311 | /***/ (function(module, exports, __webpack_require__) {
312 |
313 | var require;var require;/**
314 | * Push v1.0-beta
315 | * ==============
316 | * A compact, cross-browser solution for the JavaScript Notifications API
317 | *
318 | * Credits
319 | * -------
320 | * Tsvetan Tsvetkov (ttsvetko)
321 | * Alex Gibson (alexgibson)
322 | *
323 | * License
324 | * -------
325 | *
326 | * The MIT License (MIT)
327 | *
328 | * Copyright (c) 2015-2017 Tyler Nickerson
329 | *
330 | * Permission is hereby granted, free of charge, to any person obtaining a copy
331 | * of this software and associated documentation files (the "Software"), to deal
332 | * in the Software without restriction, including without limitation the rights
333 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
334 | * copies of the Software, and to permit persons to whom the Software is
335 | * furnished to do so, subject to the following conditions:
336 | *
337 | * The above copyright notice and this permission notice shall be included in
338 | * all copies or substantial portions of the Software.
339 | *
340 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
341 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
342 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
343 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
344 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
345 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
346 | * THE SOFTWARE.
347 | */
348 | !function(t){if(true)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).Push=t()}}(function(){return function t(e,n,i){function o(s,a){if(!n[s]){if(!e[s]){var u="function"==typeof require&&require;if(!a&&u)return require(s,!0);if(r)return r(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var f=n[s]={exports:{}};e[s][0].call(f.exports,function(t){var n=e[s][1][t];return o(n||t)},f,f.exports,t,e,n,i)}return n[s].exports}for(var r="function"==typeof require&&require,s=0;s0?this._requestWithCallback.apply(this,arguments):this._requestAsPromise()}},{key:"_requestWithCallback",value:function(t,e){var n=this,i=this.get(),o=function(){var i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:n._win.Notification.permission;void 0===i&&n._win.webkitNotifications&&(i=n._win.webkitNotifications.checkPermission()),i===n.GRANTED||0===i?t&&t():e&&e()};i!==this.DEFAULT?o(i):this._win.webkitNotifications&&this._win.webkitNotifications.checkPermission?this._win.webkitNotifications.requestPermission(o):this._win.Notification&&this._win.Notification.requestPermission?this._win.Notification.requestPermission().then(o).catch(function(){e&&e()}):t&&t()}},{key:"_requestAsPromise",value:function(){var t=this,e=this.get(),n=function(e){return e===t.GRANTED||0===e},i=e!==this.DEFAULT,o=this._win.Notification&&this._win.Notification.requestPermission,r=this._win.webkitNotifications&&this._win.webkitNotifications.checkPermission;return new Promise(function(s,a){var u=function(t){return n(t)?s():a()};i?u(e):r?t._win.webkitNotifications.requestPermission(function(t){u(t)}):o?t._win.Notification.requestPermission().then(function(t){u(t)}).catch(a):s()})}},{key:"has",value:function(){return this.get()===this.GRANTED}},{key:"get",value:function(){return this._win.Notification&&this._win.Notification.permission?this._win.Notification.permission:this._win.webkitNotifications&&this._win.webkitNotifications.checkPermission?this._permissions[this._win.webkitNotifications.checkPermission()]:navigator.mozNotification?this.GRANTED:this._win.external&&this._win.external.msIsSiteMode?this._win.external.msIsSiteMode()?this.GRANTED:this.DEFAULT:this.GRANTED}}]),t}();n.default=r},{}],3:[function(t,e,n){"use strict";function i(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function t(t,e){for(var n=0;n 0) {
405 | str = str + encode(alphabet.lookup, counter);
406 | }
407 | str = str + encode(alphabet.lookup, seconds);
408 |
409 | return str;
410 | }
411 |
412 | module.exports = build;
413 |
414 |
415 | /***/ }),
416 | /* 7 */
417 | /***/ (function(module, exports, __webpack_require__) {
418 |
419 | "use strict";
420 |
421 | var alphabet = __webpack_require__(0);
422 |
423 | /**
424 | * Decode the id to get the version and worker
425 | * Mainly for debugging and testing.
426 | * @param id - the shortid-generated id.
427 | */
428 | function decode(id) {
429 | var characters = alphabet.shuffled();
430 | return {
431 | version: characters.indexOf(id.substr(0, 1)) & 0x0f,
432 | worker: characters.indexOf(id.substr(1, 1)) & 0x0f
433 | };
434 | }
435 |
436 | module.exports = decode;
437 |
438 |
439 | /***/ }),
440 | /* 8 */
441 | /***/ (function(module, exports, __webpack_require__) {
442 |
443 | "use strict";
444 |
445 |
446 | var alphabet = __webpack_require__(0);
447 | var encode = __webpack_require__(1);
448 | var decode = __webpack_require__(7);
449 | var build = __webpack_require__(6);
450 | var isValid = __webpack_require__(9);
451 |
452 | // if you are using cluster or multiple servers use this to make each instance
453 | // has a unique value for worker
454 | // Note: I don't know if this is automatically set when using third
455 | // party cluster solutions such as pm2.
456 | var clusterWorkerId = __webpack_require__(12) || 0;
457 |
458 | /**
459 | * Set the seed.
460 | * Highly recommended if you don't want people to try to figure out your id schema.
461 | * exposed as shortid.seed(int)
462 | * @param seed Integer value to seed the random alphabet. ALWAYS USE THE SAME SEED or you might get overlaps.
463 | */
464 | function seed(seedValue) {
465 | alphabet.seed(seedValue);
466 | return module.exports;
467 | }
468 |
469 | /**
470 | * Set the cluster worker or machine id
471 | * exposed as shortid.worker(int)
472 | * @param workerId worker must be positive integer. Number less than 16 is recommended.
473 | * returns shortid module so it can be chained.
474 | */
475 | function worker(workerId) {
476 | clusterWorkerId = workerId;
477 | return module.exports;
478 | }
479 |
480 | /**
481 | *
482 | * sets new characters to use in the alphabet
483 | * returns the shuffled alphabet
484 | */
485 | function characters(newCharacters) {
486 | if (newCharacters !== undefined) {
487 | alphabet.characters(newCharacters);
488 | }
489 |
490 | return alphabet.shuffled();
491 | }
492 |
493 | /**
494 | * Generate unique id
495 | * Returns string id
496 | */
497 | function generate() {
498 | return build(clusterWorkerId);
499 | }
500 |
501 | // Export all other functions as properties of the generate function
502 | module.exports = generate;
503 | module.exports.generate = generate;
504 | module.exports.seed = seed;
505 | module.exports.worker = worker;
506 | module.exports.characters = characters;
507 | module.exports.decode = decode;
508 | module.exports.isValid = isValid;
509 |
510 |
511 | /***/ }),
512 | /* 9 */
513 | /***/ (function(module, exports, __webpack_require__) {
514 |
515 | "use strict";
516 |
517 | var alphabet = __webpack_require__(0);
518 |
519 | function isShortId(id) {
520 | if (!id || typeof id !== 'string' || id.length < 6 ) {
521 | return false;
522 | }
523 |
524 | var characters = alphabet.characters();
525 | var len = id.length;
526 | for(var i = 0; i < len;i++) {
527 | if (characters.indexOf(id[i]) === -1) {
528 | return false;
529 | }
530 | }
531 | return true;
532 | }
533 |
534 | module.exports = isShortId;
535 |
536 |
537 | /***/ }),
538 | /* 10 */
539 | /***/ (function(module, exports, __webpack_require__) {
540 |
541 | "use strict";
542 |
543 |
544 | var crypto = typeof window === 'object' && (window.crypto || window.msCrypto); // IE 11 uses window.msCrypto
545 |
546 | function randomByte() {
547 | if (!crypto || !crypto.getRandomValues) {
548 | return Math.floor(Math.random() * 256) & 0x30;
549 | }
550 | var dest = new Uint8Array(1);
551 | crypto.getRandomValues(dest);
552 | return dest[0] & 0x30;
553 | }
554 |
555 | module.exports = randomByte;
556 |
557 |
558 | /***/ }),
559 | /* 11 */
560 | /***/ (function(module, exports, __webpack_require__) {
561 |
562 | "use strict";
563 |
564 |
565 | // Found this seed-based random generator somewhere
566 | // Based on The Central Randomizer 1.3 (C) 1997 by Paul Houle (houle@msc.cornell.edu)
567 |
568 | var seed = 1;
569 |
570 | /**
571 | * return a random number based on a seed
572 | * @param seed
573 | * @returns {number}
574 | */
575 | function getNextValue() {
576 | seed = (seed * 9301 + 49297) % 233280;
577 | return seed/(233280.0);
578 | }
579 |
580 | function setSeed(_seed_) {
581 | seed = _seed_;
582 | }
583 |
584 | module.exports = {
585 | nextValue: getNextValue,
586 | seed: setSeed
587 | };
588 |
589 |
590 | /***/ }),
591 | /* 12 */
592 | /***/ (function(module, exports, __webpack_require__) {
593 |
594 | "use strict";
595 |
596 |
597 | module.exports = 0;
598 |
599 |
600 | /***/ }),
601 | /* 13 */
602 | /***/ (function(module, exports) {
603 |
604 | module.exports = require("react");
605 |
606 | /***/ })
607 | /******/ ]);
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-browser-notifications",
3 | "version": "1.0.14",
4 | "description": "React component for the Javascript Notification API",
5 | "main": "build/index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "webpack --watch",
9 | "build": "webpack"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/knxyzkn/react-browser-notifications.git"
14 | },
15 | "keywords": [
16 | "react",
17 | "javascript",
18 | "browser",
19 | "api",
20 | "notifications"
21 | ],
22 | "author": "Kaushik Nagaraj",
23 | "license": "MIT",
24 | "bugs": {
25 | "url": "https://github.com/knxyzkn/react-browser-notifications/issues"
26 | },
27 | "homepage": "https://github.com/knxyzkn/react-browser-notifications#readme",
28 | "devDependencies": {
29 | "babel-cli": "^6.24.1",
30 | "babel-core": "^6.24.1",
31 | "babel-loader": "^7.0.0",
32 | "babel-plugin-transform-object-rest-spread": "^6.23.0",
33 | "babel-plugin-transform-react-jsx": "^6.24.1",
34 | "babel-preset-env": "^1.5.1"
35 | },
36 | "dependencies": {
37 | "push.js": "^1.0.5",
38 | "react": "^16.2.0",
39 | "shortid": "^2.2.8",
40 | "webpack": "^2.6.1"
41 | },
42 | "babel": {
43 | "presets": [
44 | "es2015",
45 | "react",
46 | "stage-2"
47 | ]
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/ReactNotifications.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Push from 'push.js';
3 | const shortid = require('shortid');
4 |
5 | class ReactNotifications extends React.Component {
6 |
7 | constructor() {
8 | super();
9 | this.supported = this.supported.bind(this);
10 | this.show = this.show.bind(this);
11 | this.close = this.close.bind(this);
12 | }
13 |
14 | componentDidMount() {
15 | this.props.onRef(this)
16 | }
17 |
18 | componentWillUnmount() {
19 | this.props.onRef(undefined)
20 | }
21 |
22 | supported() {
23 | if ('Notification' in window) return true;
24 | else return false;
25 | }
26 |
27 | show() {
28 | Push.create(this.props.title, {
29 | body: this.props.body ? this.props.body : null,
30 | icon: this.props.icon ? this.props.icon : null,
31 | tag: this.props.tag ? this.props.tag : shortid.generate(),
32 | timeout: this.props.timeout ? this.props.timeout : null,
33 | requireInteraction: this.props.interaction ? this.props.interaction : false,
34 | onClick: this.props.onClick ? this.props.onClick : null
35 | })
36 | }
37 |
38 | close(tag) {
39 | Push.close(tag);
40 | }
41 |
42 | render() {
43 | return (
44 |
45 |
46 | )
47 | }
48 | }
49 |
50 | export default ReactNotifications;
51 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import ReactNotifications from './ReactNotifications.js';
2 |
3 | export default ReactNotifications;
4 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | module.exports = {
3 | entry: './src/index.js',
4 | output: {
5 | path: path.resolve(__dirname, 'build'),
6 | filename: 'index.js',
7 | libraryTarget: 'commonjs2'
8 | },
9 | module: {
10 | rules: [
11 | {
12 | test: /\.js$/,
13 | include: path.resolve(__dirname, 'src'),
14 | exclude: /(node_modules|bower_components|build)/,
15 | use: {
16 | loader: 'babel-loader',
17 | options: {
18 | presets: ['env']
19 | }
20 | }
21 | }
22 | ]
23 | },
24 | externals: {
25 | 'react': 'commonjs react'
26 | }
27 | };
28 |
--------------------------------------------------------------------------------