@4i/modal-manager 1.1.10 → 1.1.20

Sign up to get free protection for your applications and to get access to all the features.
@@ -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) => React.JSX.Element;
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: return [4 /*yield*/, applyCloseStyles(position)];
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
- return (react_1.default.createElement(react_1.default.Fragment, null, data.length !== 0 &&
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
- export type ModalList = { [key: string]: React.ComponentType };
7
-
8
- interface ModalProviderProps {
9
- modalList: any;
10
- isOverflow?: boolean;
11
- className?: string;
12
- backdropClassName?: string;
13
- onModalStateChange?: (
14
- modalState: boolean,
15
- data: TData[],
16
- names: string[]
17
- ) => void;
18
- }
19
-
20
- type TData = { [key: string]: any };
21
-
22
- const ModalProvider = ({
23
- modalList,
24
- isOverflow,
25
- className,
26
- backdropClassName,
27
- onModalStateChange,
28
- }: ModalProviderProps) => {
29
- const [data, setData] = useState<TData[]>([]);
30
- const [names, setNames] = useState<string[]>([]);
31
- const modalRef = useRef<any[]>([]);
32
-
33
- const applyCloseStyles = (index: number) => {
34
- return new Promise((resolve) => {
35
- const modal = document.querySelector(
36
- `[data-index="${index}"]`
37
- ) as HTMLElement;
38
- if (!modal) return;
39
- modal.classList.add("closing");
40
- setTimeout(() => {
41
- resolve(true);
42
- }, 150);
43
- });
44
- };
45
-
46
- useEffect(() => {
47
- if (!onModalStateChange) return;
48
- const modalState = data.length !== 0;
49
- onModalStateChange(modalState, data, names);
50
- // eslint-disable-next-line react-hooks/exhaustive-deps
51
- }, [data, names]);
52
-
53
- useEffect(() => {
54
- const handleOpenModal = (name: string, data: TData) => {
55
- setData((prev: TData[]) => [...prev, data]);
56
- setNames((prev: string[]) => [...prev, name]);
57
-
58
- if (isOverflow) {
59
- if (typeof document === "undefined") return;
60
- document.body.style.overflow = "hidden";
61
- }
62
- };
63
-
64
- const handleClose = async (position: number | string) => {
65
- await applyCloseStyles(position as number);
66
- if (isOverflow) {
67
- if (typeof document !== "undefined") {
68
- document.body.style.overflow = "";
69
- }
70
- }
71
-
72
- if (position === "all") {
73
- setData([]);
74
- setNames([]);
75
- return;
76
- }
77
-
78
- if (position === -1) {
79
- // remove last
80
- setData((prev: TData[]) =>
81
- prev.filter((_, index) => index !== prev.length - 1)
82
- );
83
- setNames((prev: string[]) =>
84
- prev.filter((_, index) => index !== prev.length - 1)
85
- );
86
- return;
87
- }
88
-
89
- if (position === 0) {
90
- // remove first
91
- setData((prev: TData[]) => prev.filter((_, index) => index !== 0));
92
- setNames((prev: string[]) => prev.filter((_, index) => index !== 0));
93
- return;
94
- }
95
-
96
- // remove position index
97
- setData((prev: TData[]) =>
98
- prev.filter((_, index) => index !== prev.length - 1)
99
- );
100
- setNames((prev: string[]) =>
101
- prev.filter((_, index) => index !== prev.length - 1)
102
- );
103
- };
104
-
105
- modal.addEventListener(constants.CHANGE, handleOpenModal);
106
- modal.addEventListener(constants.CLOSE, handleClose);
107
- return () => {
108
- modal.removeEventListener(constants.CHANGE, handleOpenModal);
109
- modal.removeEventListener(constants.CLOSE, handleClose);
110
- };
111
- // eslint-disable-next-line react-hooks/exhaustive-deps
112
- }, []);
113
-
114
- const activeModals = names.map((name: string) => {
115
- const Component = modalList[name] || (() => <></>);
116
- return Component;
117
- });
118
-
119
- const handleCloseModal = (index: number) => {
120
- modal.close(index);
121
- };
122
-
123
- const refReducer = (index: number, value: any) => {
124
- modalRef.current[index] = value;
125
- };
126
-
127
- return (
128
- <>
129
- {data.length !== 0 &&
130
- data.map((item, i) => {
131
- const Modal = activeModals[i] || (() => <></>);
132
-
133
- return (
134
- <div
135
- data-index={i}
136
- key={item.modalId}
137
- className={`modal-manager backdrop_modal_manager ${backdropClassName}`}
138
- >
139
- <div
140
- onClick={(e) => {
141
- e.stopPropagation();
142
- handleCloseModal(i);
143
- }}
144
- className="backdrop"
145
- />
146
- {/* // h-full modal not close */}
147
- <div className={`${className} modal_paper`}>
148
- <div
149
- ref={(ref) => {
150
- refReducer(i, ref);
151
- }}
152
- >
153
- <Modal {...item.data} />
154
- </div>
155
- </div>
156
- </div>
157
- );
158
- })}
159
- </>
160
- );
161
- };
162
-
163
- export default ModalProvider;
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: 1000;
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
+ }
@@ -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;