├── .babelrc
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── dist
├── components
│ ├── Notification.js
│ └── NotificationContainer.js
├── index.js
├── styles
│ └── NotificationStyles.js
└── utils
│ ├── constants.js
│ └── notification.js
├── examples
└── src
│ ├── index.html
│ └── index.js
├── package-lock.json
├── package.json
├── react-notification.gif
├── src
├── components
│ ├── Notification.js
│ └── NotificationContainer.js
├── index.js
├── styles
│ └── NotificationStyles.js
└── utils
│ ├── constants.js
│ └── notification.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env", "react"]
3 | }
4 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | webpack.config.js
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "react-app"
3 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | dist
3 | node_modules
4 | *.log
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # .npmignore
2 | src
3 | examples
4 | .babelrc
5 | .gitignore
6 | webpack.config.js
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Khuong Pham
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.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-notification
2 |
3 | [](http://badge.fury.io/js/react-notification-popup) [](https://www.npmjs.com/package/react-notification-popup) [](https://david-dm.org/igorprado/react-notification-popup) [](https://david-dm.org/igorprado/react-notification-popup#info=devDependencies) [](https://travis-ci.org/igorprado/react-notification-popup) [](https://coveralls.io/github/igorprado/react-notification-popup?branch=master)
4 |
5 | A complete and totally customizable component for notifications in React
6 |
7 | 
8 |
9 | ## Advanced notification system specification
10 |
11 | - You can request a notification to be displayed.
12 | - You can request a notification to hide.
13 | - A notification should not be displayed more than 5 seconds.
14 | - Multiple notifications can be displayed at the same time.
15 | - No more than 3 notifications can be displayed at the same time.
16 | - If a notification is requested while there are already 3 displayed notifications, then queue/postpone it.
17 |
18 | ## Installing
19 |
20 | ```
21 | npm install react-notification-popup
22 | ```
23 |
24 | ## Contributing
25 |
26 | 1. Fork project
27 | 2. Checkout **master** branch
28 | 3. Create **Feature** branch off of the **master** branch
29 | 4. Create awesome feature/enhancement/bug-fix
30 | 5. Optionally create _Issue_ to discuss feature
31 | 6. Submit pull request from your **Feature** branch to react-notification's **master** branch
32 |
33 | ## Using
34 |
35 | ```js
36 | import React from "react";
37 | import { render } from "react-dom";
38 | import { notification, NotificationContainer } from "react-notification-popup";
39 |
40 | notification.config = {
41 | maxNotifications: 3,
42 | notificationDisplayTime: 5000
43 | };
44 |
45 | const App = () => (
46 |
47 |
48 | {
50 | notification.emit(
51 | {
52 | providerURL:
53 | "http://icons.iconarchive.com/icons/johanchalibert/mac-osx-yosemite/1024/finder-icon.png",
54 | title: "Disk Not Ejected Properly",
55 | description:
56 | "Eject Time Machine before disconnecting or turning it off"
57 | },
58 | {
59 | onClick: () => console.log("Click!!"),
60 | onClose: () => console.log("Close!!")
61 | }
62 | );
63 | }}
64 | >
65 | show
66 |
67 | {
69 | notification.dismissAll();
70 | }}
71 | >
72 | dismissAll
73 |
74 |
75 | );
76 |
77 | render( , document.getElementById("root"));
78 | ```
79 |
80 | ## Methods
81 |
82 | ```js
83 | config: ({ maxNotifications, notificationDisplayTime });
84 | ```
85 |
86 | Configure notification. This is optional. The default maxNotifications is 3 and notificationDisplayTime is 5s.
87 |
88 | ```js
89 | emit: (
90 | {
91 | providerURL,
92 | title,
93 | description,
94 | closeButtonText = "Close",
95 | hasCloseButton = true,
96 | autoClose = true
97 | },
98 | { onClick = noop, onClose = noop }
99 | )
100 | ```
101 |
102 | Emit notification with some informations and callback handler.
103 |
104 | ```js
105 | dismissAll: onDismiss = noop;
106 | ```
107 |
108 | Removes ALL notifications programatically.
109 |
110 | ## Author
111 |
112 | [Khuong Pham](https://khuong291.github.io/home/)
113 |
114 | ## License
115 |
116 | react-notification-popup is released under the MIT license.
117 | See LICENSE for details.
118 |
--------------------------------------------------------------------------------
/dist/components/Notification.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | 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; }; }();
8 |
9 | var _react = require("react");
10 |
11 | var React = _interopRequireWildcard(_react);
12 |
13 | var _propTypes = require("prop-types");
14 |
15 | var _propTypes2 = _interopRequireDefault(_propTypes);
16 |
17 | var _notification = require("../utils/notification");
18 |
19 | var _notification2 = _interopRequireDefault(_notification);
20 |
21 | var _constants = require("../utils/constants");
22 |
23 | var _NotificationStyles = require("../styles/NotificationStyles");
24 |
25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
26 |
27 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
28 |
29 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
30 |
31 | 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; }
32 |
33 | 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; }
34 |
35 | var Notification = function (_React$Component) {
36 | _inherits(Notification, _React$Component);
37 |
38 | function Notification(props) {
39 | _classCallCheck(this, Notification);
40 |
41 | var _this = _possibleConstructorReturn(this, (Notification.__proto__ || Object.getPrototypeOf(Notification)).call(this, props));
42 |
43 | _this.state = {
44 | isClosed: false,
45 | isClicked: false
46 | };
47 | return _this;
48 | }
49 |
50 | _createClass(Notification, [{
51 | key: "componentDidMount",
52 | value: function componentDidMount() {
53 | var _this2 = this;
54 |
55 | this._mounted = true;
56 | if (this.props.autoClose) {
57 | setTimeout(function () {
58 | if (_this2._mounted) {
59 | _this2.setState({
60 | isClosed: true
61 | }, function () {
62 | _this2.props.onClose();
63 | setTimeout(function () {
64 | _notification2.default.onClose(_this2.props.id);
65 | }, 500);
66 | });
67 | }
68 | }, _constants.NotificationDisplayTime);
69 | }
70 | }
71 | }, {
72 | key: "componentWillUnmount",
73 | value: function componentWillUnmount() {
74 | this._mounted = false;
75 | }
76 | }, {
77 | key: "_onClose",
78 | value: function _onClose() {
79 | var _this3 = this;
80 |
81 | this.setState({
82 | isClosed: true
83 | }, function () {
84 | setTimeout(function () {
85 | _this3.props.onClose();
86 | _notification2.default.onClose(_this3.props.id);
87 | }, 500);
88 | });
89 | }
90 | }, {
91 | key: "_onClick",
92 | value: function _onClick() {
93 | var _this4 = this;
94 |
95 | this.setState({
96 | isClicked: true
97 | }, function () {
98 | setTimeout(function () {
99 | _this4.props.onClick();
100 | _notification2.default.onClose(_this4.props.id);
101 | }, 300);
102 | });
103 | }
104 | }, {
105 | key: "render",
106 | value: function render() {
107 | var Container = this.state.isClicked ? _NotificationStyles.FadeInContainer : this.state.isClosed ? _NotificationStyles.ClosedContainer : _NotificationStyles.OpenedContainer;
108 | return React.createElement(
109 | Container,
110 | null,
111 | React.createElement(
112 | _NotificationStyles.ContentBox,
113 | {
114 | hasCloseButton: this.props.hasCloseButton,
115 | onClick: this._onClick.bind(this)
116 | },
117 | React.createElement(_NotificationStyles.ProviderImage, { src: this.props.providerURL }),
118 | React.createElement(
119 | _NotificationStyles.TextBox,
120 | { hasCloseButton: this.props.hasCloseButton },
121 | React.createElement(
122 | _NotificationStyles.Title,
123 | null,
124 | this.props.title
125 | ),
126 | React.createElement(
127 | _NotificationStyles.Description,
128 | null,
129 | this.props.description
130 | )
131 | )
132 | ),
133 | this.props.hasCloseButton && React.createElement(
134 | _NotificationStyles.HandleBox,
135 | null,
136 | React.createElement(
137 | _NotificationStyles.CloseButton,
138 | { onClick: this._onClose.bind(this) },
139 | this.props.closeButtonText
140 | )
141 | )
142 | );
143 | }
144 | }]);
145 |
146 | return Notification;
147 | }(React.Component);
148 |
149 | Notification.propTypes = {
150 | id: _propTypes2.default.number.isRequired,
151 | providerURL: _propTypes2.default.string.isRequired,
152 | title: _propTypes2.default.string.isRequired,
153 | description: _propTypes2.default.string.isRequired,
154 | closeButtonText: _propTypes2.default.string,
155 | hasCloseButton: _propTypes2.default.bool,
156 | autoClose: _propTypes2.default.bool,
157 | onClose: _propTypes2.default.func,
158 | onClick: _propTypes2.default.func
159 | };
160 |
161 | Notification.defaultProps = {
162 | hasCloseButton: true,
163 | autoClose: false,
164 | onClose: function onClose() {},
165 | onClick: function onClick() {}
166 | };
167 |
168 | exports.default = Notification;
--------------------------------------------------------------------------------
/dist/components/NotificationContainer.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | 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; }; }();
8 |
9 | var _templateObject = _taggedTemplateLiteral(["\n display: flex;\n flex-direction: column;\n margin: 4px 10px 0 0;\n width: 350px;\n float: right;\n"], ["\n display: flex;\n flex-direction: column;\n margin: 4px 10px 0 0;\n width: 350px;\n float: right;\n"]);
10 |
11 | var _react = require("react");
12 |
13 | var React = _interopRequireWildcard(_react);
14 |
15 | var _propTypes = require("prop-types");
16 |
17 | var _propTypes2 = _interopRequireDefault(_propTypes);
18 |
19 | var _Notification = require("./Notification");
20 |
21 | var _Notification2 = _interopRequireDefault(_Notification);
22 |
23 | var _constants = require("../utils/constants");
24 |
25 | var _styledComponents = require("styled-components");
26 |
27 | var _styledComponents2 = _interopRequireDefault(_styledComponents);
28 |
29 | var _notification = require("../utils/notification");
30 |
31 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
32 |
33 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
34 |
35 | function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
36 |
37 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
38 |
39 | 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; }
40 |
41 | 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; }
42 |
43 | var NotificationContainer = function (_React$Component) {
44 | _inherits(NotificationContainer, _React$Component);
45 |
46 | function NotificationContainer() {
47 | _classCallCheck(this, NotificationContainer);
48 |
49 | return _possibleConstructorReturn(this, (NotificationContainer.__proto__ || Object.getPrototypeOf(NotificationContainer)).apply(this, arguments));
50 | }
51 |
52 | _createClass(NotificationContainer, [{
53 | key: "render",
54 | value: function render() {
55 | var _this2 = this;
56 |
57 | return React.createElement(
58 | Container,
59 | { id: _constants.NotificationContainerId },
60 | _notification.queue.map(function (_ref) {
61 | var id = _ref.id,
62 | providerURL = _ref.providerURL,
63 | title = _ref.title,
64 | description = _ref.description,
65 | closeButtonText = _ref.closeButtonText,
66 | hasCloseButton = _ref.hasCloseButton,
67 | autoClose = _ref.autoClose;
68 |
69 | return React.createElement(_Notification2.default, {
70 | key: id,
71 | id: id,
72 | providerURL: providerURL,
73 | title: title,
74 | description: description,
75 | closeButtonText: closeButtonText,
76 | hasCloseButton: hasCloseButton,
77 | autoClose: autoClose,
78 | onClick: _this2.props.onClick,
79 | onClose: _this2.props.onClose
80 | });
81 | })
82 | );
83 | }
84 | }]);
85 |
86 | return NotificationContainer;
87 | }(React.Component);
88 |
89 | NotificationContainer.propTypes = {
90 | onClick: _propTypes2.default.func,
91 | onClose: _propTypes2.default.func
92 | };
93 |
94 | var Container = _styledComponents2.default.div(_templateObject);
95 |
96 | exports.default = NotificationContainer;
--------------------------------------------------------------------------------
/dist/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.NotificationContainer = exports.notification = undefined;
7 |
8 | var _NotificationContainer = require("./components/NotificationContainer");
9 |
10 | var _NotificationContainer2 = _interopRequireDefault(_NotificationContainer);
11 |
12 | var _notification = require("./utils/notification");
13 |
14 | var _notification2 = _interopRequireDefault(_notification);
15 |
16 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17 |
18 | exports.notification = _notification2.default;
19 | exports.NotificationContainer = _NotificationContainer2.default;
--------------------------------------------------------------------------------
/dist/styles/NotificationStyles.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.CloseButton = exports.HandleBox = exports.TextBox = exports.ContentBox = exports.ProviderImage = exports.Description = exports.Title = exports.FadeInContainer = exports.ClosedContainer = exports.OpenedContainer = undefined;
7 |
8 | var _templateObject = _taggedTemplateLiteral(["\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n\n to {\n transform: translateX(0%);\n opacity: 1;\n }\n"], ["\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n\n to {\n transform: translateX(0%);\n opacity: 1;\n }\n"]),
9 | _templateObject2 = _taggedTemplateLiteral(["\n from {\n transform: translateX(0%);\n opacity: 1;\n }\n\n to {\n transform: translateX(100%);\n opacity: 0;\n }\n"], ["\n from {\n transform: translateX(0%);\n opacity: 1;\n }\n\n to {\n transform: translateX(100%);\n opacity: 0;\n }\n"]),
10 | _templateObject3 = _taggedTemplateLiteral(["\n from {\n transform: scale(1, 1)\n opacity: 1;\n }\n\n to {\n transform: scale(0.3, 0.3);\n opacity: 0;\n }\n"], ["\n from {\n transform: scale(1, 1)\n opacity: 1;\n }\n\n to {\n transform: scale(0.3, 0.3);\n opacity: 0;\n }\n"]),
11 | _templateObject4 = _taggedTemplateLiteral(["\n width: 100%;\n height: 60px;\n background-color: #f6f6f6;\n float: right;\n border-radius: 6px;\n display: flex;\n flex-direction: row;\n z-index: 999;\n margin-bottom: 14px;\n -moz-box-shadow: 0 0 14px #7d7d7d;\n -webkit-box-shadow: 0 0 14px #7d7d7d;\n box-shadow: 0 0 14px #7d7d7d;\n"], ["\n width: 100%;\n height: 60px;\n background-color: #f6f6f6;\n float: right;\n border-radius: 6px;\n display: flex;\n flex-direction: row;\n z-index: 999;\n margin-bottom: 14px;\n -moz-box-shadow: 0 0 14px #7d7d7d;\n -webkit-box-shadow: 0 0 14px #7d7d7d;\n box-shadow: 0 0 14px #7d7d7d;\n"]),
12 | _templateObject5 = _taggedTemplateLiteral(["\n animation: ", " 0.5s ease-in-out;\n"], ["\n animation: ", " 0.5s ease-in-out;\n"]),
13 | _templateObject6 = _taggedTemplateLiteral(["\n animation: ", " 0.4s ease-in-out;\n"], ["\n animation: ", " 0.4s ease-in-out;\n"]),
14 | _templateObject7 = _taggedTemplateLiteral(["\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n font-size: 15px;\n color: #565656;\n font-weight: 600;\n margin-bottom: 3px;\n"], ["\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n font-size: 15px;\n color: #565656;\n font-weight: 600;\n margin-bottom: 3px;\n"]),
15 | _templateObject8 = _taggedTemplateLiteral(["\n font-size: 14px;\n color: #717171;\n display: block;\n text-overflow: ellipsis;\n overflow: hidden;\n max-height: 2em;\n line-height: 1em;\n"], ["\n font-size: 14px;\n color: #717171;\n display: block;\n text-overflow: ellipsis;\n overflow: hidden;\n max-height: 2em;\n line-height: 1em;\n"]),
16 | _templateObject9 = _taggedTemplateLiteral(["\n width: 35px;\n height: 35px;\n object-fit: scale-down;\n margin: 7px 8px 0 4px;\n"], ["\n width: 35px;\n height: 35px;\n object-fit: scale-down;\n margin: 7px 8px 0 4px;\n"]),
17 | _templateObject10 = _taggedTemplateLiteral(["\n width: ", ";\n height: 100%;\n display: flex;\n flex-direction: row;\n padding: 5px;\n cursor: pointer;\n"], ["\n width: ", ";\n height: 100%;\n display: flex;\n flex-direction: row;\n padding: 5px;\n cursor: pointer;\n"]),
18 | _templateObject11 = _taggedTemplateLiteral(["\n height: 100%;\n display: flex;\n flex-direction: column;\n max-width: ", ";\n"], ["\n height: 100%;\n display: flex;\n flex-direction: column;\n max-width: ", ";\n"]),
19 | _templateObject12 = _taggedTemplateLiteral(["\n width: 20%;\n height: 100%;\n float: right;\n text-align: center;\n border-left: 1px solid #cfcfcf;\n"], ["\n width: 20%;\n height: 100%;\n float: right;\n text-align: center;\n border-left: 1px solid #cfcfcf;\n"]),
20 | _templateObject13 = _taggedTemplateLiteral(["\n border: none;\n background: none;\n outline: none;\n font-size: 13px;\n font-weight: 600;\n color: #646464;\n text-align: center;\n height: 100%;\n width: 100%;\n border-top-right-radius: 8px;\n border-bottom-right-radius: 8px;\n cursor: pointer;\n :hover {\n background-color: #f0f0f0;\n }\n"], ["\n border: none;\n background: none;\n outline: none;\n font-size: 13px;\n font-weight: 600;\n color: #646464;\n text-align: center;\n height: 100%;\n width: 100%;\n border-top-right-radius: 8px;\n border-bottom-right-radius: 8px;\n cursor: pointer;\n :hover {\n background-color: #f0f0f0;\n }\n"]);
21 |
22 | var _styledComponents = require("styled-components");
23 |
24 | var _styledComponents2 = _interopRequireDefault(_styledComponents);
25 |
26 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
27 |
28 | function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
29 |
30 | var fromRightToLeft = (0, _styledComponents.keyframes)(_templateObject);
31 |
32 | var fromLeftToRight = (0, _styledComponents.keyframes)(_templateObject2);
33 |
34 | var fadeIn = (0, _styledComponents.keyframes)(_templateObject3);
35 |
36 | var Container = _styledComponents2.default.div(_templateObject4);
37 |
38 | var OpenedContainer = exports.OpenedContainer = Container.extend(_templateObject5, fromRightToLeft);
39 |
40 | var ClosedContainer = exports.ClosedContainer = Container.extend(_templateObject5, fromLeftToRight);
41 |
42 | var FadeInContainer = exports.FadeInContainer = Container.extend(_templateObject6, fadeIn);
43 |
44 | var Title = exports.Title = _styledComponents2.default.div(_templateObject7);
45 |
46 | var Description = exports.Description = _styledComponents2.default.div(_templateObject8);
47 |
48 | var ProviderImage = exports.ProviderImage = _styledComponents2.default.img(_templateObject9);
49 |
50 | var ContentBox = exports.ContentBox = _styledComponents2.default.div(_templateObject10, function (props) {
51 | return props.hasCloseButton ? "80%" : "100%";
52 | });
53 |
54 | var TextBox = exports.TextBox = _styledComponents2.default.div(_templateObject11, function (props) {
55 | return props.hasCloseButton ? "200px" : "100%";
56 | });
57 |
58 | var HandleBox = exports.HandleBox = _styledComponents2.default.div(_templateObject12);
59 |
60 | var CloseButton = exports.CloseButton = _styledComponents2.default.button(_templateObject13);
--------------------------------------------------------------------------------
/dist/utils/constants.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | var MaxNotifications = exports.MaxNotifications = 3;
7 | var NotificationDisplayTime = exports.NotificationDisplayTime = 5000;
8 | var NotificationContainerId = exports.NotificationContainerId = "react-notification";
--------------------------------------------------------------------------------
/dist/utils/notification.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.queue = undefined;
7 |
8 | var _constants = require("./constants");
9 |
10 | var C = _interopRequireWildcard(_constants);
11 |
12 | var _reactDom = require("react-dom");
13 |
14 | var _reactDom2 = _interopRequireDefault(_reactDom);
15 |
16 | var _react = require("react");
17 |
18 | var _react2 = _interopRequireDefault(_react);
19 |
20 | var _NotificationContainer = require("../components/NotificationContainer");
21 |
22 | var _NotificationContainer2 = _interopRequireDefault(_NotificationContainer);
23 |
24 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
25 |
26 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
27 |
28 | var queue = exports.queue = [];
29 | var fullQueue = [];
30 | var notificationId = 0;
31 | var noop = function noop() {};
32 |
33 | var notification = Object.assign({
34 | config: function config(_ref) {
35 | var maxNotifications = _ref.maxNotifications,
36 | notificationDisplayTime = _ref.notificationDisplayTime;
37 |
38 | C.MaxNotifications = maxNotifications, C.NotificationDisplayTime = notificationDisplayTime;
39 | },
40 | emit: function emit(_ref2, _ref3) {
41 | var providerURL = _ref2.providerURL,
42 | title = _ref2.title,
43 | description = _ref2.description,
44 | _ref2$closeButtonText = _ref2.closeButtonText,
45 | closeButtonText = _ref2$closeButtonText === undefined ? "Close" : _ref2$closeButtonText,
46 | _ref2$hasCloseButton = _ref2.hasCloseButton,
47 | hasCloseButton = _ref2$hasCloseButton === undefined ? true : _ref2$hasCloseButton,
48 | _ref2$autoClose = _ref2.autoClose,
49 | autoClose = _ref2$autoClose === undefined ? true : _ref2$autoClose;
50 | var _ref3$onClick = _ref3.onClick,
51 | onClick = _ref3$onClick === undefined ? noop : _ref3$onClick,
52 | _ref3$onClose = _ref3.onClose,
53 | onClose = _ref3$onClose === undefined ? noop : _ref3$onClose;
54 |
55 | fullQueue.push({
56 | id: notificationId++,
57 | providerURL: providerURL,
58 | title: title,
59 | description: description,
60 | closeButtonText: closeButtonText,
61 | hasCloseButton: hasCloseButton,
62 | autoClose: autoClose
63 | });
64 | exports.queue = queue = fullQueue.slice(0, C.MaxNotifications);
65 | var target = document.getElementById(_constants.NotificationContainerId);
66 | _reactDom2.default.render(_react2.default.createElement(_NotificationContainer2.default, { onClick: onClick, onClose: onClose }), target);
67 | },
68 | dismissAll: function dismissAll() {
69 | var onDismiss = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : noop;
70 |
71 | fullQueue = [];
72 | exports.queue = queue = [];
73 | notificationId = 0;
74 | var target = document.getElementById(_constants.NotificationContainerId);
75 | _reactDom2.default.unmountComponentAtNode(target);
76 | onDismiss();
77 | },
78 | onClose: function onClose(id) {
79 | fullQueue = fullQueue.filter(function (i) {
80 | return i.id !== id;
81 | });
82 | exports.queue = queue = fullQueue.slice(0, C.MaxNotifications);
83 | var target = document.getElementById(_constants.NotificationContainerId);
84 | _reactDom2.default.render(_react2.default.createElement(_NotificationContainer2.default, null), target);
85 | }
86 | });
87 |
88 | exports.default = notification;
--------------------------------------------------------------------------------
/examples/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | My Component Demo
5 |
6 |
7 |
8 |
9 |
10 |
11 | You need to enable JavaScript to run this app.
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/examples/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "react-dom";
3 | import { notification, NotificationContainer } from "../../src";
4 |
5 | notification.config = {
6 | maxNotifications: 3,
7 | notificationDisplayTime: 5000
8 | };
9 |
10 | const App = () => (
11 |
12 |
13 | {
15 | notification.emit(
16 | {
17 | providerURL:
18 | "http://icons.iconarchive.com/icons/johanchalibert/mac-osx-yosemite/1024/finder-icon.png",
19 | title: "Disk Not Ejected Properly",
20 | description:
21 | "Eject Time Machine before disconnecting or turning it off"
22 | },
23 | {
24 | onClick: () => console.log("Click!!"),
25 | onClose: () => console.log("Close!!")
26 | }
27 | );
28 | }}
29 | >
30 | show
31 |
32 | {
34 | notification.dismissAll();
35 | }}
36 | >
37 | dismissAll
38 |
39 |
40 | );
41 |
42 | render( , document.getElementById("root"));
43 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-notification-popup",
3 | "version": "0.1.2",
4 | "description": "A complete and totally customizable component for notifications in React",
5 | "main": "dist/index.js",
6 | "keywords": [
7 | "react",
8 | "notification",
9 | "toast",
10 | "react-component",
11 | "react-notification",
12 | "push",
13 | "alert"
14 | ],
15 | "scripts": {
16 | "test": "echo \"Error: no test specified\" && exit 1",
17 | "start": "webpack-dev-server --mode development",
18 | "transpile": "babel src -d dist --copy-files",
19 | "prepublishOnly": "npm run transpile",
20 | "build": "webpack --mode production",
21 | "deploy": "gh-pages -d examples/dist",
22 | "publish-demo": "npm run build && npm run deploy"
23 | },
24 | "author": "khuong291 ",
25 | "repository": "https://github.com/khuong291/react-notification.git",
26 | "license": "MIT",
27 | "peerDependencies": {
28 | "react": "^16.3.0",
29 | "react-dom": "^16.3.0"
30 | },
31 | "dependencies": {},
32 | "devDependencies": {
33 | "babel-cli": "^6.26.0",
34 | "babel-core": "^6.26.3",
35 | "babel-loader": "^7.1.4",
36 | "babel-preset-env": "^1.7.0",
37 | "babel-preset-react": "^6.24.1",
38 | "css-loader": "^1.0.0",
39 | "gh-pages": "^1.2.0",
40 | "html-webpack-plugin": "^3.2.0",
41 | "react": "^16.4.2",
42 | "react-dom": "^16.4.2",
43 | "style-loader": "^0.23.0",
44 | "styled-components": "^3.4.5",
45 | "webpack": "^4.17.1",
46 | "webpack-cli": "^3.1.0",
47 | "webpack-dev-server": "^3.1.7"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/react-notification.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khuong291/react-notification/db5bae69dc6b5b11061a22156501f6bee1c930b8/react-notification.gif
--------------------------------------------------------------------------------
/src/components/Notification.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import PropTypes from "prop-types";
3 | import notification from "../utils/notification";
4 | import { NotificationDisplayTime } from "../utils/constants";
5 | import {
6 | OpenedContainer,
7 | ClosedContainer,
8 | FadeInContainer,
9 | Title,
10 | Description,
11 | ProviderImage,
12 | ContentBox,
13 | TextBox,
14 | HandleBox,
15 | CloseButton
16 | } from "../styles/NotificationStyles";
17 |
18 | class Notification extends React.Component {
19 | constructor(props) {
20 | super(props);
21 | this.state = {
22 | isClosed: false,
23 | isClicked: false
24 | };
25 | }
26 |
27 | componentDidMount() {
28 | this._mounted = true;
29 | if (this.props.autoClose) {
30 | setTimeout(() => {
31 | if (this._mounted) {
32 | this.setState(
33 | {
34 | isClosed: true
35 | },
36 | () => {
37 | this.props.onClose();
38 | setTimeout(() => {
39 | notification.onClose(this.props.id);
40 | }, 500);
41 | }
42 | );
43 | }
44 | }, NotificationDisplayTime);
45 | }
46 | }
47 |
48 | componentWillUnmount() {
49 | this._mounted = false;
50 | }
51 |
52 | _onClose() {
53 | this.setState(
54 | {
55 | isClosed: true
56 | },
57 | () => {
58 | setTimeout(() => {
59 | this.props.onClose();
60 | notification.onClose(this.props.id);
61 | }, 500);
62 | }
63 | );
64 | }
65 |
66 | _onClick() {
67 | this.setState(
68 | {
69 | isClicked: true
70 | },
71 | () => {
72 | setTimeout(() => {
73 | this.props.onClick();
74 | notification.onClose(this.props.id);
75 | }, 300);
76 | }
77 | );
78 | }
79 |
80 | render() {
81 | const Container = this.state.isClicked
82 | ? FadeInContainer
83 | : this.state.isClosed
84 | ? ClosedContainer
85 | : OpenedContainer;
86 | return (
87 |
88 |
92 |
93 |
94 | {this.props.title}
95 | {this.props.description}
96 |
97 |
98 | {this.props.hasCloseButton && (
99 |
100 |
101 | {this.props.closeButtonText}
102 |
103 |
104 | )}
105 |
106 | );
107 | }
108 | }
109 |
110 | Notification.propTypes = {
111 | id: PropTypes.number.isRequired,
112 | providerURL: PropTypes.string.isRequired,
113 | title: PropTypes.string.isRequired,
114 | description: PropTypes.string.isRequired,
115 | closeButtonText: PropTypes.string,
116 | hasCloseButton: PropTypes.bool,
117 | autoClose: PropTypes.bool,
118 | onClose: PropTypes.func,
119 | onClick: PropTypes.func
120 | };
121 |
122 | Notification.defaultProps = {
123 | hasCloseButton: true,
124 | autoClose: false,
125 | onClose: () => {},
126 | onClick: () => {}
127 | };
128 |
129 | export default Notification;
130 |
--------------------------------------------------------------------------------
/src/components/NotificationContainer.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import PropTypes from "prop-types";
3 | import Notification from "./Notification";
4 | import { NotificationContainerId } from "../utils/constants";
5 | import styled from "styled-components";
6 | import { queue } from "../utils/notification";
7 |
8 | class NotificationContainer extends React.Component {
9 | render() {
10 | return (
11 |
12 | {queue.map(
13 | ({
14 | id,
15 | providerURL,
16 | title,
17 | description,
18 | closeButtonText,
19 | hasCloseButton,
20 | autoClose
21 | }) => {
22 | return (
23 |
35 | );
36 | }
37 | )}
38 |
39 | );
40 | }
41 | }
42 |
43 | NotificationContainer.propTypes = {
44 | onClick: PropTypes.func,
45 | onClose: PropTypes.func
46 | };
47 |
48 | const Container = styled.div`
49 | display: flex;
50 | flex-direction: column;
51 | margin: 4px 10px 0 0;
52 | width: 350px;
53 | float: right;
54 | `;
55 |
56 | export default NotificationContainer;
57 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import NotificationContainer from "./components/NotificationContainer";
2 | import notification from "./utils/notification";
3 |
4 | export { notification, NotificationContainer };
5 |
--------------------------------------------------------------------------------
/src/styles/NotificationStyles.js:
--------------------------------------------------------------------------------
1 | import styled, { keyframes } from "styled-components";
2 |
3 | const fromRightToLeft = keyframes`
4 | from {
5 | transform: translateX(100%);
6 | opacity: 0;
7 | }
8 |
9 | to {
10 | transform: translateX(0%);
11 | opacity: 1;
12 | }
13 | `;
14 |
15 | const fromLeftToRight = keyframes`
16 | from {
17 | transform: translateX(0%);
18 | opacity: 1;
19 | }
20 |
21 | to {
22 | transform: translateX(100%);
23 | opacity: 0;
24 | }
25 | `;
26 |
27 | const fadeIn = keyframes`
28 | from {
29 | transform: scale(1, 1)
30 | opacity: 1;
31 | }
32 |
33 | to {
34 | transform: scale(0.3, 0.3);
35 | opacity: 0;
36 | }
37 | `;
38 |
39 | const Container = styled.div`
40 | width: 100%;
41 | height: 60px;
42 | background-color: #f6f6f6;
43 | float: right;
44 | border-radius: 6px;
45 | display: flex;
46 | flex-direction: row;
47 | z-index: 999;
48 | margin-bottom: 14px;
49 | -moz-box-shadow: 0 0 14px #7d7d7d;
50 | -webkit-box-shadow: 0 0 14px #7d7d7d;
51 | box-shadow: 0 0 14px #7d7d7d;
52 | `;
53 |
54 | export const OpenedContainer = Container.extend`
55 | animation: ${fromRightToLeft} 0.5s ease-in-out;
56 | `;
57 |
58 | export const ClosedContainer = Container.extend`
59 | animation: ${fromLeftToRight} 0.5s ease-in-out;
60 | `;
61 |
62 | export const FadeInContainer = Container.extend`
63 | animation: ${fadeIn} 0.4s ease-in-out;
64 | `;
65 |
66 | export const Title = styled.div`
67 | text-overflow: ellipsis;
68 | overflow: hidden;
69 | white-space: nowrap;
70 | font-size: 15px;
71 | color: #565656;
72 | font-weight: 600;
73 | margin-bottom: 3px;
74 | `;
75 |
76 | export const Description = styled.div`
77 | font-size: 14px;
78 | color: #717171;
79 | display: block;
80 | text-overflow: ellipsis;
81 | overflow: hidden;
82 | max-height: 2em;
83 | line-height: 1em;
84 | `;
85 |
86 | export const ProviderImage = styled.img`
87 | width: 35px;
88 | height: 35px;
89 | object-fit: scale-down;
90 | margin: 7px 8px 0 4px;
91 | `;
92 |
93 | export const ContentBox = styled.div`
94 | width: ${props => (props.hasCloseButton ? "80%" : "100%")};
95 | height: 100%;
96 | display: flex;
97 | flex-direction: row;
98 | padding: 5px;
99 | cursor: pointer;
100 | `;
101 |
102 | export const TextBox = styled.div`
103 | height: 100%;
104 | display: flex;
105 | flex-direction: column;
106 | max-width: ${props => (props.hasCloseButton ? "200px" : "100%")};
107 | `;
108 |
109 | export const HandleBox = styled.div`
110 | width: 20%;
111 | height: 100%;
112 | float: right;
113 | text-align: center;
114 | border-left: 1px solid #cfcfcf;
115 | `;
116 |
117 | export const CloseButton = styled.button`
118 | border: none;
119 | background: none;
120 | outline: none;
121 | font-size: 13px;
122 | font-weight: 600;
123 | color: #646464;
124 | text-align: center;
125 | height: 100%;
126 | width: 100%;
127 | border-top-right-radius: 8px;
128 | border-bottom-right-radius: 8px;
129 | cursor: pointer;
130 | :hover {
131 | background-color: #f0f0f0;
132 | }
133 | `;
134 |
--------------------------------------------------------------------------------
/src/utils/constants.js:
--------------------------------------------------------------------------------
1 | export let MaxNotifications = 3;
2 | export let NotificationDisplayTime = 5000;
3 | export const NotificationContainerId = "react-notification";
4 |
--------------------------------------------------------------------------------
/src/utils/notification.js:
--------------------------------------------------------------------------------
1 | import { NotificationContainerId } from "./constants";
2 | import ReactDOM from "react-dom";
3 | import React from "react";
4 | import NotificationContainer from "../components/NotificationContainer";
5 | import * as C from "./constants";
6 |
7 | export let queue = [];
8 | let fullQueue = [];
9 | let notificationId = 0;
10 | const noop = () => {};
11 |
12 | const notification = Object.assign({
13 | config: ({ maxNotifications, notificationDisplayTime }) => {
14 | (C.MaxNotifications = maxNotifications),
15 | (C.NotificationDisplayTime = notificationDisplayTime);
16 | },
17 | emit: (
18 | {
19 | providerURL,
20 | title,
21 | description,
22 | closeButtonText = "Close",
23 | hasCloseButton = true,
24 | autoClose = true
25 | },
26 | { onClick = noop, onClose = noop }
27 | ) => {
28 | fullQueue.push({
29 | id: notificationId++,
30 | providerURL,
31 | title,
32 | description,
33 | closeButtonText,
34 | hasCloseButton,
35 | autoClose
36 | });
37 | queue = fullQueue.slice(0, C.MaxNotifications);
38 | let target = document.getElementById(NotificationContainerId);
39 | ReactDOM.render(
40 | ,
41 | target
42 | );
43 | },
44 | dismissAll: (onDismiss = noop) => {
45 | fullQueue = [];
46 | queue = [];
47 | notificationId = 0;
48 | let target = document.getElementById(NotificationContainerId);
49 | ReactDOM.unmountComponentAtNode(target);
50 | onDismiss();
51 | },
52 | onClose: id => {
53 | fullQueue = fullQueue.filter(i => i.id !== id);
54 | queue = fullQueue.slice(0, C.MaxNotifications);
55 | let target = document.getElementById(NotificationContainerId);
56 | ReactDOM.render( , target);
57 | }
58 | });
59 |
60 | export default notification;
61 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const HtmlWebpackPlugin = require("html-webpack-plugin");
3 | const htmlWebpackPlugin = new HtmlWebpackPlugin({
4 | template: path.join(__dirname, "examples/src/index.html"),
5 | filename: "./index.html"
6 | });
7 | module.exports = {
8 | entry: path.join(__dirname, "examples/src/index.js"),
9 | output: {
10 | path: path.join(__dirname, "examples/dist"),
11 | filename: "bundle.js"
12 | },
13 | module: {
14 | rules: [
15 | {
16 | test: /\.(js|jsx)$/,
17 | use: "babel-loader",
18 | exclude: /node_modules/
19 | },
20 | {
21 | test: /\.css$/,
22 | use: ["style-loader", "css-loader"]
23 | }
24 | ]
25 | },
26 | plugins: [htmlWebpackPlugin],
27 | resolve: {
28 | extensions: [".js", ".jsx"]
29 | },
30 | devServer: {
31 | port: 3001
32 | }
33 | };
34 |
--------------------------------------------------------------------------------