@4i/modal-manager 1.0.117 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4i/modal-manager",
3
- "version": "1.0.117",
3
+ "version": "1.1.1",
4
4
  "description": "",
5
5
  "main": "src/index.ts",
6
6
  "scripts": {
package/readme.md CHANGED
@@ -13,37 +13,41 @@ This package simplifies the management of multiple modals, popups, notifications
13
13
  npm install @4i/modal-manager
14
14
  ```
15
15
 
16
- ## Usage
17
-
18
- #### Instance methods:
19
-
20
- ##### .call(action, props)
21
-
22
- Call a modal by its action name and pass props to it.
23
-
24
- ##### .close('all')
25
-
26
- Close all modals.
27
-
28
- ##### .close(-1)
16
+ ## Example
29
17
 
30
- Close last modals.
18
+ <a href="https://codesandbox.io/p/github/tonichiga/modal-manager-example/main?layout=%257B%2522sidebarPanel%2522%253A%2522GIT%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522clsnqfzod00063p6le9554u03%2522%252C%2522sizes%2522%253A%255B70%252C30%255D%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522id%2522%253A%2522clsnqfzod00023p6lo9e5ocrg%2522%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522SHELLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522id%2522%253A%2522clsnqfzod00043p6l5kpjziav%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522id%2522%253A%2522clsnqfzod00053p6lleknh8sj%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%252C%2522sizes%2522%253A%255B50%252C50%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clsnqfzod00023p6lo9e5ocrg%2522%253A%257B%2522id%2522%253A%2522clsnqfzod00023p6lo9e5ocrg%2522%252C%2522tabs%2522%253A%255B%255D%257D%252C%2522clsnqfzod00053p6lleknh8sj%2522%253A%257B%2522id%2522%253A%2522clsnqfzod00053p6lleknh8sj%2522%252C%2522activeTabId%2522%253A%2522clsnqihgr00ht3p6l2nn59nq5%2522%252C%2522tabs%2522%253A%255B%257B%2522type%2522%253A%2522TASK_PORT%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522port%2522%253A3000%252C%2522id%2522%253A%2522clsnqihgr00ht3p6l2nn59nq5%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522path%2522%253A%2522%252F%2522%257D%255D%257D%252C%2522clsnqfzod00043p6l5kpjziav%2522%253A%257B%2522id%2522%253A%2522clsnqfzod00043p6l5kpjziav%2522%252C%2522activeTabId%2522%253A%2522clsnqojb3003j3p6m98yg0rzn%2522%252C%2522tabs%2522%253A%255B%257B%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522id%2522%253A%2522clsnqh362007k3p6lgb90p583%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%252C%257B%2522id%2522%253A%2522clsnqojb3003j3p6m98yg0rzn%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522TERMINAL%2522%252C%2522shellId%2522%253A%2522clsnqojh1001mdjig37kbat9k%2522%257D%255D%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showShells%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A15%257D">Codesandbox</a>
31
19
 
32
- ##### .close(0)
33
-
34
- Close first modals.
35
-
36
- ##### .close() (default)
37
-
38
- Close last modals.
39
-
40
- ##### .addEventListener(event, callback)
41
-
42
- Add an event listener to the modal manager.
20
+ ## Usage
43
21
 
44
- ##### .removeEventListener(event, callback)
22
+ #### Instance methods:
45
23
 
46
- Remove an event listener from the modal manager.
24
+ | Method | Description |
25
+ | ------------------------------------ | ----------------------------------------------------- |
26
+ | call(action, props) | Call a modal by its action name and pass props to it. |
27
+ | |
28
+ | close('all') | Close all modals. |
29
+ | |
30
+ | close(-1) | Close last modals. |
31
+ | |
32
+ | close(0) | Close first modals. |
33
+ | |
34
+ | close() | Close last modals. (default) |
35
+ | |
36
+ | onOpenModalState(callback) | Is there at least one window open now |
37
+ | |
38
+ | addEventListener(event, callback) | Add an event listener to the modal manager. |
39
+ | |
40
+ | removeEventListener(event, callback) | Remove an event listener from the modal manager. |
41
+ | |
42
+
43
+ #### ModalProvider props
44
+
45
+ | Prop | Type | Description |
46
+ | ------------------ | -------- | -------------------------------------------------------------------------- |
47
+ | modalList | Object | An object containing modal actions as keys and modal components as values. |
48
+ | className | string | |
49
+ | isOverflow | boolean | Set "overflow: hidden" on body |
50
+ | onModalStateChange | function | Callback function that is called when modal state changes. |
47
51
 
48
52
  #### Define Modal Actions:
49
53
 
@@ -1,9 +1,18 @@
1
1
  import React from "react";
2
+ import { ModalManager } from "../utils/ModalManager";
2
3
  export type ModalList = {
3
4
  [key: string]: React.ComponentType;
4
5
  };
5
6
  interface ModalProviderProps {
6
- modalList: ModalList;
7
+ modalList: any;
8
+ isOverflow?: boolean;
9
+ className?: string;
10
+ backdropClassName?: string;
11
+ modalManager?: ModalManager;
12
+ onModalStateChange?: (modalState: boolean, data: TData[], names: string[]) => void;
7
13
  }
8
- declare const ModalProvider: ({ modalList }: ModalProviderProps) => false | React.JSX.Element[];
14
+ type TData = {
15
+ [key: string]: any;
16
+ };
17
+ declare const ModalProvider: ({ modalList, isOverflow, className, backdropClassName, modalManager, onModalStateChange, }: ModalProviderProps) => React.JSX.Element;
9
18
  export default ModalProvider;
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ "use client";
2
3
  var __assign = (this && this.__assign) || function () {
3
4
  __assign = Object.assign || function(t) {
4
5
  for (var s, i = 1, n = arguments.length; i < n; i++) {
@@ -42,24 +43,38 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
42
43
  }
43
44
  return to.concat(ar || Array.prototype.slice.call(from));
44
45
  };
45
- var __importDefault = (this && this.__importDefault) || function (mod) {
46
- return (mod && mod.__esModule) ? mod : { "default": mod };
47
- };
48
46
  Object.defineProperty(exports, "__esModule", { value: true });
49
47
  var react_1 = __importStar(require("react"));
50
- var ModalManager_1 = __importDefault(require("../utils/ModalManager"));
51
- var ModalManager_2 = __importDefault(require("../utils/ModalManager"));
48
+ var ModalManager_1 = __importStar(require("../utils/ModalManager"));
52
49
  var ModalProvider = function (_a) {
53
- var modalList = _a.modalList;
50
+ var modalList = _a.modalList, isOverflow = _a.isOverflow, className = _a.className, backdropClassName = _a.backdropClassName, modalManager = _a.modalManager, onModalStateChange = _a.onModalStateChange;
54
51
  var _b = (0, react_1.useState)([]), data = _b[0], setData = _b[1];
55
52
  var _c = (0, react_1.useState)([]), names = _c[0], setNames = _c[1];
56
53
  var modalRef = (0, react_1.useRef)([]);
54
+ var m = modalManager !== null && modalManager !== void 0 ? modalManager : ModalManager_1.default;
55
+ (0, react_1.useEffect)(function () {
56
+ if (!onModalStateChange)
57
+ return;
58
+ var modalState = data.length !== 0;
59
+ onModalStateChange(modalState, data, names);
60
+ // eslint-disable-next-line react-hooks/exhaustive-deps
61
+ }, [data, names]);
57
62
  (0, react_1.useEffect)(function () {
58
63
  var handleOpenModal = function (name, data) {
59
64
  setData(function (prev) { return __spreadArray(__spreadArray([], prev, true), [data], false); });
60
65
  setNames(function (prev) { return __spreadArray(__spreadArray([], prev, true), [name], false); });
66
+ if (isOverflow) {
67
+ if (typeof document === "undefined")
68
+ return;
69
+ document.body.style.overflow = "hidden";
70
+ }
61
71
  };
62
72
  var handleClose = function (position) {
73
+ if (isOverflow) {
74
+ if (typeof document !== "undefined") {
75
+ document.body.style.overflow = "";
76
+ }
77
+ }
63
78
  if (position === "all") {
64
79
  setData([]);
65
80
  setNames([]);
@@ -89,38 +104,37 @@ var ModalProvider = function (_a) {
89
104
  return prev.filter(function (_, index) { return index !== prev.length - 1; });
90
105
  });
91
106
  };
92
- ModalManager_1.default.addEventListener("change", handleOpenModal);
93
- ModalManager_1.default.addEventListener("close", handleClose);
107
+ m.addEventListener(ModalManager_1.constants.CHANGE, handleOpenModal);
108
+ m.addEventListener(ModalManager_1.constants.CLOSE, handleClose);
94
109
  return function () {
95
- ModalManager_1.default.removeEventListener("change", handleOpenModal);
96
- ModalManager_1.default.removeEventListener("close", handleClose);
110
+ m.removeEventListener(ModalManager_1.constants.CHANGE, handleOpenModal);
111
+ m.removeEventListener(ModalManager_1.constants.CLOSE, handleClose);
97
112
  };
113
+ // eslint-disable-next-line react-hooks/exhaustive-deps
98
114
  }, []);
99
115
  var activeModals = names.map(function (name) {
100
116
  var Component = modalList[name] || (function () { return react_1.default.createElement(react_1.default.Fragment, null); });
101
117
  return Component;
102
118
  });
103
- var handleCloseModal = function (index, e) {
104
- console.log(index);
105
- if (modalRef.current[index] &&
106
- !modalRef.current[index].contains(e.target)) {
107
- ModalManager_2.default.close(index);
108
- }
119
+ var handleCloseModal = function (index) {
120
+ m.close(index);
109
121
  };
110
122
  var refReducer = function (index, value) {
111
123
  modalRef.current[index] = value;
112
124
  };
113
- return (data.length !== 0 &&
125
+ return (react_1.default.createElement(react_1.default.Fragment, null, data.length !== 0 &&
114
126
  data.map(function (item, i) {
115
127
  var Modal = activeModals[i] || (function () { return react_1.default.createElement(react_1.default.Fragment, null); });
116
- return (react_1.default.createElement("div", { key: item.modalId, onClick: function (e) {
117
- handleCloseModal(i, e);
118
- } },
119
- react_1.default.createElement("div", { className: "backdrop_modal_manager" },
128
+ return (react_1.default.createElement("div", { key: item.modalId, className: "modal-manager backdrop_modal_manager ".concat(backdropClassName) },
129
+ react_1.default.createElement("div", { onClick: function (e) {
130
+ e.stopPropagation();
131
+ handleCloseModal(i);
132
+ }, className: "backdrop" }),
133
+ react_1.default.createElement("div", { className: "".concat(className, " modal_paper") },
120
134
  react_1.default.createElement("div", { ref: function (ref) {
121
135
  refReducer(i, ref);
122
136
  } },
123
137
  react_1.default.createElement(Modal, __assign({}, item.data))))));
124
- }));
138
+ })));
125
139
  };
126
140
  exports.default = ModalProvider;
@@ -1,27 +1,63 @@
1
+ "use client";
2
+
1
3
  import React, { useEffect, useRef, useState } from "react";
2
- import manager from "../utils/ModalManager";
3
- import modal from "../utils/ModalManager";
4
+ import modal, { constants, ModalManager } from "../utils/ModalManager";
4
5
 
5
6
  export type ModalList = { [key: string]: React.ComponentType };
6
7
 
7
8
  interface ModalProviderProps {
8
- modalList: ModalList;
9
+ modalList: any;
10
+ isOverflow?: boolean;
11
+ className?: string;
12
+ backdropClassName?: string;
13
+ modalManager?: ModalManager;
14
+ onModalStateChange?: (
15
+ modalState: boolean,
16
+ data: TData[],
17
+ names: string[]
18
+ ) => void;
9
19
  }
10
20
 
11
21
  type TData = { [key: string]: any };
12
22
 
13
- const ModalProvider = ({ modalList }: ModalProviderProps) => {
23
+ const ModalProvider = ({
24
+ modalList,
25
+ isOverflow,
26
+ className,
27
+ backdropClassName,
28
+ modalManager,
29
+ onModalStateChange,
30
+ }: ModalProviderProps) => {
14
31
  const [data, setData] = useState<TData[]>([]);
15
32
  const [names, setNames] = useState<string[]>([]);
16
33
  const modalRef = useRef<any[]>([]);
34
+ const m = modalManager ?? modal;
35
+
36
+ useEffect(() => {
37
+ if (!onModalStateChange) return;
38
+ const modalState = data.length !== 0;
39
+ onModalStateChange(modalState, data, names);
40
+ // eslint-disable-next-line react-hooks/exhaustive-deps
41
+ }, [data, names]);
17
42
 
18
43
  useEffect(() => {
19
44
  const handleOpenModal = (name: string, data: TData) => {
20
45
  setData((prev: TData[]) => [...prev, data]);
21
46
  setNames((prev: string[]) => [...prev, name]);
47
+
48
+ if (isOverflow) {
49
+ if (typeof document === "undefined") return;
50
+ document.body.style.overflow = "hidden";
51
+ }
22
52
  };
23
53
 
24
54
  const handleClose = (position: number | string) => {
55
+ if (isOverflow) {
56
+ if (typeof document !== "undefined") {
57
+ document.body.style.overflow = "";
58
+ }
59
+ }
60
+
25
61
  if (position === "all") {
26
62
  setData([]);
27
63
  setNames([]);
@@ -55,12 +91,13 @@ const ModalProvider = ({ modalList }: ModalProviderProps) => {
55
91
  );
56
92
  };
57
93
 
58
- manager.addEventListener("change", handleOpenModal);
59
- manager.addEventListener("close", handleClose);
94
+ m.addEventListener(constants.CHANGE, handleOpenModal);
95
+ m.addEventListener(constants.CLOSE, handleClose);
60
96
  return () => {
61
- manager.removeEventListener("change", handleOpenModal);
62
- manager.removeEventListener("close", handleClose);
97
+ m.removeEventListener(constants.CHANGE, handleOpenModal);
98
+ m.removeEventListener(constants.CLOSE, handleClose);
63
99
  };
100
+ // eslint-disable-next-line react-hooks/exhaustive-deps
64
101
  }, []);
65
102
 
66
103
  const activeModals = names.map((name: string) => {
@@ -68,14 +105,8 @@ const ModalProvider = ({ modalList }: ModalProviderProps) => {
68
105
  return Component;
69
106
  });
70
107
 
71
- const handleCloseModal = (index: number, e: any) => {
72
- console.log(index);
73
- if (
74
- modalRef.current[index] &&
75
- !modalRef.current[index].contains(e.target)
76
- ) {
77
- modal.close(index);
78
- }
108
+ const handleCloseModal = (index: number) => {
109
+ m.close(index);
79
110
  };
80
111
 
81
112
  const refReducer = (index: number, value: any) => {
@@ -83,29 +114,37 @@ const ModalProvider = ({ modalList }: ModalProviderProps) => {
83
114
  };
84
115
 
85
116
  return (
86
- data.length !== 0 &&
87
- data.map((item, i) => {
88
- const Modal = activeModals[i] || (() => <></>);
89
-
90
- return (
91
- <div
92
- key={item.modalId}
93
- onClick={(e) => {
94
- handleCloseModal(i, e);
95
- }}
96
- >
97
- <div className="backdrop_modal_manager">
117
+ <>
118
+ {data.length !== 0 &&
119
+ data.map((item, i) => {
120
+ const Modal = activeModals[i] || (() => <></>);
121
+
122
+ return (
98
123
  <div
99
- ref={(ref) => {
100
- refReducer(i, ref);
101
- }}
124
+ key={item.modalId}
125
+ className={`modal-manager backdrop_modal_manager ${backdropClassName}`}
102
126
  >
103
- <Modal {...item.data} />
127
+ <div
128
+ onClick={(e) => {
129
+ e.stopPropagation();
130
+ handleCloseModal(i);
131
+ }}
132
+ className="backdrop"
133
+ />
134
+ {/* // h-full modal not close */}
135
+ <div className={`${className} modal_paper`}>
136
+ <div
137
+ ref={(ref) => {
138
+ refReducer(i, ref);
139
+ }}
140
+ >
141
+ <Modal {...item.data} />
142
+ </div>
143
+ </div>
104
144
  </div>
105
- </div>
106
- </div>
107
- );
108
- })
145
+ );
146
+ })}
147
+ </>
109
148
  );
110
149
  };
111
150
 
package/src/styles.css CHANGED
@@ -16,8 +16,7 @@
16
16
  }
17
17
  }
18
18
 
19
- .backdrop_modal_manager {
20
- position: absolute;
19
+ .modal-manager.backdrop_modal_manager {
21
20
  display: flex;
22
21
  justify-content: center;
23
22
  align-items: center;
@@ -27,18 +26,23 @@
27
26
  bottom: 0;
28
27
  width: 100%;
29
28
  height: 100%;
30
- background-color: rgba(0, 0, 0, 0.5);
31
29
  position: fixed;
32
30
  z-index: 1000;
31
+ }
32
+
33
+ .modal-manager .backdrop {
34
+ background-color: rgba(0, 0, 0, 0.5);
33
35
  opacity: 0;
36
+ position: fixed;
37
+ top: 0;
38
+ left: 0;
39
+ right: 0;
40
+ bottom: 0;
34
41
  animation: bg_opacity 150ms ease-in-out forwards;
35
42
  }
36
43
 
37
- .backdrop_modal_manager > div {
44
+ .modal-manager .modal_paper {
45
+ position: relative;
46
+ z-index: 1001;
38
47
  animation: bg_opacity_scale 150ms ease-in-out forwards;
39
48
  }
40
-
41
- .main_container_modal_manager {
42
- opacity: 0;
43
- animation: bg_opacity 250ms forwards;
44
- }
@@ -1,11 +1,36 @@
1
1
  import Manager from "./Manager";
2
- declare class ModalManager extends Manager {
2
+ export declare const constants: {
3
+ CHANGE: string;
4
+ CLOSE: string;
5
+ };
6
+ interface QueueState {
7
+ queue: string[];
8
+ closedModalName?: string | undefined;
9
+ lastOpenedModal?: string | undefined;
10
+ }
11
+ interface ModalState {
12
+ isHaveOpenModals: boolean;
13
+ queue: string[];
14
+ closedModalName?: string | undefined;
15
+ lastOpenedModal?: string | undefined;
16
+ }
17
+ export declare class ModalManager extends Manager {
18
+ queue: string[];
19
+ _openModalStateCallback: null | ((props: ModalState) => void);
3
20
  constructor();
4
- create(name: string, data: {
5
- [key: string]: any;
21
+ create<T>(name: string, payload: {
22
+ modalId: number;
23
+ data?: T;
6
24
  }): void;
7
- call(name: string, data?: any): void;
25
+ call<T>(name: string, data?: T): void;
8
26
  close<T>(position?: T): void;
27
+ getQueueState({ queue, closedModalName, lastOpenedModal }: QueueState): {
28
+ isHaveOpenModals: boolean;
29
+ queue: string[];
30
+ lastOpenedModal: string | undefined;
31
+ closedModalName: string | undefined;
32
+ };
33
+ onOpenModalState(callback: (state: ModalState) => void): void;
9
34
  }
10
35
  declare const modal: ModalManager;
11
36
  export default modal;
@@ -18,32 +18,65 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
18
18
  return (mod && mod.__esModule) ? mod : { "default": mod };
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.ModalManager = exports.constants = void 0;
21
22
  var Manager_1 = __importDefault(require("./Manager"));
22
23
  function uniqueID() {
23
24
  return Math.floor(Math.random() * Date.now());
24
25
  }
25
- var constants = {
26
+ exports.constants = {
26
27
  CHANGE: "change",
27
28
  CLOSE: "close",
28
29
  };
29
30
  var ModalManager = /** @class */ (function (_super) {
30
31
  __extends(ModalManager, _super);
31
32
  function ModalManager() {
32
- return _super.call(this) || this;
33
+ var _this = _super.call(this) || this;
34
+ _this.queue = [];
35
+ _this.create = _this.create.bind(_this);
36
+ _this.call = _this.call.bind(_this);
37
+ _this.close = _this.close.bind(_this);
38
+ _this._openModalStateCallback = null;
39
+ return _this;
33
40
  }
34
- ModalManager.prototype.create = function (name, data) {
41
+ ModalManager.prototype.create = function (name, payload) {
35
42
  this.name = name;
36
- this.data = data;
37
- this.emitter.emit(constants.CHANGE, this.name, this.data);
43
+ this.data = payload;
44
+ this.emitter.emit(exports.constants.CHANGE, this.name, this.data);
38
45
  };
39
46
  ModalManager.prototype.call = function (name, data) {
40
- if (data === void 0) { data = {}; }
47
+ var _a;
41
48
  this.create(name, { modalId: uniqueID(), data: data });
49
+ var lastOpenedModal = name;
50
+ this.queue.push(name);
51
+ (_a = this._openModalStateCallback) === null || _a === void 0 ? void 0 : _a.call(this, this.getQueueState({
52
+ queue: this.queue,
53
+ lastOpenedModal: lastOpenedModal,
54
+ }));
42
55
  };
43
56
  ModalManager.prototype.close = function (position) {
44
- this.emitter.emit(constants.CLOSE, position);
57
+ var _a, _b;
58
+ this.emitter.emit(exports.constants.CLOSE, position !== null && position !== void 0 ? position : ((_a = this.queue) === null || _a === void 0 ? void 0 : _a.length) - 1);
59
+ var closedModalName = this.queue[this.queue.length - 1];
60
+ this.queue.pop();
61
+ (_b = this._openModalStateCallback) === null || _b === void 0 ? void 0 : _b.call(this, this.getQueueState({
62
+ queue: this.queue,
63
+ closedModalName: closedModalName,
64
+ }));
65
+ };
66
+ ModalManager.prototype.getQueueState = function (_a) {
67
+ var queue = _a.queue, closedModalName = _a.closedModalName, lastOpenedModal = _a.lastOpenedModal;
68
+ return {
69
+ isHaveOpenModals: queue.length > 0,
70
+ queue: queue,
71
+ lastOpenedModal: lastOpenedModal,
72
+ closedModalName: closedModalName,
73
+ };
74
+ };
75
+ ModalManager.prototype.onOpenModalState = function (callback) {
76
+ this._openModalStateCallback = callback;
45
77
  };
46
78
  return ModalManager;
47
79
  }(Manager_1.default));
80
+ exports.ModalManager = ModalManager;
48
81
  var modal = new ModalManager();
49
82
  exports.default = modal;
@@ -4,28 +4,79 @@ function uniqueID() {
4
4
  return Math.floor(Math.random() * Date.now());
5
5
  }
6
6
 
7
- const constants = {
7
+ export const constants = {
8
8
  CHANGE: "change",
9
9
  CLOSE: "close",
10
10
  };
11
11
 
12
- class ModalManager extends Manager {
12
+ interface QueueState {
13
+ queue: string[];
14
+ closedModalName?: string | undefined;
15
+ lastOpenedModal?: string | undefined;
16
+ }
17
+
18
+ interface ModalState {
19
+ isHaveOpenModals: boolean;
20
+ queue: string[];
21
+ closedModalName?: string | undefined;
22
+ lastOpenedModal?: string | undefined;
23
+ }
24
+
25
+ export class ModalManager extends Manager {
26
+ queue: string[] = [];
27
+ _openModalStateCallback: null | ((props: ModalState) => void);
28
+
13
29
  constructor() {
14
30
  super();
31
+ this.create = this.create.bind(this);
32
+ this.call = this.call.bind(this);
33
+ this.close = this.close.bind(this);
34
+ this._openModalStateCallback = null;
15
35
  }
16
36
 
17
- create(name: string, data: { [key: string]: any }) {
37
+ create<T>(name: string, payload: { modalId: number; data?: T }) {
18
38
  this.name = name;
19
- this.data = data;
39
+ this.data = payload;
20
40
  this.emitter.emit(constants.CHANGE, this.name, this.data);
21
41
  }
22
42
 
23
- call(name: string, data: any = {}) {
24
- this.create(name, { modalId: uniqueID(), data });
43
+ call<T>(name: string, data?: T) {
44
+ this.create<T>(name, { modalId: uniqueID(), data });
45
+ const lastOpenedModal = name;
46
+ this.queue.push(name);
47
+
48
+ this._openModalStateCallback?.(
49
+ this.getQueueState({
50
+ queue: this.queue,
51
+ lastOpenedModal,
52
+ })
53
+ );
25
54
  }
26
55
 
27
56
  close<T>(position?: T) {
28
- this.emitter.emit(constants.CLOSE, position);
57
+ this.emitter.emit(constants.CLOSE, position ?? this.queue?.length - 1);
58
+ const closedModalName = this.queue[this.queue.length - 1];
59
+ this.queue.pop();
60
+
61
+ this._openModalStateCallback?.(
62
+ this.getQueueState({
63
+ queue: this.queue,
64
+ closedModalName,
65
+ })
66
+ );
67
+ }
68
+
69
+ getQueueState({ queue, closedModalName, lastOpenedModal }: QueueState) {
70
+ return {
71
+ isHaveOpenModals: queue.length > 0,
72
+ queue,
73
+ lastOpenedModal: lastOpenedModal,
74
+ closedModalName,
75
+ };
76
+ }
77
+
78
+ onOpenModalState(callback: (state: ModalState) => void) {
79
+ this._openModalStateCallback = callback;
29
80
  }
30
81
  }
31
82
 
package/tsconfig.json CHANGED
@@ -2,9 +2,9 @@
2
2
  "compilerOptions": {
3
3
  "target": "es5",
4
4
  "module": "commonjs",
5
+ "esModuleInterop": true,
5
6
  "jsx": "react",
6
7
  "strict": true,
7
- "esModuleInterop": true,
8
8
  "skipLibCheck": true,
9
9
  "forceConsistentCasingInFileNames": true,
10
10
  "moduleResolution": "node",