├── .gitignore
├── .npmignore
├── README.md
├── package-lock.json
├── package.json
├── src
├── index.ts
└── notifications
│ ├── Notification.css
│ ├── Notifications.tsx
│ ├── PushNotification.tsx
│ └── Storage.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fabioshub/react-push-notification/2b5d8a0863b096a51c30e703c4152f4c514d858d/.npmignore
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | [](https://www.npmjs.com/package/react-push-notification)
3 |
4 | ---
5 |
6 | # react-push-notification
7 |
8 | Easy, type-safe, & lightweight push notification library for React.js.
9 | Written in TypeScript & compiled to JavaScript for robust code.
10 |
11 | In-app notification system, as well as web native Notification support.
12 |
13 | 
14 | 
15 |
16 |
17 | ### Install
18 |
19 | ```bash
20 | yarn add react-push-notification
21 | ```
22 | or
23 | ```bash
24 | npm i react-push-notification
25 | ```
26 |
27 | ### Sneakpeak
28 |
29 | In-app notification example. Regular React components.
30 |
31 | 
32 |
33 | Web native notification example. Web native components. Send push notifications outside of the browser while the browser is running in the background or just idle.
34 |
35 | Mac OSX example:
36 |
37 | 
38 | 
39 |
40 |
41 |
42 | ### Set-up
43 |
44 | Add the notifications component to the top of your React.js project.
45 | This is probably `index.js` or `app.js`. When using `native: true`, this step is not required.
46 |
47 |
48 | ```jsx
49 | import { Notifications } from 'react-push-notification';
50 |
51 | const App = () => {
52 | return (
53 |
54 | // Top of DOM tree
55 |
56 |
57 |
58 | Hello world.
59 |
60 |
61 |
62 | );
63 | }
64 | };
65 |
66 | export default App;
67 | ```
68 |
69 | ### Usage
70 |
71 | import the `addNotification` function and call it.
72 |
73 | ```jsx
74 | import addNotification from 'react-push-notification';
75 |
76 | const Page = () => {
77 |
78 | const buttonClick = () => {
79 | addNotification({
80 | title: 'Warning',
81 | subtitle: 'This is a subtitle',
82 | message: 'This is a very long message',
83 | theme: 'darkblue',
84 | native: true // when using native, your OS will handle theming.
85 | });
86 | };
87 |
88 | return (
89 |
90 |
93 |
94 | );
95 | }
96 | };
97 |
98 | export default Page;
99 | ```
100 |
101 | ## Props
102 |
103 |
104 | | Property | Description |
105 | | ---------------------------------- | ------------------------------------------------------------------ |
106 | | position `string` | One of `top-left`, `top-middle`, `top-right`, `bottom-left`, `bottom-middle`, `bottom-right`.
Default: `top-left` |
107 |
108 |
109 |
110 | ## `addNotification({Options})` argument properties
111 |
112 | The `addNotification()` function has the following function type:
113 |
114 | ```tsx
115 |
116 | const options = {
117 | title: 'title',
118 | subtitle: 'subtitle', //optional
119 | message: 'message', //optional
120 | onClick: (e: Event | Notification) => void, //optional, onClick callback.
121 | theme: 'red', //optional, default: undefined
122 | duration: 3000, //optional, default: 5000,
123 | backgroundTop: 'green', //optional, background color of top container.
124 | backgroundBottom: 'darkgreen', //optional, background color of bottom container.
125 | colorTop: 'green', //optional, font color of top container.
126 | colorBottom: 'darkgreen', //optional, font color of bottom container.
127 | closeButton: 'Go away', //optional, text or html/jsx element for close text. Default: Close,
128 | native?: boolean, //optional, makes the push notification a native OS notification
129 | icon?: string, // optional, Native only. Sets an icon for the notification.
130 | vibrate?: number | number[], // optional, Native only. Sets a vibration for the notification.
131 | silent?: boolean // optional, Native only. Makes the notification silent.
132 |
133 | };
134 |
135 | const addNotification: (options: Options) => void;
136 |
137 | ```
138 |
139 |
140 |
141 |
142 | The `addNotification()` function takes an object as argument with the follow properties:
143 |
144 |
145 | | Property | Description |
146 | | ---------------------------------- | ------------------------------------------------------------------ |
147 | | title `string` | Required. Title of the push notification |
148 | | subtitle `string` | Optional. Subtitle of the push notification |
149 | | message `string` | Optional. Message of the push notification |
150 | | onClick `(e: Event OR Notification) => void` | Optional. onClick callback of push notification.
When `native: true` `e` will be of type `Notification`.
Else `e` will be of type `Event`. |
151 | | theme `string` | Optional. One of `darkblue`, `red`, `light`, `undefined`.
Default: `undefined` |
152 | | duration `number` | Optional. Duration of the push notification in ms.
Default: 3000 |
153 | | backgroundTop `string` | Optional. background color of top container. |
154 | | backgroundBottom `string` | Optional. background color of bottom container. |
155 | | colorTop `string` | Optional. font color of top container. |
156 | | colorBottom `string` | Optional. font color of bottom container. |
157 | | closeButton `string` | Optional. text or html/jsx element for close text.
Default: `Close` |
158 | | native `boolean` | Optional. Turns the notification into a native web notification.
Default: `false` |
159 | | icon `string` | Optional. Native only. Shows an icon in the notification. |
160 | | vibrate `number` | `number[]` | Optional. Native only. Makes the notification vibrate. |
161 | | silent `boolean` | Optional. Native only. Makes the notification silent. |
162 |
163 |
164 |
165 | The custom background or font colors will always override a chosen theme.
166 |
167 | ### Changelog
168 |
169 | v1.3.0
170 |
171 | Added native OS push notification support, as well as an `onClick` callback function.
172 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-push-notification",
3 | "version": "1.5.4",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "react-push-notification",
9 | "version": "1.5.4",
10 | "license": "MIT",
11 | "devDependencies": {
12 | "@types/react": "^16.9.21",
13 | "typescript": "^3.9.10"
14 | },
15 | "peerDependencies": {
16 | "react": "^18.2.0"
17 | }
18 | },
19 | "node_modules/@types/prop-types": {
20 | "version": "15.7.3",
21 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
22 | "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
23 | "dev": true
24 | },
25 | "node_modules/@types/react": {
26 | "version": "16.9.23",
27 | "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.23.tgz",
28 | "integrity": "sha512-SsGVT4E7L2wLN3tPYLiF20hmZTPGuzaayVunfgXzUn1x4uHVsKH6QDJQ/TdpHqwsTLd4CwrmQ2vOgxN7gE24gw==",
29 | "dev": true,
30 | "dependencies": {
31 | "@types/prop-types": "*",
32 | "csstype": "^2.2.0"
33 | }
34 | },
35 | "node_modules/csstype": {
36 | "version": "2.6.9",
37 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.9.tgz",
38 | "integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==",
39 | "dev": true
40 | },
41 | "node_modules/js-tokens": {
42 | "version": "4.0.0",
43 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
44 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
45 | "peer": true
46 | },
47 | "node_modules/loose-envify": {
48 | "version": "1.4.0",
49 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
50 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
51 | "peer": true,
52 | "dependencies": {
53 | "js-tokens": "^3.0.0 || ^4.0.0"
54 | },
55 | "bin": {
56 | "loose-envify": "cli.js"
57 | }
58 | },
59 | "node_modules/react": {
60 | "version": "18.2.0",
61 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
62 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
63 | "peer": true,
64 | "dependencies": {
65 | "loose-envify": "^1.1.0"
66 | },
67 | "engines": {
68 | "node": ">=0.10.0"
69 | }
70 | },
71 | "node_modules/typescript": {
72 | "version": "3.9.10",
73 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz",
74 | "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==",
75 | "dev": true,
76 | "bin": {
77 | "tsc": "bin/tsc",
78 | "tsserver": "bin/tsserver"
79 | },
80 | "engines": {
81 | "node": ">=4.2.0"
82 | }
83 | }
84 | },
85 | "dependencies": {
86 | "@types/prop-types": {
87 | "version": "15.7.3",
88 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
89 | "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
90 | "dev": true
91 | },
92 | "@types/react": {
93 | "version": "16.9.23",
94 | "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.23.tgz",
95 | "integrity": "sha512-SsGVT4E7L2wLN3tPYLiF20hmZTPGuzaayVunfgXzUn1x4uHVsKH6QDJQ/TdpHqwsTLd4CwrmQ2vOgxN7gE24gw==",
96 | "dev": true,
97 | "requires": {
98 | "@types/prop-types": "*",
99 | "csstype": "^2.2.0"
100 | }
101 | },
102 | "csstype": {
103 | "version": "2.6.9",
104 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.9.tgz",
105 | "integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==",
106 | "dev": true
107 | },
108 | "js-tokens": {
109 | "version": "4.0.0",
110 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
111 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
112 | "peer": true
113 | },
114 | "loose-envify": {
115 | "version": "1.4.0",
116 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
117 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
118 | "peer": true,
119 | "requires": {
120 | "js-tokens": "^3.0.0 || ^4.0.0"
121 | }
122 | },
123 | "react": {
124 | "version": "18.2.0",
125 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
126 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
127 | "peer": true,
128 | "requires": {
129 | "loose-envify": "^1.1.0"
130 | }
131 | },
132 | "typescript": {
133 | "version": "3.9.10",
134 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz",
135 | "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==",
136 | "dev": true
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-push-notification",
3 | "version": "1.5.4",
4 | "description": "React push notifications",
5 | "main": "dist/index.js",
6 | "types": "dist/index.d.ts",
7 | "license": "MIT",
8 | "bundleDependencies": [],
9 | "devDependencies": {
10 | "@types/react": "^16.9.21",
11 | "typescript": "^3.9.10"
12 | },
13 | "peerDependencies": {
14 | "react": "^18.2.0"
15 | },
16 | "scripts": {
17 | "start": "tsc -w",
18 | "build": "npx tsc && cp src/Notifications/Notification.css dist/Notifications/Notification.css",
19 | "publish": "git push && npm publish",
20 | "build:check": "tsc --noEmit"
21 | },
22 | "repository": {
23 | "type": "git",
24 | "url": "https://github.com/fabioshub/react-push-notification"
25 | },
26 | "author": "Fabio de Bruijn ",
27 | "keywords": [
28 | "push notifications",
29 | "notifications",
30 | "messages",
31 | "react",
32 | "react push notification",
33 | "react push notifications",
34 | "react notifications",
35 | "react native OS push notifications",
36 | "native OS",
37 | "native push notifications"
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import Notifications from './notifications/Notifications';
2 | import Storage, { Options } from './notifications/Storage';
3 |
4 | /**
5 | * Add a new notification.
6 | * Must pass an object with the params to the function.
7 | * @param {Options} options
8 | * @property {string} options.title - Title of the push notification.
9 | * @property {string} [options.subtitle] - Subtitle of the push notification.
10 | * @property {string} [options.message] - Message of the push notification.
11 | * @property {function} [options.onClick] - onclick callback. Optional parameter.
12 | * @property {('darkblue'|'red'|'light')} [options.theme=undefined] - Theme of the push notification.
13 | * @property {number} [options.duration=3000] - duration of the push notification in ms.
14 | * @property {string} [options.backgroundTop=undefined] - Background color of the top container of push notification.
15 | * @property {string} [options.backgroundBottom=undefined] - Background color of the bottom container of push notification.
16 | * @property {string} [options.colorTop=undefined] - Color of the top text of push notification.
17 | * @property {string} [options.colorBottom=undefined] - Color of the bottom text of push notification.
18 | * @property {(string|JSX.Element)} [options.closeButton="close"] - Color of the bottom text of push notification.
19 | * @property {boolean} [options.native=false] - Uses native browser notifications. Will prompt for user permission if not granted.
20 | * @property {string} [options.icon] - Native only. Link to image to show in notification.
21 | * @property {boolean} [options.silent] - Native only. Makes the notification silent.
22 | * @property {(number|numer[])} [options.vibrate] - Native only. Makes the notification vibrate.
23 | *
24 | */
25 | const addNotification: (options: Options) => void = Storage.addNotification;
26 | export { Notifications };
27 | export default addNotification;
28 |
--------------------------------------------------------------------------------
/src/notifications/Notification.css:
--------------------------------------------------------------------------------
1 | .rpn-notification-holder {
2 | position: fixed;
3 | display: flex;
4 | flex-direction: column;
5 | z-index: 100000;
6 | }
7 |
8 | .rpn-notification-holder.top-left {
9 | left: 10px;
10 | }
11 |
12 | .rpn-notification-holder.top-middle {
13 | left: 50%;
14 | transform: translateX(-50%);
15 | }
16 |
17 | .rpn-notification-holder.top-right {
18 | right: 30px;
19 | }
20 |
21 | .rpn-notification-holder.bottom-left {
22 | left: 10px;
23 | bottom: 10px;
24 | }
25 |
26 | .rpn-notification-holder.bottom-middle {
27 | left: 50%;
28 | transform: translateX(-50%);
29 | bottom: 10px;
30 | }
31 |
32 | .rpn-notification-holder.bottom-right {
33 | right: 30px;
34 | bottom: 10px;
35 | }
36 |
37 | .rpn-notification-card {
38 | display: flex;
39 | flex-direction: column;
40 | width: 250px;
41 | margin-top: 15px;
42 | -webkit-animation: fadein 0.2s; /* Safari, Chrome and Opera > 12.1 */
43 | -moz-animation: fadein 0.2s; /* Firefox < 16 */
44 | -ms-animation: fadein 0.2s; /* Internet Explorer */
45 | -o-animation: fadein 0.2s; /* Opera < 12.1 */
46 | animation: fadein 0.2s;
47 | }
48 |
49 | .rpn-notification-card-top {
50 | width: 100%;
51 | display: flex;
52 | justify-content: space-between;
53 | flex-wrap: wrap;
54 | padding: 10px;
55 | font-weight: bold;
56 | font-size: 11px;
57 | background-color: rgb(51, 51, 51);
58 | color: white;
59 | border-radius: 5px 5px 0 0;
60 |
61 | }
62 |
63 | .rpn-notification-card-bottom {
64 | width: 100%;
65 | display: flex;
66 | flex-direction: column;
67 | align-items: flex-start;
68 | padding: 10px 10px 15px 10px;
69 | flex-wrap: wrap;
70 | background-color: rgb(59, 59, 59);
71 | color: white;
72 | border-radius: 0 0 5px 5px;
73 | justify-content: center;
74 | box-shadow: 0 5px 0px 0px rgb(0, 0, 0);
75 | }
76 |
77 | .rpn-notification-card-bottom span {
78 | padding: 3px 0;
79 | }
80 |
81 | .rpn-notification-card-bottom .subtitle {
82 | font-weight: bold;
83 | font-size: 12px;
84 | }
85 |
86 | .rpn-notification-card-bottom .message {
87 | font-size: 14px;
88 | }
89 |
90 | .rpn-notification-card-close {
91 | font-size: 10px;
92 | cursor: pointer;
93 | height: 100%;
94 | }
95 |
96 | .rpn-notification-card-top.light {
97 | background-color: rgb(240, 240, 240);
98 | color: black;
99 | }
100 |
101 | .rpn-notification-card-bottom.light {
102 | background-color: rgb(245, 245, 245);
103 | color: black;
104 | box-shadow: 0 5px 0px 0px rgb(218, 217, 217);
105 | }
106 |
107 | .rpn-notification-card-top.darkblue {
108 | background-color: #2d3542;
109 | color: white;
110 | }
111 |
112 | .rpn-notification-card-bottom.darkblue {
113 | background-color: #394357;
114 | color: white;
115 | box-shadow: 0 5px 0px 0px #1f2b42;
116 |
117 | }
118 |
119 | .rpn-notification-card-top.red {
120 | background-color: rgb(187, 37, 37);
121 | color: white;
122 | }
123 |
124 | .rpn-notification-card-bottom.red {
125 | background-color: #D32F2F;
126 | color: white;
127 | box-shadow: 0 5px 0px 0px rgb(145, 1, 1);
128 | }
129 |
130 | @keyframes fadein {
131 | from { opacity: 0; }
132 | to { opacity: 1; }
133 | }
134 |
135 | /* Firefox < 16 */
136 | @-moz-keyframes fadein {
137 | from { opacity: 0; }
138 | to { opacity: 1; }
139 | }
140 |
141 | /* Safari, Chrome and Opera > 12.1 */
142 | @-webkit-keyframes fadein {
143 | from { opacity: 0; }
144 | to { opacity: 1; }
145 | }
146 |
147 | /* Internet Explorer */
148 | @-ms-keyframes fadein {
149 | from { opacity: 0; }
150 | to { opacity: 1; }
151 | }
152 |
153 | /* Opera < 12.1 */
154 | @-o-keyframes fadein {
155 | from { opacity: 0; }
156 | to { opacity: 1; }
157 | }
--------------------------------------------------------------------------------
/src/notifications/Notifications.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Storage, { PushNotification as Not } from './Storage';
3 | import './Notification.css';
4 | import PushNotification from './PushNotification';
5 |
6 | type Position = 'top-left' | 'top-middle' | 'top-right' | 'bottom-left' | 'bottom-middle' | 'bottom-right';
7 |
8 | interface Props {
9 | position?: Position;
10 | }
11 |
12 | interface State {
13 | value: Array;
14 | }
15 |
16 | /**
17 | * Notification injector, which renders
18 | * the push notifications rendered
19 | * by the addNotifcation({}) function.
20 | *
21 | * @param {string} position - Must pass as prop. Sets the position of the push notification.
22 | * position can me 'top-left', 'top-middle', 'top-right', 'bottom-left', 'bottom-middle', 'bottom-right'.
23 | * Example
24 | *
25 | */
26 | class Notifications extends React.Component {
27 | state: State = {
28 | value: [],
29 | };
30 |
31 | componentDidMount() {
32 | Storage.addListener((v: Array): void => this.setState({ value: v }));
33 | }
34 |
35 | render(): JSX.Element {
36 | const { position } = this.props;
37 | const classN: string = `rpn-notification-holder ${position || 'top-middle'} supertest`;
38 | return
39 | {this.state.value.map((note: Not, i: number): JSX.Element => {
40 | return
41 | })}
42 |
43 | }
44 | };
45 |
46 |
47 | export default Notifications;
--------------------------------------------------------------------------------
/src/notifications/PushNotification.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Color, Styling, eventFunc } from './Storage';
3 |
4 | interface Props {
5 | title: string;
6 | id: number;
7 | message?: string;
8 | subtitle?: string;
9 | theme?: Color;
10 | styling?: Styling;
11 | closeButton?: JSX.Element | string;
12 | onClick?: eventFunc;
13 | closeNotification: (id: number) => void;
14 | }
15 |
16 | type Style = {
17 | backgroundColor?: string,
18 | color?: string
19 | }
20 |
21 | const PushNotification = (props: Props): JSX.Element => {
22 | const { title, subtitle, message, theme, id, closeNotification, styling, closeButton, onClick } = props;
23 | let topStyling: Style = {};
24 | let bottomStyling: Style = {};
25 | if (styling) {
26 | topStyling.backgroundColor = styling.backgroundTop;
27 | topStyling.color = styling.colorTop;
28 | bottomStyling.backgroundColor = styling.backgroundBottom;
29 | bottomStyling.color = styling.colorBottom;
30 | }
31 | return
32 |
33 | {title}
34 | closeNotification(id)}>{closeButton || 'close'}
35 |
36 |
37 | {subtitle}
38 | {message}
39 |
40 |
41 |
;
42 | }
43 |
44 | export default PushNotification;
--------------------------------------------------------------------------------
/src/notifications/Storage.ts:
--------------------------------------------------------------------------------
1 |
2 | export type Color = 'light' | 'darkblue' | 'red' | undefined;
3 |
4 | const defaultDuration = 3000;
5 |
6 | type voidFunc = () => void;
7 | export type eventFunc = (e: any) => void;
8 |
9 | export type onClickType = voidFunc | eventFunc | undefined;
10 |
11 | export type Options = {
12 | title: string,
13 | subtitle?: string,
14 | message?: string,
15 | onClick?: onClickType,
16 | theme?: Color,
17 | duration?: number,
18 | backgroundTop?: string,
19 | backgroundBottom?: string,
20 | colorTop?: string,
21 | colorBottom?: string,
22 | closeButton?: JSX.Element | string,
23 | native?: boolean,
24 | icon?: string,
25 | vibrate?: number | number[],
26 | silent?: boolean
27 | }
28 |
29 | export type Styling = {
30 | backgroundTop?: string,
31 | backgroundBottom?: string,
32 | colorTop?: string,
33 | colorBottom?: string
34 | }
35 |
36 | export interface PushNotificationObject {
37 | title: string;
38 | subtitle?: string;
39 | message?: string;
40 | theme?: Color;
41 | styling?: Styling;
42 | closeButton?: JSX.Element | string;
43 | onClick?: onClickType;
44 | }
45 |
46 | export class PushNotification {
47 | title: string;
48 | subtitle?: string;
49 | message?: string;
50 | theme?: Color;
51 | id: number;
52 | styling?: Styling;
53 | closeButton?: JSX.Element | string;
54 | onClick?: onClickType;
55 | constructor(op: PushNotificationObject) {
56 | this.title = op.title;
57 | this.subtitle = op.subtitle;
58 | this.message = op.message;
59 | this.theme = op.theme;
60 | this.id = Math.random();
61 | this.styling = op.styling;
62 | this.closeButton = op.closeButton;
63 | this.onClick = op.onClick;
64 | }
65 | }
66 |
67 | class Storage {
68 | Storage: Array = [];
69 | Listener: (storage: any) => void = () => this.Storage;
70 |
71 | popAndPush = (NotificationId: number) => {
72 | let i: number = 0;
73 | while (i < this.Storage.length) {
74 | if (this.Storage[i].id === NotificationId) {
75 | this.Storage.splice(i, 1);
76 | }
77 | else {
78 | ++i;
79 | }
80 | }
81 | this.Listener(this.Storage);
82 | };
83 |
84 | setTimer = (NotificationId: number, duration: number) => {
85 | setTimeout(() => this.popAndPush(NotificationId), duration);
86 | };
87 |
88 | addListener = (listener: (v: Array) => void): void => {
89 | this.Listener = listener;
90 | };
91 |
92 | addNativeNotification = async (options: Options): Promise => {
93 | const { title, subtitle, message, duration, icon, vibrate, silent, onClick } = options;
94 | if (Notification.permission === 'default' || Notification.permission === 'denied') {
95 | await Notification.requestPermission();
96 | }
97 | if (Notification.permission === 'granted') {
98 | const not: Notification = new Notification(title, {
99 | body: message,
100 | data: subtitle,
101 | icon,
102 | vibrate,
103 | silent
104 | });
105 | not.onclick = onClick || null;
106 | setTimeout(not.close.bind(not), duration || defaultDuration);
107 | }
108 | };
109 |
110 | addWebNotification = (options: Options): void => {
111 | const { title, subtitle, message, theme, duration, backgroundBottom, backgroundTop, colorBottom, colorTop, closeButton, onClick } = options;
112 | const styling: Styling = {
113 | backgroundTop,
114 | backgroundBottom,
115 | colorTop,
116 | colorBottom
117 | };
118 | const newNotification: PushNotification = new PushNotification({ title, subtitle, message, theme, styling, closeButton, onClick });
119 | this.Storage.push(newNotification);
120 | this.setTimer(newNotification.id, duration || defaultDuration);
121 | this.Listener(this.Storage);
122 | };
123 |
124 | addNotification = async (options: Options): Promise => {
125 | const { native } = options;
126 | if (native) {
127 | return this.addNativeNotification(options);
128 | }
129 | return this.addWebNotification(options);
130 |
131 | };
132 | }
133 |
134 | export default new Storage();
135 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "jsx": "react",
4 | "esModuleInterop": true,
5 | "target": "ES6",
6 | "module": "commonjs",
7 | "declaration": true,
8 | "noImplicitAny": true,
9 | "removeComments": false,
10 | "outDir": "dist/",
11 | "rootDir": "src",
12 | "strict": true
13 | },
14 | "include": [
15 | "src/**/*"
16 | ],
17 | "exclude": [
18 | "node_modules",
19 | "dist",
20 | "**/*.spec.ts"
21 | ]
22 | }
--------------------------------------------------------------------------------