@4i/modal-manager 1.1.10 → 1.1.20
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 +42 -40
- package/readme.md +285 -285
- package/src/components/modal-provider.d.ts +1 -1
- package/src/components/modal-provider.js +8 -3
- package/src/components/modal-provider.tsx +169 -163
- package/src/index.ts +5 -5
- package/src/styles.css +77 -77
- package/src/utils/Manager.ts +27 -27
- package/src/utils/ModalManager.ts +94 -94
- package/tsconfig.json +17 -16
@@ -12,5 +12,5 @@ interface ModalProviderProps {
|
|
12
12
|
type TData = {
|
13
13
|
[key: string]: any;
|
14
14
|
};
|
15
|
-
declare const ModalProvider: ({ modalList, isOverflow, className, backdropClassName, onModalStateChange, }: ModalProviderProps) =>
|
15
|
+
declare const ModalProvider: ({ modalList, isOverflow, className, backdropClassName, onModalStateChange, }: ModalProviderProps) => null;
|
16
16
|
export default ModalProvider;
|
@@ -82,6 +82,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
82
82
|
Object.defineProperty(exports, "__esModule", { value: true });
|
83
83
|
var react_1 = __importStar(require("react"));
|
84
84
|
var ModalManager_1 = __importStar(require("../utils/ModalManager"));
|
85
|
+
var react_dom_1 = require("react-dom");
|
85
86
|
var ModalProvider = function (_a) {
|
86
87
|
var modalList = _a.modalList, isOverflow = _a.isOverflow, className = _a.className, backdropClassName = _a.backdropClassName, onModalStateChange = _a.onModalStateChange;
|
87
88
|
var _b = (0, react_1.useState)([]), data = _b[0], setData = _b[1];
|
@@ -118,7 +119,9 @@ var ModalProvider = function (_a) {
|
|
118
119
|
var handleClose = function (position) { return __awaiter(void 0, void 0, void 0, function () {
|
119
120
|
return __generator(this, function (_a) {
|
120
121
|
switch (_a.label) {
|
121
|
-
case 0:
|
122
|
+
case 0:
|
123
|
+
console.log("position", position);
|
124
|
+
return [4 /*yield*/, applyCloseStyles(position)];
|
122
125
|
case 1:
|
123
126
|
_a.sent();
|
124
127
|
if (isOverflow) {
|
@@ -176,7 +179,8 @@ var ModalProvider = function (_a) {
|
|
176
179
|
var refReducer = function (index, value) {
|
177
180
|
modalRef.current[index] = value;
|
178
181
|
};
|
179
|
-
|
182
|
+
var body = document.body;
|
183
|
+
(0, react_dom_1.createPortal)(react_1.default.createElement(react_1.default.Fragment, null, data.length !== 0 &&
|
180
184
|
data.map(function (item, i) {
|
181
185
|
var Modal = activeModals[i] || (function () { return react_1.default.createElement(react_1.default.Fragment, null); });
|
182
186
|
return (react_1.default.createElement("div", { "data-index": i, key: item.modalId, className: "modal-manager backdrop_modal_manager ".concat(backdropClassName) },
|
@@ -189,6 +193,7 @@ var ModalProvider = function (_a) {
|
|
189
193
|
refReducer(i, ref);
|
190
194
|
} },
|
191
195
|
react_1.default.createElement(Modal, __assign({}, item.data))))));
|
192
|
-
})));
|
196
|
+
})), body);
|
197
|
+
return null;
|
193
198
|
};
|
194
199
|
exports.default = ModalProvider;
|
@@ -1,163 +1,169 @@
|
|
1
|
-
"use client";
|
2
|
-
|
3
|
-
import React, { useEffect, useRef, useState } from "react";
|
4
|
-
import modal, { constants } from "../utils/ModalManager";
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
const [
|
31
|
-
const
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
modal
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
document
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
)
|
83
|
-
|
84
|
-
|
85
|
-
)
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
)
|
100
|
-
|
101
|
-
|
102
|
-
)
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
}
|
162
|
-
|
163
|
-
|
1
|
+
"use client";
|
2
|
+
|
3
|
+
import React, { useEffect, useRef, useState } from "react";
|
4
|
+
import modal, { constants } from "../utils/ModalManager";
|
5
|
+
import { createPortal } from "react-dom";
|
6
|
+
|
7
|
+
export type ModalList = { [key: string]: React.ComponentType };
|
8
|
+
|
9
|
+
interface ModalProviderProps {
|
10
|
+
modalList: any;
|
11
|
+
isOverflow?: boolean;
|
12
|
+
className?: string;
|
13
|
+
backdropClassName?: string;
|
14
|
+
onModalStateChange?: (
|
15
|
+
modalState: boolean,
|
16
|
+
data: TData[],
|
17
|
+
names: string[]
|
18
|
+
) => void;
|
19
|
+
}
|
20
|
+
|
21
|
+
type TData = { [key: string]: any };
|
22
|
+
|
23
|
+
const ModalProvider = ({
|
24
|
+
modalList,
|
25
|
+
isOverflow,
|
26
|
+
className,
|
27
|
+
backdropClassName,
|
28
|
+
onModalStateChange,
|
29
|
+
}: ModalProviderProps) => {
|
30
|
+
const [data, setData] = useState<TData[]>([]);
|
31
|
+
const [names, setNames] = useState<string[]>([]);
|
32
|
+
const modalRef = useRef<any[]>([]);
|
33
|
+
|
34
|
+
const applyCloseStyles = (index: number) => {
|
35
|
+
return new Promise((resolve) => {
|
36
|
+
const modal = document.querySelector(
|
37
|
+
`[data-index="${index}"]`
|
38
|
+
) as HTMLElement;
|
39
|
+
if (!modal) return;
|
40
|
+
modal.classList.add("closing");
|
41
|
+
setTimeout(() => {
|
42
|
+
resolve(true);
|
43
|
+
}, 150);
|
44
|
+
});
|
45
|
+
};
|
46
|
+
|
47
|
+
useEffect(() => {
|
48
|
+
if (!onModalStateChange) return;
|
49
|
+
const modalState = data.length !== 0;
|
50
|
+
onModalStateChange(modalState, data, names);
|
51
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
52
|
+
}, [data, names]);
|
53
|
+
|
54
|
+
useEffect(() => {
|
55
|
+
const handleOpenModal = (name: string, data: TData) => {
|
56
|
+
setData((prev: TData[]) => [...prev, data]);
|
57
|
+
setNames((prev: string[]) => [...prev, name]);
|
58
|
+
|
59
|
+
if (isOverflow) {
|
60
|
+
if (typeof document === "undefined") return;
|
61
|
+
document.body.style.overflow = "hidden";
|
62
|
+
}
|
63
|
+
};
|
64
|
+
|
65
|
+
const handleClose = async (position: number | string) => {
|
66
|
+
console.log("position", position);
|
67
|
+
await applyCloseStyles(position as number);
|
68
|
+
if (isOverflow) {
|
69
|
+
if (typeof document !== "undefined") {
|
70
|
+
document.body.style.overflow = "";
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
if (position === "all") {
|
75
|
+
setData([]);
|
76
|
+
setNames([]);
|
77
|
+
return;
|
78
|
+
}
|
79
|
+
|
80
|
+
if (position === -1) {
|
81
|
+
// remove last
|
82
|
+
setData((prev: TData[]) =>
|
83
|
+
prev.filter((_, index) => index !== prev.length - 1)
|
84
|
+
);
|
85
|
+
setNames((prev: string[]) =>
|
86
|
+
prev.filter((_, index) => index !== prev.length - 1)
|
87
|
+
);
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
|
91
|
+
if (position === 0) {
|
92
|
+
// remove first
|
93
|
+
setData((prev: TData[]) => prev.filter((_, index) => index !== 0));
|
94
|
+
setNames((prev: string[]) => prev.filter((_, index) => index !== 0));
|
95
|
+
return;
|
96
|
+
}
|
97
|
+
|
98
|
+
// remove position index
|
99
|
+
setData((prev: TData[]) =>
|
100
|
+
prev.filter((_, index) => index !== prev.length - 1)
|
101
|
+
);
|
102
|
+
setNames((prev: string[]) =>
|
103
|
+
prev.filter((_, index) => index !== prev.length - 1)
|
104
|
+
);
|
105
|
+
};
|
106
|
+
|
107
|
+
modal.addEventListener(constants.CHANGE, handleOpenModal);
|
108
|
+
modal.addEventListener(constants.CLOSE, handleClose);
|
109
|
+
return () => {
|
110
|
+
modal.removeEventListener(constants.CHANGE, handleOpenModal);
|
111
|
+
modal.removeEventListener(constants.CLOSE, handleClose);
|
112
|
+
};
|
113
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
114
|
+
}, []);
|
115
|
+
|
116
|
+
const activeModals = names.map((name: string) => {
|
117
|
+
const Component = modalList[name] || (() => <></>);
|
118
|
+
return Component;
|
119
|
+
});
|
120
|
+
|
121
|
+
const handleCloseModal = (index: number) => {
|
122
|
+
modal.close(index);
|
123
|
+
};
|
124
|
+
|
125
|
+
const refReducer = (index: number, value: any) => {
|
126
|
+
modalRef.current[index] = value;
|
127
|
+
};
|
128
|
+
|
129
|
+
const body = document.body;
|
130
|
+
createPortal(
|
131
|
+
<>
|
132
|
+
{data.length !== 0 &&
|
133
|
+
data.map((item, i) => {
|
134
|
+
const Modal = activeModals[i] || (() => <></>);
|
135
|
+
|
136
|
+
return (
|
137
|
+
<div
|
138
|
+
data-index={i}
|
139
|
+
key={item.modalId}
|
140
|
+
className={`modal-manager backdrop_modal_manager ${backdropClassName}`}
|
141
|
+
>
|
142
|
+
<div
|
143
|
+
onClick={(e) => {
|
144
|
+
e.stopPropagation();
|
145
|
+
handleCloseModal(i);
|
146
|
+
}}
|
147
|
+
className="backdrop"
|
148
|
+
/>
|
149
|
+
{/* // h-full modal not close */}
|
150
|
+
<div className={`${className} modal_paper`}>
|
151
|
+
<div
|
152
|
+
ref={(ref) => {
|
153
|
+
refReducer(i, ref);
|
154
|
+
}}
|
155
|
+
>
|
156
|
+
<Modal {...item.data} />
|
157
|
+
</div>
|
158
|
+
</div>
|
159
|
+
</div>
|
160
|
+
);
|
161
|
+
})}
|
162
|
+
</>,
|
163
|
+
body
|
164
|
+
);
|
165
|
+
|
166
|
+
return null;
|
167
|
+
};
|
168
|
+
|
169
|
+
export default ModalProvider;
|
package/src/index.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import Manager from "./utils/Manager";
|
2
|
-
import modal from "./utils/ModalManager";
|
3
|
-
import ModalProvider from "./components/modal-provider";
|
4
|
-
|
5
|
-
export { Manager, modal, ModalProvider };
|
1
|
+
import Manager from "./utils/Manager";
|
2
|
+
import modal from "./utils/ModalManager";
|
3
|
+
import ModalProvider from "./components/modal-provider";
|
4
|
+
|
5
|
+
export { Manager, modal, ModalProvider };
|
package/src/styles.css
CHANGED
@@ -1,77 +1,77 @@
|
|
1
|
-
@keyframes bg_opacity_scale {
|
2
|
-
from {
|
3
|
-
transform: scale(0.8);
|
4
|
-
}
|
5
|
-
to {
|
6
|
-
transform: scale(1);
|
7
|
-
}
|
8
|
-
}
|
9
|
-
|
10
|
-
@keyframes bg_opacity {
|
11
|
-
from {
|
12
|
-
opacity: 0;
|
13
|
-
}
|
14
|
-
to {
|
15
|
-
opacity: 1;
|
16
|
-
}
|
17
|
-
}
|
18
|
-
|
19
|
-
@keyframes bg_opacity_out {
|
20
|
-
from {
|
21
|
-
opacity: 1;
|
22
|
-
}
|
23
|
-
to {
|
24
|
-
opacity: 0;
|
25
|
-
}
|
26
|
-
}
|
27
|
-
|
28
|
-
@keyframes bg_scale_out {
|
29
|
-
from {
|
30
|
-
opacity: 1;
|
31
|
-
transform: scale(1);
|
32
|
-
}
|
33
|
-
to {
|
34
|
-
opacity: 0;
|
35
|
-
transform: scale(0.9);
|
36
|
-
}
|
37
|
-
}
|
38
|
-
|
39
|
-
.modal-manager.backdrop_modal_manager {
|
40
|
-
display: flex;
|
41
|
-
justify-content: center;
|
42
|
-
align-items: center;
|
43
|
-
top: 0;
|
44
|
-
left: 0;
|
45
|
-
right: 0;
|
46
|
-
bottom: 0;
|
47
|
-
width: 100%;
|
48
|
-
height: 100%;
|
49
|
-
position: fixed;
|
50
|
-
z-index:
|
51
|
-
}
|
52
|
-
|
53
|
-
.modal-manager .backdrop {
|
54
|
-
background-color: rgba(0, 0, 0, 0.5);
|
55
|
-
opacity: 0;
|
56
|
-
position: fixed;
|
57
|
-
top: 0;
|
58
|
-
left: 0;
|
59
|
-
right: 0;
|
60
|
-
bottom: 0;
|
61
|
-
animation: bg_opacity 150ms ease-in-out forwards;
|
62
|
-
}
|
63
|
-
|
64
|
-
.modal-manager .modal_paper {
|
65
|
-
position: relative;
|
66
|
-
z-index: 1001;
|
67
|
-
animation: bg_opacity_scale 150ms ease-in-out forwards;
|
68
|
-
width: 100%;
|
69
|
-
}
|
70
|
-
|
71
|
-
.modal-manager.closing .backdrop {
|
72
|
-
animation: bg_opacity_out 150ms ease-in-out forwards;
|
73
|
-
}
|
74
|
-
|
75
|
-
.modal-manager.closing .modal_paper {
|
76
|
-
animation: bg_scale_out 150ms ease-in-out forwards;
|
77
|
-
}
|
1
|
+
@keyframes bg_opacity_scale {
|
2
|
+
from {
|
3
|
+
transform: scale(0.8);
|
4
|
+
}
|
5
|
+
to {
|
6
|
+
transform: scale(1);
|
7
|
+
}
|
8
|
+
}
|
9
|
+
|
10
|
+
@keyframes bg_opacity {
|
11
|
+
from {
|
12
|
+
opacity: 0;
|
13
|
+
}
|
14
|
+
to {
|
15
|
+
opacity: 1;
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
@keyframes bg_opacity_out {
|
20
|
+
from {
|
21
|
+
opacity: 1;
|
22
|
+
}
|
23
|
+
to {
|
24
|
+
opacity: 0;
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
@keyframes bg_scale_out {
|
29
|
+
from {
|
30
|
+
opacity: 1;
|
31
|
+
transform: scale(1);
|
32
|
+
}
|
33
|
+
to {
|
34
|
+
opacity: 0;
|
35
|
+
transform: scale(0.9);
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
.modal-manager.backdrop_modal_manager {
|
40
|
+
display: flex;
|
41
|
+
justify-content: center;
|
42
|
+
align-items: center;
|
43
|
+
top: 0;
|
44
|
+
left: 0;
|
45
|
+
right: 0;
|
46
|
+
bottom: 0;
|
47
|
+
width: 100%;
|
48
|
+
height: 100%;
|
49
|
+
position: fixed;
|
50
|
+
z-index: 20000;
|
51
|
+
}
|
52
|
+
|
53
|
+
.modal-manager .backdrop {
|
54
|
+
background-color: rgba(0, 0, 0, 0.5);
|
55
|
+
opacity: 0;
|
56
|
+
position: fixed;
|
57
|
+
top: 0;
|
58
|
+
left: 0;
|
59
|
+
right: 0;
|
60
|
+
bottom: 0;
|
61
|
+
animation: bg_opacity 150ms ease-in-out forwards;
|
62
|
+
}
|
63
|
+
|
64
|
+
.modal-manager .modal_paper {
|
65
|
+
position: relative;
|
66
|
+
z-index: 1001;
|
67
|
+
animation: bg_opacity_scale 150ms ease-in-out forwards;
|
68
|
+
width: 100%;
|
69
|
+
}
|
70
|
+
|
71
|
+
.modal-manager.closing .backdrop {
|
72
|
+
animation: bg_opacity_out 150ms ease-in-out forwards;
|
73
|
+
}
|
74
|
+
|
75
|
+
.modal-manager.closing .modal_paper {
|
76
|
+
animation: bg_scale_out 150ms ease-in-out forwards;
|
77
|
+
}
|
package/src/utils/Manager.ts
CHANGED
@@ -1,27 +1,27 @@
|
|
1
|
-
import { EventEmitter } from "events";
|
2
|
-
|
3
|
-
type TData = {
|
4
|
-
[key: string]: any;
|
5
|
-
};
|
6
|
-
|
7
|
-
class Manager {
|
8
|
-
emitter: EventEmitter;
|
9
|
-
name: string | null;
|
10
|
-
data: { [key: string]: any };
|
11
|
-
|
12
|
-
constructor() {
|
13
|
-
this.name = "";
|
14
|
-
this.data = {};
|
15
|
-
this.emitter = new EventEmitter();
|
16
|
-
}
|
17
|
-
|
18
|
-
addEventListener(event: string, listener: (...args: any[]) => void) {
|
19
|
-
this.emitter.addListener(event, listener);
|
20
|
-
}
|
21
|
-
|
22
|
-
removeEventListener(event: string, listener: (...args: any[]) => void) {
|
23
|
-
this.emitter.removeListener(event, listener);
|
24
|
-
}
|
25
|
-
}
|
26
|
-
|
27
|
-
export default Manager;
|
1
|
+
import { EventEmitter } from "events";
|
2
|
+
|
3
|
+
type TData = {
|
4
|
+
[key: string]: any;
|
5
|
+
};
|
6
|
+
|
7
|
+
class Manager {
|
8
|
+
emitter: EventEmitter;
|
9
|
+
name: string | null;
|
10
|
+
data: { [key: string]: any };
|
11
|
+
|
12
|
+
constructor() {
|
13
|
+
this.name = "";
|
14
|
+
this.data = {};
|
15
|
+
this.emitter = new EventEmitter();
|
16
|
+
}
|
17
|
+
|
18
|
+
addEventListener(event: string, listener: (...args: any[]) => void) {
|
19
|
+
this.emitter.addListener(event, listener);
|
20
|
+
}
|
21
|
+
|
22
|
+
removeEventListener(event: string, listener: (...args: any[]) => void) {
|
23
|
+
this.emitter.removeListener(event, listener);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
export default Manager;
|