├── .babelrc
├── .eslintignore
├── .eslintrc
├── .gitignore
├── LICENSE
├── README.md
├── __tests__
├── .gitkeep
├── helpers
│ ├── setup-browser-env.js
│ └── setup-enzyme.js
└── popup.test.js
├── dist
├── ActionButton.react.js
├── Bem.js
├── ButtonsSpace.react.js
├── Constants.js
├── Footer.react.js
├── Header.react.js
├── Popup.react.js
├── Store.js
└── index.js
├── example
├── index.jsx
├── template.html
└── webpack.config.js
├── package.json
├── src
├── ActionButton.react.js
├── Bem.js
├── ButtonsSpace.react.js
├── Constants.js
├── Footer.react.js
├── Header.react.js
├── Popup.react.js
├── Store.js
└── index.js
├── style.css
├── webpack.config.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env",
4 | ["@babel/preset-react", {
5 | "runtime": "automatic"
6 | }]
7 | ],
8 | "plugins": [
9 | "@babel/plugin-proposal-class-properties",
10 | "@babel/plugin-proposal-object-rest-spread"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": "airbnb",
4 | "env": {
5 | "browser": true,
6 | "node": true
7 | },
8 | "rules": {
9 | "indent": ["error", 4],
10 | "react/jsx-indent": ["error", 4],
11 | "react/jsx-indent-props": ["error", 4],
12 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
13 | "import/no-unresolved": [2, {"ignore": ["src/"]}]
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | .DS_Store
4 | yarn-error.log
5 | .vscode
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Minutemailer AB
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 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Simple and powerful react popup component. Part of Minutemailer.com - Marketing Simplified
20 |
21 |
22 |
23 | ## Breaking changes in 0.9.x
24 |
25 | The popup and overlay is now two separate layers to allow more customization. See [demo css](https://github.com/minutemailer/react-popup/blob/gh-pages/popup.example.css) for styling example.
26 |
27 | ## Global API approach
28 |
29 | The idea behind `react-popup` is to use it as a drop-in replacement for the native `window.alert`. With the similarity of only displaying one popup at a time. This is why we use a global API to control the component instead of rendering it inside components. Maybe this is an anti-pattern, maybe it's not. Feel free to discuss it by opening an issue if one doesn't already exist.
30 |
31 | ## Install
32 |
33 | Install it with npm (or yarn) (`npm install react-popup --save`). The component is API driven and means that you only render it once, on a global level. Here's a simple example:
34 |
35 | ```jsx
36 | import React from 'react';
37 | import ReactDom from 'react-dom';
38 | import Popup from 'react-popup';
39 |
40 | ReactDom.render(
41 | ,
42 | document.getElementById('popupContainer')
43 | );
44 |
45 | Popup.alert('Hello');
46 | ```
47 |
48 | ## Documentation
49 |
50 | Documentation and demo can be found here: http://minutemailer.github.io/react-popup/
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/__tests__/.gitkeep:
--------------------------------------------------------------------------------
1 | .gitkeep
--------------------------------------------------------------------------------
/__tests__/helpers/setup-browser-env.js:
--------------------------------------------------------------------------------
1 | import browserEnv from 'browser-env';
2 | browserEnv(['window', 'document', 'navigator']);
3 |
4 | global.requestAnimationFrame = (callback) => {
5 | setTimeout(callback, 0);
6 | };
7 |
--------------------------------------------------------------------------------
/__tests__/helpers/setup-enzyme.js:
--------------------------------------------------------------------------------
1 | import { configure } from 'enzyme';
2 | import Adapter from 'enzyme-adapter-react-16';
3 |
4 | configure({ adapter: new Adapter() });
5 |
--------------------------------------------------------------------------------
/__tests__/popup.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava';
2 | import React from 'react';
3 | import { shallow } from 'enzyme';
4 | import Popup from '../src/Popup.react';
5 |
6 | test('Initialization works', (t) => {
7 | const component = shallow( );
8 |
9 | t.true(component.hasClass('popup'));
10 | t.is(component.find('.popup__overlay').length, 1);
11 | });
12 |
13 | test('Display and hide popup', (t) => {
14 | const component = shallow( );
15 |
16 | Popup.create({});
17 | component.update();
18 |
19 | t.is(component.find('.popup__box').length, 1);
20 |
21 | Popup.close();
22 | component.update();
23 |
24 | t.is(component.find('.popup__box').length, 0);
25 | });
26 |
--------------------------------------------------------------------------------
/dist/ActionButton.react.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
4 |
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 | exports["default"] = void 0;
9 |
10 | var _react = _interopRequireDefault(require("react"));
11 |
12 | var _propTypes = _interopRequireDefault(require("prop-types"));
13 |
14 | var _jsxRuntime = require("react/jsx-runtime");
15 |
16 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
17 |
18 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
19 |
20 | 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); } }
21 |
22 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
23 |
24 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }
25 |
26 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
27 |
28 | function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
29 |
30 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }
31 |
32 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
33 |
34 | function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
35 |
36 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
37 |
38 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
39 |
40 | var PopupAction = /*#__PURE__*/function (_React$Component) {
41 | _inherits(PopupAction, _React$Component);
42 |
43 | var _super = _createSuper(PopupAction);
44 |
45 | function PopupAction() {
46 | _classCallCheck(this, PopupAction);
47 |
48 | return _super.apply(this, arguments);
49 | }
50 |
51 | _createClass(PopupAction, [{
52 | key: "handleClick",
53 | value: function handleClick() {
54 | return this.props.onClick();
55 | }
56 | }, {
57 | key: "render",
58 | value: function render() {
59 | var _this = this;
60 |
61 | var className = this.props.className;
62 |
63 | if (this.props.url && this.props.url !== '#') {
64 | return /*#__PURE__*/(0, _jsxRuntime.jsx)("a", {
65 | href: this.props.url,
66 | target: "_blank",
67 | className: className,
68 | children: this.props.children
69 | });
70 | }
71 |
72 | return /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
73 | onClick: function onClick() {
74 | return _this.handleClick();
75 | },
76 | className: className,
77 | children: this.props.children
78 | });
79 | }
80 | }]);
81 |
82 | return PopupAction;
83 | }(_react["default"].Component);
84 |
85 | _defineProperty(PopupAction, "defaultProps", {
86 | onClick: function onClick() {},
87 | className: 'btn',
88 | url: null
89 | });
90 |
91 | PopupAction.propTypes = {
92 | onClick: _propTypes["default"].func,
93 | className: _propTypes["default"].string,
94 | children: _propTypes["default"].node.isRequired,
95 | url: _propTypes["default"].string
96 | };
97 | var _default = PopupAction;
98 | exports["default"] = _default;
--------------------------------------------------------------------------------
/dist/Bem.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.modifier = exports.element = void 0;
7 |
8 | var element = function element(el, base) {
9 | return "".concat(base, "__").concat(el);
10 | };
11 |
12 | exports.element = element;
13 |
14 | var modifier = function modifier(modifiers, base) {
15 | if (!modifiers) {
16 | return null;
17 | }
18 |
19 | var finalClass = [];
20 | var classNames = modifiers.split(' ');
21 | classNames.forEach(function (singleClass) {
22 | finalClass.push("".concat(base, "--").concat(singleClass));
23 | });
24 | return finalClass.join(' ');
25 | };
26 |
27 | exports.modifier = modifier;
--------------------------------------------------------------------------------
/dist/ButtonsSpace.react.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
4 |
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 | exports["default"] = void 0;
9 |
10 | var _react = _interopRequireDefault(require("react"));
11 |
12 | var _propTypes = _interopRequireDefault(require("prop-types"));
13 |
14 | var _ActionButton = _interopRequireDefault(require("./ActionButton.react"));
15 |
16 | var _Bem = require("./Bem");
17 |
18 | var _jsxRuntime = require("react/jsx-runtime");
19 |
20 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
21 |
22 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
23 |
24 | 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); } }
25 |
26 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
27 |
28 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }
29 |
30 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
31 |
32 | function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
33 |
34 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }
35 |
36 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
37 |
38 | function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
39 |
40 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
41 |
42 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
43 |
44 | var PopupFooterButtons = /*#__PURE__*/function (_React$Component) {
45 | _inherits(PopupFooterButtons, _React$Component);
46 |
47 | var _super = _createSuper(PopupFooterButtons);
48 |
49 | function PopupFooterButtons() {
50 | _classCallCheck(this, PopupFooterButtons);
51 |
52 | return _super.apply(this, arguments);
53 | }
54 |
55 | _createClass(PopupFooterButtons, [{
56 | key: "onOk",
57 | value: function onOk() {
58 | return this.props.onOk();
59 | }
60 | }, {
61 | key: "onClose",
62 | value: function onClose() {
63 | return this.props.onClose();
64 | }
65 | }, {
66 | key: "buttonClick",
67 | value: function buttonClick(action) {
68 | return this.props.buttonClick(action);
69 | }
70 | }, {
71 | key: "render",
72 | value: function render() {
73 | var _this = this;
74 |
75 | if (!this.props.buttons) {
76 | return null;
77 | }
78 |
79 | var btns = [];
80 | this.props.buttons.forEach(function (btn, i) {
81 | var url = btn.url ? btn.url : null;
82 | var key = i;
83 |
84 | if (typeof btn === 'string') {
85 | if (btn === 'ok') {
86 | btns.push( /*#__PURE__*/(0, _jsxRuntime.jsx)(_ActionButton["default"], {
87 | className: "".concat(_this.props.btnClass, " ").concat(_this.props.btnClass, "--ok"),
88 | onClick: function onClick() {
89 | return _this.onOk();
90 | },
91 | children: _this.props.defaultOk
92 | }, key));
93 | } else if (btn === 'cancel') {
94 | btns.push( /*#__PURE__*/(0, _jsxRuntime.jsx)(_ActionButton["default"], {
95 | className: "".concat(_this.props.btnClass, " ").concat(_this.props.btnClass, "--cancel"),
96 | onClick: function onClick() {
97 | return _this.onClose();
98 | },
99 | children: _this.props.defaultCancel
100 | }, key));
101 | }
102 | } else if ( /*#__PURE__*/_react["default"].isValidElement(btn)) {
103 | btns.push(btn);
104 | } else {
105 | var className = "".concat(_this.props.btnClass, " ").concat((0, _Bem.modifier)(btn.className, _this.props.btnClass));
106 | var btnComponent = /*#__PURE__*/(0, _jsxRuntime.jsx)(_ActionButton["default"], {
107 | className: className,
108 | url: url,
109 | onClick: function onClick() {
110 | return _this.buttonClick(btn.action);
111 | },
112 | children: btn.text
113 | }, key);
114 | btns.push(btnComponent);
115 | }
116 | });
117 | return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
118 | className: this.props.className,
119 | children: btns
120 | });
121 | }
122 | }]);
123 |
124 | return PopupFooterButtons;
125 | }(_react["default"].Component);
126 |
127 | exports["default"] = PopupFooterButtons;
128 |
129 | _defineProperty(PopupFooterButtons, "defaultProps", {
130 | buttons: null,
131 | className: null,
132 | onOk: function onOk() {},
133 | onClose: function onClose() {},
134 | buttonClick: function buttonClick() {},
135 | btnClass: null,
136 | defaultOk: null,
137 | defaultCancel: null
138 | });
139 |
140 | PopupFooterButtons.propTypes = {
141 | buttons: _propTypes["default"].arrayOf(_propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].object])),
142 | className: _propTypes["default"].string,
143 | onOk: _propTypes["default"].func,
144 | onClose: _propTypes["default"].func,
145 | buttonClick: _propTypes["default"].func,
146 | btnClass: _propTypes["default"].string,
147 | defaultOk: _propTypes["default"].string,
148 | defaultCancel: _propTypes["default"].string
149 | };
--------------------------------------------------------------------------------
/dist/Constants.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 | var _default = {
8 | SHOW: 'SHOW',
9 | CLOSE: 'CLOSE',
10 | REFRESH: 'REFRESH'
11 | };
12 | exports["default"] = _default;
--------------------------------------------------------------------------------
/dist/Footer.react.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _propTypes = _interopRequireDefault(require("prop-types"));
9 |
10 | var _ButtonsSpace = _interopRequireDefault(require("./ButtonsSpace.react"));
11 |
12 | var _jsxRuntime = require("react/jsx-runtime");
13 |
14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
15 |
16 | var PopupFooter = function PopupFooter(props) {
17 | if (!props.buttons) {
18 | return null;
19 | }
20 |
21 | return /*#__PURE__*/(0, _jsxRuntime.jsxs)("footer", {
22 | className: props.className,
23 | children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_ButtonsSpace["default"], {
24 | buttonClick: props.buttonClick,
25 | onOk: props.onOk,
26 | onClose: props.onClose,
27 | className: "".concat(props.className, "__left-space"),
28 | btnClass: props.btnClass,
29 | defaultOk: props.defaultOk,
30 | defaultCancel: props.defaultCancel,
31 | buttons: props.buttons.left
32 | }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_ButtonsSpace["default"], {
33 | buttonClick: props.buttonClick,
34 | onOk: props.onOk,
35 | onClose: props.onClose,
36 | className: "".concat(props.className, "__right-space"),
37 | btnClass: props.btnClass,
38 | defaultOk: props.defaultOk,
39 | defaultCancel: props.defaultCancel,
40 | buttons: props.buttons.right
41 | })]
42 | });
43 | };
44 |
45 | PopupFooter.propTypes = {
46 | buttons: _propTypes["default"].shape({
47 | left: _propTypes["default"].arrayOf(_propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].object])),
48 | right: _propTypes["default"].arrayOf(_propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].object]))
49 | }),
50 | className: _propTypes["default"].string,
51 | btnClass: _propTypes["default"].string,
52 | onOk: _propTypes["default"].func,
53 | onClose: _propTypes["default"].func,
54 | buttonClick: _propTypes["default"].func,
55 | defaultOk: _propTypes["default"].string,
56 | defaultCancel: _propTypes["default"].string
57 | };
58 | PopupFooter.defaultProps = {
59 | buttons: null,
60 | className: null,
61 | btnClass: null,
62 | defaultOk: null,
63 | defaultCancel: null,
64 | buttonClick: function buttonClick() {},
65 | onOk: function onOk() {},
66 | onClose: function onClose() {}
67 | };
68 | var _default = PopupFooter;
69 | exports["default"] = _default;
--------------------------------------------------------------------------------
/dist/Header.react.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _propTypes = _interopRequireDefault(require("prop-types"));
9 |
10 | var _jsxRuntime = require("react/jsx-runtime");
11 |
12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
13 |
14 | var PopupHeader = function PopupHeader(props) {
15 | if (!props.title) {
16 | return null;
17 | }
18 |
19 | return /*#__PURE__*/(0, _jsxRuntime.jsx)("header", {
20 | className: props.className,
21 | children: /*#__PURE__*/(0, _jsxRuntime.jsx)("h1", {
22 | className: "".concat(props.className, "__title"),
23 | children: props.title
24 | })
25 | });
26 | };
27 |
28 | PopupHeader.defaultProps = {
29 | title: null,
30 | className: null
31 | };
32 | PopupHeader.propTypes = {
33 | title: _propTypes["default"].string,
34 | className: _propTypes["default"].string
35 | };
36 | var _default = PopupHeader;
37 | exports["default"] = _default;
--------------------------------------------------------------------------------
/dist/Popup.react.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
4 |
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 | exports["default"] = void 0;
9 |
10 | var _react = _interopRequireDefault(require("react"));
11 |
12 | var _propTypes = _interopRequireDefault(require("prop-types"));
13 |
14 | var _keymaster = _interopRequireDefault(require("keymaster"));
15 |
16 | var _Store = _interopRequireDefault(require("./Store"));
17 |
18 | var _Header = _interopRequireDefault(require("./Header.react"));
19 |
20 | var _Footer = _interopRequireDefault(require("./Footer.react"));
21 |
22 | var _Constants = _interopRequireDefault(require("./Constants"));
23 |
24 | var _Bem = require("./Bem");
25 |
26 | var _jsxRuntime = require("react/jsx-runtime");
27 |
28 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
29 |
30 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
31 |
32 | 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); } }
33 |
34 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
35 |
36 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }
37 |
38 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
39 |
40 | function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
41 |
42 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }
43 |
44 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
45 |
46 | function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
47 |
48 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
49 |
50 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
51 |
52 | var defaultKeyFilter = _keymaster["default"].filter;
53 | var Store = new _Store["default"]();
54 |
55 | var handleClose = function handleClose() {
56 | _keymaster["default"].deleteScope('react-popup');
57 |
58 | _keymaster["default"].filter = defaultKeyFilter;
59 | Store.close();
60 | };
61 |
62 | var initialState = {
63 | id: null,
64 | title: null,
65 | buttons: null,
66 | content: null,
67 | visible: false,
68 | className: null,
69 | noOverlay: false,
70 | position: false,
71 | closeOnOutsideClick: true,
72 | onClose: function onClose() {},
73 | onShow: function onShow() {}
74 | };
75 |
76 | var Popup = /*#__PURE__*/function (_React$Component) {
77 | _inherits(Popup, _React$Component);
78 |
79 | var _super = _createSuper(Popup);
80 |
81 | function Popup(props) {
82 | var _this;
83 |
84 | _classCallCheck(this, Popup);
85 |
86 | _this = _super.call(this, props);
87 | initialState.closeOnOutsideClick = _this.props.closeOnOutsideClick;
88 | _this.state = initialState;
89 | _this.bound = {
90 | onShow: _this.onShow.bind(_assertThisInitialized(_this)),
91 | onClose: _this.onClose.bind(_assertThisInitialized(_this)),
92 | onRefresh: _this.onRefresh.bind(_assertThisInitialized(_this)),
93 | containerClick: _this.containerClick.bind(_assertThisInitialized(_this)),
94 | handleButtonClick: _this.handleButtonClick.bind(_assertThisInitialized(_this))
95 | };
96 | _this.boxRef = null;
97 | _this.defaultKeyBindings = {
98 | ok: _this.props.defaultOkKey,
99 | cancel: _this.props.defaultCancelKey
100 | };
101 | return _this;
102 | }
103 |
104 | _createClass(Popup, [{
105 | key: "componentDidMount",
106 | value: function componentDidMount() {
107 | Store.on(_Constants["default"].SHOW, this.bound.onShow);
108 | Store.on(_Constants["default"].CLOSE, this.bound.onClose);
109 | Store.on(_Constants["default"].REFRESH, this.bound.onRefresh);
110 | }
111 | }, {
112 | key: "componentDidUpdate",
113 | value: function componentDidUpdate() {
114 | if (this.boxRef) {
115 | this.boxRef.focus();
116 | }
117 |
118 | this.setPosition(this.state.position);
119 | }
120 | }, {
121 | key: "componentWillUnmount",
122 | value: function componentWillUnmount() {
123 | Store.removeListener(_Constants["default"].SHOW, this.bound.onShow);
124 | Store.removeListener(_Constants["default"].CLOSE, this.bound.onClose);
125 | Store.removeListener(_Constants["default"].REFRESH, this.bound.onRefresh);
126 |
127 | _keymaster["default"].deleteScope('react-popup');
128 |
129 | _keymaster["default"].filter = defaultKeyFilter;
130 | }
131 | /**
132 | * Refresh popup position
133 | * @param position
134 | * @private
135 | */
136 |
137 | }, {
138 | key: "onRefresh",
139 | value: function onRefresh(position) {
140 | this.setPosition(position);
141 | }
142 | /**
143 | * On popup close
144 | * @private
145 | */
146 |
147 | }, {
148 | key: "onClose",
149 | value: function onClose() {
150 | _keymaster["default"].deleteScope('react-popup');
151 |
152 | _keymaster["default"].filter = defaultKeyFilter;
153 | this.state.onClose(this.state.id, this.state.title);
154 | this.setState(initialState);
155 | }
156 | /**
157 | * On popup show
158 | * @private
159 | */
160 |
161 | }, {
162 | key: "onShow",
163 | value: function onShow(id) {
164 | var _this2 = this;
165 |
166 | _keymaster["default"].deleteScope('react-popup');
167 |
168 | _keymaster["default"].filter = function () {
169 | return true;
170 | };
171 |
172 | var popup = Store.activePopup();
173 |
174 | if (popup.buttons && !Object.prototype.hasOwnProperty.call(popup.buttons, 'left')) {
175 | popup.buttons.left = [];
176 | }
177 |
178 | if (popup.buttons && !Object.prototype.hasOwnProperty.call(popup.buttons, 'right')) {
179 | popup.buttons.right = [];
180 | }
181 |
182 | this.setState({
183 | id: id,
184 | title: popup.title,
185 | content: popup.content,
186 | buttons: popup.buttons,
187 | visible: true,
188 | className: popup.className,
189 | noOverlay: popup.noOverlay,
190 | position: popup.position,
191 | closeOnOutsideClick: popup.closeOnOutsideClick,
192 | onClose: popup.onClose,
193 | onShow: popup.onShow
194 | }, function () {
195 | _keymaster["default"].setScope('react-popup');
196 |
197 | _this2.state.onShow(_this2.state.id, _this2.state.title);
198 |
199 | if (_this2.props.escToClose) {
200 | (0, _keymaster["default"])('esc', 'react-popup', _this2.handleKeyEvent.bind(_this2, 'cancel', _this2.state.id));
201 | }
202 |
203 | if (_this2.state.buttons) {
204 | if (_this2.state.buttons.left.length) {
205 | _this2.state.buttons.left.forEach(function (button) {
206 | return _this2.bindKeyEvents(button);
207 | });
208 | }
209 |
210 | if (_this2.state.buttons.right.length) {
211 | _this2.state.buttons.right.forEach(function (button) {
212 | return _this2.bindKeyEvents(button);
213 | });
214 | }
215 | }
216 | });
217 | }
218 | }, {
219 | key: "setPosition",
220 | value: function setPosition(position) {
221 | var box = this.boxRef;
222 | var boxPosition = position;
223 |
224 | if (!box) {
225 | return;
226 | }
227 |
228 | if (!boxPosition) {
229 | boxPosition = this.state.position;
230 | }
231 |
232 | if (!boxPosition) {
233 | box.style.opacity = 1;
234 | box.style.top = null;
235 | box.style.left = null;
236 | box.style.margin = null;
237 | return;
238 | }
239 |
240 | if (typeof boxPosition === 'function') {
241 | boxPosition.call(null, box);
242 | return;
243 | }
244 |
245 | box.style.top = "".concat(parseInt(boxPosition.y, 10), "px");
246 | box.style.left = "".concat(parseInt(boxPosition.x, 10), "px");
247 | box.style.margin = 0;
248 | box.style.opacity = 1;
249 | }
250 | /**
251 | * Handle container click
252 | * @param e
253 | * @private
254 | */
255 |
256 | }, {
257 | key: "containerClick",
258 | value: function containerClick() {
259 | if (this.state.closeOnOutsideClick) {
260 | handleClose();
261 | }
262 | }
263 | }, {
264 | key: "bindKeyEvents",
265 | value: function bindKeyEvents(button) {
266 | var code = null;
267 |
268 | if (typeof button === 'string') {
269 | code = this.defaultKeyBindings[button];
270 | } else if (Object.prototype.hasOwnProperty.call(button, 'key')) {
271 | code = button.key;
272 | }
273 |
274 | if (this.props.escToClose && code === 'esc') {
275 | return;
276 | }
277 |
278 | if (code) {
279 | (0, _keymaster["default"])(code, 'react-popup', this.handleKeyEvent.bind(this, button, this.state.id));
280 | }
281 | }
282 | }, {
283 | key: "handleKeyEvent",
284 | value: function handleKeyEvent(button, id, e) {
285 | var excludeTags = ['INPUT', 'TEXTAREA', 'BUTTON'];
286 |
287 | if (this.state.id !== id || button.key === 'enter' && excludeTags.indexOf(e.target.tagName) >= 0) {
288 | return true;
289 | }
290 |
291 | if (typeof button === 'string') {
292 | handleClose();
293 | } else if (Object.prototype.hasOwnProperty.call(button, 'action')) {
294 | this.handleButtonClick(button.action);
295 | }
296 |
297 | return false;
298 | }
299 | /**
300 | * Handle button clicks
301 | * @param action
302 | * @returns {*}
303 | * @private
304 | */
305 |
306 | }, {
307 | key: "handleButtonClick",
308 | value: function handleButtonClick(action) {
309 | if (typeof action === 'function') {
310 | return action.call(this, Store);
311 | }
312 |
313 | return null;
314 | }
315 | }, {
316 | key: "className",
317 | value: function className(_className) {
318 | return (0, _Bem.element)(_className, this.props.className);
319 | }
320 | }, {
321 | key: "render",
322 | value: function render() {
323 | var _this3 = this;
324 |
325 | var className = this.props.className;
326 | var box = null;
327 | var overlayStyle = {};
328 |
329 | if (this.state.visible) {
330 | var closeBtn = null;
331 | className += " ".concat(this.props.className, "--visible");
332 |
333 | if (this.props.closeBtn) {
334 | closeBtn = /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
335 | onClick: handleClose,
336 | className: "".concat(this.props.className, "__close"),
337 | children: this.props.closeHtml
338 | });
339 | }
340 |
341 | var boxClass = this.className('box');
342 |
343 | if (this.state.className) {
344 | boxClass += " ".concat((0, _Bem.modifier)(this.state.className, boxClass));
345 | }
346 |
347 | box = /*#__PURE__*/(0, _jsxRuntime.jsxs)("article", {
348 | role: "dialog",
349 | tabIndex: "-1",
350 | ref: function ref(el) {
351 | _this3.boxRef = el;
352 | },
353 | style: {
354 | opacity: 0,
355 | outline: 'none'
356 | },
357 | className: boxClass,
358 | children: [closeBtn, /*#__PURE__*/(0, _jsxRuntime.jsx)(_Header["default"], {
359 | title: this.state.title,
360 | className: this.className('box__header')
361 | }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
362 | className: this.className('box__body'),
363 | children: this.state.content
364 | }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Footer["default"], {
365 | className: this.className('box__footer'),
366 | btnClass: this.props.btnClass,
367 | buttonClick: this.bound.handleButtonClick,
368 | onClose: handleClose,
369 | onOk: handleClose,
370 | defaultOk: this.props.defaultOk,
371 | defaultCancel: this.props.defaultCancel,
372 | buttons: this.state.buttons
373 | })]
374 | });
375 | }
376 |
377 | if (this.state.noOverlay) {
378 | overlayStyle.background = 'transparent';
379 | }
380 |
381 | return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
382 | className: className,
383 | children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
384 | role: "presentation",
385 | onClick: this.bound.containerClick,
386 | className: this.className('overlay'),
387 | style: overlayStyle
388 | }), box]
389 | });
390 | }
391 | }], [{
392 | key: "addShowListener",
393 | value: function addShowListener(callback) {
394 | Store.on(_Constants["default"].SHOW, callback);
395 | }
396 | }, {
397 | key: "removeShowListener",
398 | value: function removeShowListener(callback) {
399 | Store.removeListener(_Constants["default"].SHOW, callback);
400 | }
401 | }, {
402 | key: "addCloseListener",
403 | value: function addCloseListener(callback) {
404 | Store.on(_Constants["default"].CLOSE, callback);
405 | }
406 | }, {
407 | key: "removeCloseListener",
408 | value: function removeCloseListener(callback) {
409 | Store.removeListener(_Constants["default"].CLOSE, callback);
410 | }
411 | }, {
412 | key: "register",
413 | value: function register(data) {
414 | var id = Store.getId();
415 | Store.popups[id] = Object.assign({}, initialState, data);
416 | return id;
417 | }
418 | }, {
419 | key: "queue",
420 | value: function queue(id) {
421 | if (!Object.prototype.hasOwnProperty.call(Store.popups, id)) {
422 | return false;
423 | }
424 | /** Add popup to queue */
425 |
426 |
427 | Store.queue.push(id);
428 | /** Dispatch queue */
429 |
430 | Store.dispatch();
431 | return id;
432 | }
433 | }, {
434 | key: "create",
435 | value: function create(data, bringToFront) {
436 | /** Register popup */
437 | var id = this.register(data);
438 | /** Queue popup */
439 |
440 | if (bringToFront === true) {
441 | var currentlyActive = Store.active;
442 | Store.active = null;
443 | this.queue(id);
444 | this.queue(currentlyActive);
445 | Store.dispatch();
446 | } else {
447 | this.queue(id);
448 | }
449 |
450 | return id;
451 | }
452 | }, {
453 | key: "alert",
454 | value: function alert(text, title, bringToFront) {
455 | var data = {
456 | title: title,
457 | content: text,
458 | buttons: {
459 | right: ['ok']
460 | }
461 | };
462 | return this.create(data, bringToFront);
463 | }
464 | }, {
465 | key: "close",
466 | value: function close() {
467 | Store.close();
468 | }
469 | }, {
470 | key: "registerPlugin",
471 | value: function registerPlugin(name, callback) {
472 | Store.plugins[name] = callback.bind(this);
473 | }
474 | }, {
475 | key: "plugins",
476 | value: function plugins() {
477 | return Store.plugins;
478 | }
479 | }, {
480 | key: "refreshPosition",
481 | value: function refreshPosition(position) {
482 | return Store.refreshPosition(position);
483 | }
484 | }, {
485 | key: "clearQueue",
486 | value: function clearQueue() {
487 | return Store.clearQueue();
488 | }
489 | }]);
490 |
491 | return Popup;
492 | }(_react["default"].Component);
493 |
494 | _defineProperty(Popup, "defaultProps", {
495 | className: 'mm-popup',
496 | btnClass: 'mm-popup__btn',
497 | closeBtn: true,
498 | closeHtml: null,
499 | defaultOk: 'Ok',
500 | defaultOkKey: 'enter',
501 | defaultCancel: 'Cancel',
502 | defaultCancelKey: 'esc',
503 | closeOnOutsideClick: true,
504 | escToClose: true,
505 | onClose: function onClose() {},
506 | onShow: function onShow() {}
507 | });
508 |
509 | Popup.propTypes = {
510 | className: _propTypes["default"].string,
511 | btnClass: _propTypes["default"].string,
512 | closeBtn: _propTypes["default"].bool,
513 | closeHtml: _propTypes["default"].node,
514 | defaultOk: _propTypes["default"].string,
515 | defaultOkKey: _propTypes["default"].string,
516 | defaultCancel: _propTypes["default"].string,
517 | defaultCancelKey: _propTypes["default"].string,
518 | closeOnOutsideClick: _propTypes["default"].bool,
519 | escToClose: _propTypes["default"].bool,
520 | onClose: _propTypes["default"].func,
521 | onShow: _propTypes["default"].func
522 | };
523 | var _default = Popup;
524 | exports["default"] = _default;
--------------------------------------------------------------------------------
/dist/Store.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
4 |
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 | exports["default"] = void 0;
9 |
10 | var _events = require("events");
11 |
12 | var _Constants = _interopRequireDefault(require("./Constants"));
13 |
14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
15 |
16 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
17 |
18 | 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); } }
19 |
20 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
21 |
22 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }
23 |
24 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
25 |
26 | function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
27 |
28 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }
29 |
30 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
31 |
32 | function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
33 |
34 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
35 |
36 | var PopupStore = /*#__PURE__*/function (_EventEmitter) {
37 | _inherits(PopupStore, _EventEmitter);
38 |
39 | var _super = _createSuper(PopupStore);
40 |
41 | function PopupStore(props) {
42 | var _this;
43 |
44 | _classCallCheck(this, PopupStore);
45 |
46 | _this = _super.call(this, props);
47 | _this.id = 1;
48 | _this.popups = {};
49 | _this.queue = [];
50 | _this.active = null;
51 | _this.plugins = {};
52 | return _this;
53 | }
54 | /**
55 | * Get popup ID
56 | */
57 |
58 |
59 | _createClass(PopupStore, [{
60 | key: "getId",
61 | value: function getId() {
62 | return "id_".concat(this.id++);
63 | }
64 | /**
65 | * Get active popup
66 | * @returns {*}
67 | */
68 |
69 | }, {
70 | key: "activePopup",
71 | value: function activePopup() {
72 | return this.popups[this.active];
73 | }
74 | /**
75 | * Close current popup
76 | */
77 |
78 | }, {
79 | key: "close",
80 | value: function close() {
81 | if (!this.active) {
82 | return false;
83 | }
84 |
85 | var id = this.active;
86 | this.active = null;
87 | this.emit(_Constants["default"].CLOSE, id);
88 | this.dispatch();
89 | this.value = null;
90 | return id;
91 | }
92 | /**
93 | * Dispatch next popup in queue
94 | */
95 |
96 | }, {
97 | key: "dispatch",
98 | value: function dispatch() {
99 | if (this.active || this.queue.length < 1) {
100 | return false;
101 | }
102 |
103 | var id = this.queue.shift();
104 | /** Set active */
105 |
106 | this.active = id;
107 | this.emit(_Constants["default"].SHOW, id);
108 | return true;
109 | }
110 | /**
111 | * Refresh popup position
112 | * @param position
113 | */
114 |
115 | }, {
116 | key: "refreshPosition",
117 | value: function refreshPosition(position) {
118 | this.emit(_Constants["default"].REFRESH, position);
119 | }
120 | /**
121 | * Clear queue
122 | */
123 |
124 | }, {
125 | key: "clearQueue",
126 | value: function clearQueue() {
127 | this.queue = [];
128 | }
129 | }]);
130 |
131 | return PopupStore;
132 | }(_events.EventEmitter);
133 |
134 | exports["default"] = PopupStore;
--------------------------------------------------------------------------------
/dist/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | Object.defineProperty(exports, "default", {
7 | enumerable: true,
8 | get: function get() {
9 | return _Popup["default"];
10 | }
11 | });
12 |
13 | var _Popup = _interopRequireDefault(require("./Popup.react"));
14 |
15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
--------------------------------------------------------------------------------
/example/index.jsx:
--------------------------------------------------------------------------------
1 | import React, {useEffect} from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import Popup from '../src';
4 | import '../style.css';
5 |
6 | const root = createRoot(document.querySelector('#root'));
7 |
8 | function App() {
9 | useEffect(() => {
10 | Popup.create({
11 | title: 'Hello World!',
12 | onShow: (id, title) => {
13 | console.log('Callback: onShow', id, title);
14 | },
15 | onClose: (id, title) => {
16 | console.log('Callback: onClose', id, title);
17 | },
18 | content: (
19 |
20 | It takes more than just a good looking body. You've got to have the heart and soul to go with it.
21 |
22 | ),
23 | className: 'alert',
24 | buttons: {
25 | left: ['cancel'],
26 | right: [
27 | 🦄 ,
28 | {
29 | text: 'Ok!',
30 | className: 'success',
31 | action: Popup.close
32 | }
33 | ]
34 | },
35 | });
36 | }, []);
37 |
38 | return ;
39 | }
40 |
41 | root.render( );
42 |
--------------------------------------------------------------------------------
/example/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%= htmlWebpackPlugin.options.title %>
7 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/example/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 |
4 | module.exports = {
5 | entry: resolve(__dirname),
6 | resolve: {
7 | extensions: ['.js', '.jsx'],
8 | },
9 | devServer: {
10 | compress: true,
11 | },
12 | module: {
13 | rules: [
14 | {
15 | test: /\.jsx?$/,
16 | exclude: /node_modules/,
17 | use: {
18 | loader: 'babel-loader',
19 | },
20 | },
21 | {
22 | test: /\.css$/,
23 | use: [
24 | { loader: 'style-loader' },
25 | { loader: 'css-loader' },
26 | ],
27 | },
28 | ],
29 | },
30 | plugins: [
31 | new HtmlWebpackPlugin({
32 | title: 'Popup',
33 | template: resolve(__dirname, './template.html'),
34 | }),
35 | ],
36 | };
37 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-popup",
3 | "version": "0.11.2",
4 | "description": "React popup component from Minutemailer",
5 | "main": "dist",
6 | "scripts": {
7 | "lint": "eslint src/*.js",
8 | "test": "ava",
9 | "start": "webpack-dev-server --config example/webpack.config.js",
10 | "build": "NODE_ENV=production babel src --out-dir dist"
11 | },
12 | "files": [
13 | "dist",
14 | "style.css"
15 | ],
16 | "repository": {
17 | "type": "git",
18 | "url": "https://github.com/minutemailer/react-popup.git"
19 | },
20 | "keywords": [
21 | "react",
22 | "popup",
23 | "js",
24 | "javascript",
25 | "minutemailer",
26 | "react-component"
27 | ],
28 | "author": "Tobias Bleckert (Minutemailer)",
29 | "license": "MIT",
30 | "bugs": {
31 | "url": "https://github.com/minutemailer/react-popup/issues"
32 | },
33 | "homepage": "https://github.com/minutemailer/react-popup",
34 | "peerDependencies": {
35 | "prop-types": "^15.6.0",
36 | "react": "^17.0.2 || ^18.0.0",
37 | "react-dom": "^17.0.2 || ^18.0.0"
38 | },
39 | "devDependencies": {
40 | "@babel/cli": "^7.17.0",
41 | "@babel/core": "^7.17.2",
42 | "@babel/plugin-proposal-class-properties": "^7.16.7",
43 | "@babel/plugin-proposal-object-rest-spread": "^7.16.7",
44 | "@babel/preset-env": "^7.16.11",
45 | "@babel/preset-react": "^7.16.7",
46 | "@babel/register": "^7.17.0",
47 | "ava": "^1.0.0-beta.4",
48 | "babel-core": "^7.0.0-0",
49 | "babel-eslint": "^8.2.1",
50 | "babel-loader": "^8.2.3",
51 | "browser-env": "^3.3.0",
52 | "css-loader": "^0.28.9",
53 | "enzyme": "^3.11.0",
54 | "enzyme-adapter-react-16": "^1.15.6",
55 | "eslint": "^4.11.0",
56 | "eslint-config-airbnb": "^16.1.0",
57 | "eslint-plugin-import": "^2.8.0",
58 | "eslint-plugin-jsx-a11y": "^6.0.3",
59 | "eslint-plugin-react": "^7.6.1",
60 | "html-webpack-plugin": "^2.30.1",
61 | "react": "^18.2.0",
62 | "react-dom": "^18.2.0",
63 | "style-loader": "^0.20.1",
64 | "webpack": "^3.10.0",
65 | "webpack-dev-server": "^2.11.1"
66 | },
67 | "dependencies": {
68 | "keymaster": "^1.6.2"
69 | },
70 | "ava": {
71 | "require": [
72 | "@babel/register",
73 | "./__tests__/helpers/setup-browser-env.js",
74 | "./__tests__/helpers/setup-enzyme.js"
75 | ]
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/ActionButton.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | class PopupAction extends React.Component {
5 | static defaultProps = {
6 | onClick: () => {},
7 | className: 'btn',
8 | url: null,
9 | };
10 |
11 | handleClick() {
12 | return this.props.onClick();
13 | }
14 |
15 | render() {
16 | const { className } = this.props;
17 |
18 | if (this.props.url && this.props.url !== '#') {
19 | return ({this.props.children} );
20 | }
21 |
22 | return (
23 | this.handleClick()} className={className}>
24 | {this.props.children}
25 |
26 | );
27 | }
28 | }
29 |
30 | PopupAction.propTypes = {
31 | onClick: PropTypes.func,
32 | className: PropTypes.string,
33 | children: PropTypes.node.isRequired,
34 | url: PropTypes.string,
35 | };
36 |
37 | export default PopupAction;
38 |
--------------------------------------------------------------------------------
/src/Bem.js:
--------------------------------------------------------------------------------
1 | const element = (el, base) => `${base}__${el}`;
2 |
3 | const modifier = (modifiers, base) => {
4 | if (!modifiers) {
5 | return null;
6 | }
7 |
8 | const finalClass = [];
9 | const classNames = modifiers.split(' ');
10 |
11 | classNames.forEach((singleClass) => {
12 | finalClass.push(`${base}--${singleClass}`);
13 | });
14 |
15 | return finalClass.join(' ');
16 | };
17 |
18 | export { modifier, element };
19 |
--------------------------------------------------------------------------------
/src/ButtonsSpace.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import ActionButton from './ActionButton.react';
4 | import { modifier } from './Bem';
5 |
6 | export default class PopupFooterButtons extends React.Component {
7 | static defaultProps = {
8 | buttons: null,
9 | className: null,
10 | onOk: () => {},
11 | onClose: () => {},
12 | buttonClick: () => {},
13 | btnClass: null,
14 | defaultOk: null,
15 | defaultCancel: null,
16 | };
17 |
18 | onOk() {
19 | return this.props.onOk();
20 | }
21 |
22 | onClose() {
23 | return this.props.onClose();
24 | }
25 |
26 | buttonClick(action) {
27 | return this.props.buttonClick(action);
28 | }
29 |
30 | render() {
31 | if (!this.props.buttons) {
32 | return null;
33 | }
34 |
35 | const btns = [];
36 |
37 | this.props.buttons.forEach((btn, i) => {
38 | const url = (btn.url) ? btn.url : null;
39 | const key = i;
40 |
41 | if (typeof btn === 'string') {
42 | if (btn === 'ok') {
43 | btns.push( this.onOk()}>{this.props.defaultOk} );
44 | } else if (btn === 'cancel') {
45 | btns.push( this.onClose()}>{this.props.defaultCancel} );
46 | }
47 | } else if (React.isValidElement(btn)) {
48 | btns.push(btn);
49 | } else {
50 | const className = `${this.props.btnClass} ${modifier(btn.className, this.props.btnClass)}`;
51 | const btnComponent = (
52 | this.buttonClick(btn.action)}
57 | >
58 | {btn.text}
59 |
60 | );
61 |
62 | btns.push(btnComponent);
63 | }
64 | });
65 |
66 | return (
67 |
68 | {btns}
69 |
70 | );
71 | }
72 | }
73 |
74 | PopupFooterButtons.propTypes = {
75 | buttons: PropTypes.arrayOf(PropTypes.oneOfType([
76 | PropTypes.string,
77 | PropTypes.object,
78 | ])),
79 | className: PropTypes.string,
80 | onOk: PropTypes.func,
81 | onClose: PropTypes.func,
82 | buttonClick: PropTypes.func,
83 | btnClass: PropTypes.string,
84 | defaultOk: PropTypes.string,
85 | defaultCancel: PropTypes.string,
86 | };
87 |
--------------------------------------------------------------------------------
/src/Constants.js:
--------------------------------------------------------------------------------
1 | export default {
2 | SHOW: 'SHOW',
3 | CLOSE: 'CLOSE',
4 | REFRESH: 'REFRESH',
5 | };
6 |
--------------------------------------------------------------------------------
/src/Footer.react.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import ButtonsSpace from './ButtonsSpace.react';
3 |
4 | const PopupFooter = (props) => {
5 | if (!props.buttons) {
6 | return null;
7 | }
8 |
9 | return (
10 |
33 | );
34 | };
35 |
36 | PopupFooter.propTypes = {
37 | buttons: PropTypes.shape({
38 | left: PropTypes.arrayOf(PropTypes.oneOfType([
39 | PropTypes.string,
40 | PropTypes.object,
41 | ])),
42 | right: PropTypes.arrayOf(PropTypes.oneOfType([
43 | PropTypes.string,
44 | PropTypes.object,
45 | ])),
46 | }),
47 | className: PropTypes.string,
48 | btnClass: PropTypes.string,
49 | onOk: PropTypes.func,
50 | onClose: PropTypes.func,
51 | buttonClick: PropTypes.func,
52 | defaultOk: PropTypes.string,
53 | defaultCancel: PropTypes.string,
54 | };
55 |
56 | PopupFooter.defaultProps = {
57 | buttons: null,
58 | className: null,
59 | btnClass: null,
60 | defaultOk: null,
61 | defaultCancel: null,
62 | buttonClick: () => {},
63 | onOk: () => {},
64 | onClose: () => {},
65 | };
66 |
67 | export default PopupFooter;
68 |
--------------------------------------------------------------------------------
/src/Header.react.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 |
3 | const PopupHeader = (props) => {
4 | if (!props.title) {
5 | return null;
6 | }
7 |
8 | return (
9 |
12 | );
13 | };
14 |
15 | PopupHeader.defaultProps = {
16 | title: null,
17 | className: null,
18 | };
19 |
20 | PopupHeader.propTypes = {
21 | title: PropTypes.string,
22 | className: PropTypes.string,
23 | };
24 |
25 | export default PopupHeader;
26 |
--------------------------------------------------------------------------------
/src/Popup.react.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import key from 'keymaster';
4 | import PopupStore from './Store';
5 | import Header from './Header.react';
6 | import Footer from './Footer.react';
7 | import Constants from './Constants';
8 | import { element, modifier } from './Bem';
9 |
10 | const defaultKeyFilter = key.filter;
11 | const Store = new PopupStore();
12 |
13 | const handleClose = () => {
14 | key.deleteScope('react-popup');
15 | key.filter = defaultKeyFilter;
16 |
17 | Store.close();
18 | };
19 |
20 | const initialState = {
21 | id: null,
22 | title: null,
23 | buttons: null,
24 | content: null,
25 | visible: false,
26 | className: null,
27 | noOverlay: false,
28 | position: false,
29 | closeOnOutsideClick: true,
30 | onClose: () => {},
31 | onShow: () => {},
32 | };
33 |
34 | class Popup extends React.Component {
35 | static defaultProps = {
36 | className: 'mm-popup',
37 | btnClass: 'mm-popup__btn',
38 | closeBtn: true,
39 | closeHtml: null,
40 | defaultOk: 'Ok',
41 | defaultOkKey: 'enter',
42 | defaultCancel: 'Cancel',
43 | defaultCancelKey: 'esc',
44 | closeOnOutsideClick: true,
45 | escToClose: true,
46 | onClose: () => {},
47 | onShow: () => {},
48 | };
49 |
50 | static addShowListener(callback) {
51 | Store.on(Constants.SHOW, callback);
52 | }
53 |
54 | static removeShowListener(callback) {
55 | Store.removeListener(Constants.SHOW, callback);
56 | }
57 |
58 | static addCloseListener(callback) {
59 | Store.on(Constants.CLOSE, callback);
60 | }
61 |
62 | static removeCloseListener(callback) {
63 | Store.removeListener(Constants.CLOSE, callback);
64 | }
65 |
66 | static register(data) {
67 | const id = Store.getId();
68 |
69 | Store.popups[id] = Object.assign({}, initialState, data);
70 |
71 | return id;
72 | }
73 |
74 | static queue(id) {
75 | if (!Object.prototype.hasOwnProperty.call(Store.popups, id)) {
76 | return false;
77 | }
78 |
79 | /** Add popup to queue */
80 | Store.queue.push(id);
81 |
82 | /** Dispatch queue */
83 | Store.dispatch();
84 |
85 | return id;
86 | }
87 |
88 | static create(data, bringToFront) {
89 | /** Register popup */
90 | const id = this.register(data);
91 |
92 | /** Queue popup */
93 | if (bringToFront === true) {
94 | const currentlyActive = Store.active;
95 |
96 | Store.active = null;
97 | this.queue(id);
98 | this.queue(currentlyActive);
99 | Store.dispatch();
100 | } else {
101 | this.queue(id);
102 | }
103 |
104 | return id;
105 | }
106 |
107 | static alert(text, title, bringToFront) {
108 | const data = {
109 | title,
110 | content: text,
111 | buttons: {
112 | right: ['ok'],
113 | },
114 | };
115 |
116 | return this.create(data, bringToFront);
117 | }
118 |
119 | static close() {
120 | Store.close();
121 | }
122 |
123 | static registerPlugin(name, callback) {
124 | Store.plugins[name] = callback.bind(this);
125 | }
126 |
127 | static plugins() {
128 | return Store.plugins;
129 | }
130 |
131 | static refreshPosition(position) {
132 | return Store.refreshPosition(position);
133 | }
134 |
135 | static clearQueue() {
136 | return Store.clearQueue();
137 | }
138 |
139 | constructor(props) {
140 | super(props);
141 |
142 | initialState.closeOnOutsideClick = this.props.closeOnOutsideClick;
143 |
144 | this.state = initialState;
145 |
146 | this.bound = {
147 | onShow: this.onShow.bind(this),
148 | onClose: this.onClose.bind(this),
149 | onRefresh: this.onRefresh.bind(this),
150 | containerClick: this.containerClick.bind(this),
151 | handleButtonClick: this.handleButtonClick.bind(this),
152 | };
153 |
154 | this.boxRef = null;
155 |
156 | this.defaultKeyBindings = {
157 | ok: this.props.defaultOkKey,
158 | cancel: this.props.defaultCancelKey,
159 | };
160 | }
161 |
162 | componentDidMount() {
163 | Store.on(Constants.SHOW, this.bound.onShow);
164 | Store.on(Constants.CLOSE, this.bound.onClose);
165 | Store.on(Constants.REFRESH, this.bound.onRefresh);
166 | }
167 |
168 | componentDidUpdate() {
169 | if (this.boxRef) {
170 | this.boxRef.focus();
171 | }
172 |
173 | this.setPosition(this.state.position);
174 | }
175 |
176 | componentWillUnmount() {
177 | Store.removeListener(Constants.SHOW, this.bound.onShow);
178 | Store.removeListener(Constants.CLOSE, this.bound.onClose);
179 | Store.removeListener(Constants.REFRESH, this.bound.onRefresh);
180 | key.deleteScope('react-popup');
181 | key.filter = defaultKeyFilter;
182 | }
183 |
184 | /**
185 | * Refresh popup position
186 | * @param position
187 | * @private
188 | */
189 | onRefresh(position) {
190 | this.setPosition(position);
191 | }
192 |
193 | /**
194 | * On popup close
195 | * @private
196 | */
197 | onClose() {
198 | key.deleteScope('react-popup');
199 | key.filter = defaultKeyFilter;
200 | this.state.onClose(this.state.id, this.state.title);
201 | this.setState(initialState);
202 | }
203 |
204 | /**
205 | * On popup show
206 | * @private
207 | */
208 | onShow(id) {
209 | key.deleteScope('react-popup');
210 |
211 | key.filter = () => true;
212 |
213 | const popup = Store.activePopup();
214 |
215 | if (popup.buttons && !Object.prototype.hasOwnProperty.call(popup.buttons, 'left')) {
216 | popup.buttons.left = [];
217 | }
218 |
219 | if (popup.buttons && !Object.prototype.hasOwnProperty.call(popup.buttons, 'right')) {
220 | popup.buttons.right = [];
221 | }
222 |
223 | this.setState({
224 | id,
225 | title: popup.title,
226 | content: popup.content,
227 | buttons: popup.buttons,
228 | visible: true,
229 | className: popup.className,
230 | noOverlay: popup.noOverlay,
231 | position: popup.position,
232 | closeOnOutsideClick: popup.closeOnOutsideClick,
233 | onClose: popup.onClose,
234 | onShow: popup.onShow,
235 | }, () => {
236 | key.setScope('react-popup');
237 | this.state.onShow(this.state.id, this.state.title);
238 |
239 | if (this.props.escToClose) {
240 | key('esc', 'react-popup', this.handleKeyEvent.bind(this, 'cancel', this.state.id));
241 | }
242 |
243 | if (this.state.buttons) {
244 | if (this.state.buttons.left.length) {
245 | this.state.buttons.left.forEach(button => this.bindKeyEvents(button));
246 | }
247 |
248 | if (this.state.buttons.right.length) {
249 | this.state.buttons.right.forEach(button => this.bindKeyEvents(button));
250 | }
251 | }
252 | });
253 | }
254 |
255 | setPosition(position) {
256 | const box = this.boxRef;
257 | let boxPosition = position;
258 |
259 | if (!box) {
260 | return;
261 | }
262 |
263 | if (!boxPosition) {
264 | boxPosition = this.state.position;
265 | }
266 |
267 | if (!boxPosition) {
268 | box.style.opacity = 1;
269 | box.style.top = null;
270 | box.style.left = null;
271 | box.style.margin = null;
272 |
273 | return;
274 | }
275 |
276 | if (typeof boxPosition === 'function') {
277 | boxPosition.call(null, box);
278 |
279 | return;
280 | }
281 |
282 | box.style.top = `${parseInt(boxPosition.y, 10)}px`;
283 | box.style.left = `${parseInt(boxPosition.x, 10)}px`;
284 | box.style.margin = 0;
285 | box.style.opacity = 1;
286 | }
287 |
288 | /**
289 | * Handle container click
290 | * @param e
291 | * @private
292 | */
293 | containerClick() {
294 | if (this.state.closeOnOutsideClick) {
295 | handleClose();
296 | }
297 | }
298 |
299 | bindKeyEvents(button) {
300 | let code = null;
301 |
302 | if (typeof button === 'string') {
303 | code = this.defaultKeyBindings[button];
304 | } else if (Object.prototype.hasOwnProperty.call(button, 'key')) {
305 | code = button.key;
306 | }
307 |
308 | if (this.props.escToClose && code === 'esc') {
309 | return;
310 | }
311 |
312 | if (code) {
313 | key(code, 'react-popup', this.handleKeyEvent.bind(this, button, this.state.id));
314 | }
315 | }
316 |
317 | handleKeyEvent(button, id, e) {
318 | const excludeTags = ['INPUT', 'TEXTAREA', 'BUTTON'];
319 |
320 | if (this.state.id !== id || (button.key === 'enter' && excludeTags.indexOf(e.target.tagName) >= 0)) {
321 | return true;
322 | }
323 |
324 | if (typeof button === 'string') {
325 | handleClose();
326 | } else if (Object.prototype.hasOwnProperty.call(button, 'action')) {
327 | this.handleButtonClick(button.action);
328 | }
329 |
330 | return false;
331 | }
332 |
333 | /**
334 | * Handle button clicks
335 | * @param action
336 | * @returns {*}
337 | * @private
338 | */
339 | handleButtonClick(action) {
340 | if (typeof action === 'function') {
341 | return action.call(this, Store);
342 | }
343 |
344 | return null;
345 | }
346 |
347 | className(className) {
348 | return element(className, this.props.className);
349 | }
350 |
351 | render() {
352 | let { className } = this.props;
353 | let box = null;
354 | const overlayStyle = {};
355 |
356 | if (this.state.visible) {
357 | let closeBtn = null;
358 |
359 | className += ` ${this.props.className}--visible`;
360 |
361 | if (this.props.closeBtn) {
362 | closeBtn = {this.props.closeHtml} ;
363 | }
364 |
365 | let boxClass = this.className('box');
366 |
367 | if (this.state.className) {
368 | boxClass += ` ${modifier(this.state.className, boxClass)}`;
369 | }
370 |
371 | box = (
372 | { this.boxRef = el; }} style={{ opacity: 0, outline: 'none' }} className={boxClass}>
373 | {closeBtn}
374 |
375 |
376 |
377 | {this.state.content}
378 |
379 |
380 |
390 |
391 | );
392 | }
393 |
394 | if (this.state.noOverlay) {
395 | overlayStyle.background = 'transparent';
396 | }
397 |
398 | return (
399 |
403 | );
404 | }
405 | }
406 |
407 | Popup.propTypes = {
408 | className: PropTypes.string,
409 | btnClass: PropTypes.string,
410 | closeBtn: PropTypes.bool,
411 | closeHtml: PropTypes.node,
412 | defaultOk: PropTypes.string,
413 | defaultOkKey: PropTypes.string,
414 | defaultCancel: PropTypes.string,
415 | defaultCancelKey: PropTypes.string,
416 | closeOnOutsideClick: PropTypes.bool,
417 | escToClose: PropTypes.bool,
418 | onClose: PropTypes.func,
419 | onShow: PropTypes.func,
420 | };
421 |
422 | export default Popup;
423 |
--------------------------------------------------------------------------------
/src/Store.js:
--------------------------------------------------------------------------------
1 | import { EventEmitter } from 'events';
2 | import Constants from './Constants';
3 |
4 | export default class PopupStore extends EventEmitter {
5 | constructor(props) {
6 | super(props);
7 |
8 | this.id = 1;
9 | this.popups = {};
10 | this.queue = [];
11 | this.active = null;
12 | this.plugins = {};
13 | }
14 |
15 | /**
16 | * Get popup ID
17 | */
18 | getId() {
19 | return `id_${this.id++}`;
20 | }
21 |
22 | /**
23 | * Get active popup
24 | * @returns {*}
25 | */
26 | activePopup() {
27 | return this.popups[this.active];
28 | }
29 |
30 | /**
31 | * Close current popup
32 | */
33 | close() {
34 | if (!this.active) {
35 | return false;
36 | }
37 |
38 | const id = this.active;
39 | this.active = null;
40 |
41 | this.emit(Constants.CLOSE, id);
42 | this.dispatch();
43 |
44 | this.value = null;
45 |
46 | return id;
47 | }
48 |
49 | /**
50 | * Dispatch next popup in queue
51 | */
52 | dispatch() {
53 | if (this.active || this.queue.length < 1) {
54 | return false;
55 | }
56 |
57 | const id = this.queue.shift();
58 |
59 | /** Set active */
60 | this.active = id;
61 |
62 | this.emit(Constants.SHOW, id);
63 |
64 | return true;
65 | }
66 |
67 | /**
68 | * Refresh popup position
69 | * @param position
70 | */
71 | refreshPosition(position) {
72 | this.emit(Constants.REFRESH, position);
73 | }
74 |
75 | /**
76 | * Clear queue
77 | */
78 | clearQueue() {
79 | this.queue = [];
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './Popup.react';
2 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | .mm-popup {
2 | display: none;
3 | }
4 |
5 | .mm-popup--visible {
6 | display: block;
7 | }
8 |
9 | .mm-popup__overlay {
10 | position: fixed;
11 | top: 0;
12 | left: 0;
13 | width: 100%;
14 | height: 100%;
15 | z-index: 1000;
16 | overflow: auto;
17 | background: rgba(0, 0, 0, .1);
18 | }
19 |
20 | .mm-popup__close {
21 | position: absolute;
22 | top: 15px;
23 | right: 20px;
24 | padding: 0;
25 | width: 20px;
26 | height: 20px;
27 | cursor: pointer;
28 | outline: none;
29 | text-align: center;
30 | border-radius: 10px;
31 | border: none;
32 | text-indent: -9999px;
33 | background: transparent url('data:image/png;base64,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') no-repeat center center;
34 | background-size: 100%;
35 | margin: 0;
36 | }
37 |
38 | .mm-popup__input {
39 | display: block;
40 | width: 100%;
41 | height: 30px;
42 | border-radius: 3px;
43 | background: #f5f5f5;
44 | border: 1px solid #e9ebec;
45 | outline: none;
46 | -moz-box-sizing: border-box !important;
47 | -webkit-box-sizing: border-box !important;
48 | box-sizing: border-box !important;
49 | font-size: 14px;
50 | padding: 0 12px;
51 | color: #808080;
52 | }
53 |
54 | .mm-popup__btn {
55 | border-radius: 3px;
56 | -moz-box-sizing: border-box;
57 | -webkit-box-sizing: border-box;
58 | box-sizing: border-box;
59 | padding: 0 10px;
60 | margin: 0;
61 | line-height: 32px;
62 | height: 32px;
63 | border: 1px solid #666;
64 | text-align: center;
65 | display: inline-block;
66 | font-size: 12px;
67 | font-weight: 400;
68 | color: #333;
69 | background: transparent;
70 | outline: none;
71 | text-decoration: none;
72 | cursor: pointer;
73 | font-family: "Open Sans", sans-serif;
74 | }
75 |
76 | .mm-popup__btn--success {
77 | background-color: #27ae60;
78 | border-color: #27ae60;
79 | color: #fff;
80 | }
81 |
82 | .mm-popup__btn--danger {
83 | background-color: #c5545c;
84 | border-color: #c5545c;
85 | color: #fff;
86 | }
87 |
88 | .mm-popup__box {
89 | width: 350px;
90 | position: fixed;
91 | top: 10%;
92 | left: 50%;
93 | margin-left: -175px;
94 | background: #fff;
95 | box-shadow: 0px 5px 20px 0px rgba(126, 137, 140, 0.20);
96 | border-radius: 5px;
97 | border: 1px solid #B8C8CC;
98 | overflow: hidden;
99 | z-index: 1001;
100 | }
101 |
102 | .mm-popup__box__header {
103 | padding: 15px 20px;
104 | background: #EDF5F7;
105 | color: #454B4D;
106 | }
107 |
108 | .mm-popup__box__header__title {
109 | margin: 0;
110 | font-size: 16px;
111 | text-align: left;
112 | font-weight: 600;
113 | }
114 |
115 | .mm-popup__box__body {
116 | padding: 20px;
117 | line-height: 1.4;
118 | font-size: 14px;
119 | color: #454B4D;
120 | background: #fff;
121 | position: relative;
122 | z-index: 2;
123 | }
124 |
125 | .mm-popup__box__body p {
126 | margin: 0 0 5px;
127 | }
128 |
129 | .mm-popup__box__footer {
130 | overflow: hidden;
131 | padding: 40px 20px 20px;
132 | }
133 |
134 | .mm-popup__box__footer__right-space {
135 | float: right;
136 | }
137 |
138 | .mm-popup__box__footer__right-space .mm-popup__btn {
139 | margin-left: 5px;
140 | }
141 |
142 | .mm-popup__box__footer__left-space {
143 | float: left;
144 | }
145 |
146 | .mm-popup__box__footer__left-space .mm-popup__btn {
147 | margin-right: 5px;
148 | }
149 |
150 | .mm-popup__box--popover {
151 | width: 300px;
152 | margin-left: -150px;
153 | }
154 |
155 | .mm-popup__box--popover .mm-popup__close {
156 | position: absolute;
157 | top: 5px;
158 | right: 5px;
159 | padding: 0;
160 | width: 20px;
161 | height: 20px;
162 | cursor: pointer;
163 | outline: none;
164 | text-align: center;
165 | border-radius: 10px;
166 | border: none;
167 | text-indent: -9999px;
168 | background: transparent url('data:image/png;base64,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') no-repeat center center;
169 | background-size: 100%;
170 | margin: 0;
171 | z-index: 3;
172 | }
173 |
174 | .mm-popup__box--popover .mm-popup__box__body {
175 | padding: 20px;
176 | }
177 |
178 | @media (max-width: 420px) {
179 | .mm-popup__box {
180 | width: auto;
181 | left: 10px;
182 | right: 10px;
183 | top: 10px;
184 | margin-left: 0;
185 | }
186 | .mm-popup__box__footer__left-space {
187 | float: none;
188 | }
189 | .mm-popup__box__footer__right-space {
190 | float: none;
191 | }
192 | .mm-popup__box__footer {
193 | padding-top: 30px;
194 | }
195 | .mm-popup__box__footer .mm-popup__btn {
196 | display: block;
197 | width: 100%;
198 | text-align: center;
199 | margin-top: 10px;
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { resolve } = require('path');
2 |
3 | module.exports = {
4 | entry: './src',
5 | output: {
6 | path: resolve(__dirname, 'dist'),
7 | filename: 'bundle.js',
8 | libraryTarget: 'commonjs2',
9 | },
10 | resolve: {
11 | extensions: ['.js', '.jsx'],
12 | },
13 | module: {
14 | rules: [
15 | {
16 | test: /\.jsx?$/,
17 | exclude: /node_modules/,
18 | use: {
19 | loader: 'babel-loader',
20 | },
21 | },
22 | ],
23 | },
24 | externals: ['react', 'keymaster'],
25 | };
26 |
--------------------------------------------------------------------------------