@4i/modal-manager 1.0.0

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/.babelrc ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "presets": ["@babel/preset-env", "@babel/preset-react"]
3
+ }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@4i/modal-manager",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "src/index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "build": "babel src -d lib"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/tonichiga/modal-manager.git"
13
+ },
14
+ "keywords": [
15
+ "modal",
16
+ "manager"
17
+ ],
18
+ "author": "Toni",
19
+ "license": "ISC",
20
+ "bugs": {
21
+ "url": "https://github.com/tonichiga/modal-manager/issues"
22
+ },
23
+ "homepage": "https://github.com/tonichiga/modal-manager#readme",
24
+ "dependencies": {
25
+ "react": "^18.2.0",
26
+ "uuid": "^9.0.1"
27
+ },
28
+ "devDependencies": {
29
+ "@babel/cli": "^7.23.4",
30
+ "@babel/core": "^7.23.5",
31
+ "@babel/preset-env": "^7.23.5",
32
+ "@babel/preset-react": "^7.23.3",
33
+ "@types/node": "^20.10.2"
34
+ }
35
+ }
@@ -0,0 +1,44 @@
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
+ .backdrop_modal_manager {
20
+ position: absolute;
21
+ display: flex;
22
+ justify-content: center;
23
+ align-items: center;
24
+ top: 0;
25
+ left: 0;
26
+ right: 0;
27
+ bottom: 0;
28
+ width: 100%;
29
+ height: 100%;
30
+ background-color: rgba(0, 0, 0, 0.5);
31
+ position: fixed;
32
+ z-index: 1000;
33
+ opacity: 0;
34
+ animation: bg_opacity 150ms ease-in-out forwards;
35
+ }
36
+
37
+ .backdrop_modal_manager > div {
38
+ animation: bg_opacity_scale 150ms ease-in-out forwards;
39
+ }
40
+
41
+ .main_container_modal_manager {
42
+ opacity: 0;
43
+ animation: bg_opacity 250ms forwards;
44
+ }
@@ -0,0 +1,108 @@
1
+ import React, { useEffect, useRef, useState } from "react";
2
+ import manager from "../utils/service/ModalManager";
3
+ import "./backdrop.css";
4
+ import modal from "../utils/service/ModalManager";
5
+ import modalList from "../utils/config/modal-list";
6
+
7
+ interface ModalProviderProps {
8
+ CustomComponent?: React.ComponentType;
9
+ }
10
+
11
+ const ModalProvider = ({ CustomComponent }: ModalProviderProps) => {
12
+ const [data, setData] = useState([]);
13
+ const [names, setNames] = useState([]);
14
+ const modalRef = useRef([]);
15
+
16
+ useEffect(() => {
17
+ const handleOpenModal = (name, data) => {
18
+ setData((prev) => [...prev, data]);
19
+ setNames((prev) => [...prev, name]);
20
+ };
21
+
22
+ const handleClose = (position) => {
23
+ if (position === "all") {
24
+ setData([]);
25
+ setNames([]);
26
+ return;
27
+ }
28
+
29
+ if (position === -1) {
30
+ // remove last
31
+ setData((prev) => prev.filter((_, index) => index !== prev.length - 1));
32
+ setNames((prev) =>
33
+ prev.filter((_, index) => index !== prev.length - 1)
34
+ );
35
+ return;
36
+ }
37
+
38
+ if (position === 0) {
39
+ // remove first
40
+ setData((prev) => prev.filter((_, index) => index !== 0));
41
+ setNames((prev) => prev.filter((_, index) => index !== 0));
42
+ return;
43
+ }
44
+
45
+ // remove position index
46
+ setData((prev) => prev.filter((_, index) => index !== prev.length - 1));
47
+ setNames((prev) => prev.filter((_, index) => index !== prev.length - 1));
48
+ };
49
+
50
+ manager.addEventListener("change", handleOpenModal);
51
+ manager.addEventListener("close", handleClose);
52
+ return () => {
53
+ manager.removeEventListener("change", handleOpenModal);
54
+ manager.removeEventListener("close", handleClose);
55
+ };
56
+ }, []);
57
+
58
+ const activeModals = names.map((name) => {
59
+ const Component = modalList[name] || (() => <></>);
60
+ return Component;
61
+ });
62
+
63
+ const handleCloseModal = (index, e) => {
64
+ if (
65
+ modalRef.current[index] &&
66
+ !modalRef.current[index].contains(e.target)
67
+ ) {
68
+ modal.close(index);
69
+ }
70
+ };
71
+
72
+ const refReducer = (index, value) => {
73
+ modalRef.current[index] = value;
74
+ };
75
+
76
+ return (
77
+ activeModals.length !== 0 &&
78
+ activeModals.map((Component, i) => {
79
+ const Modal = Component;
80
+
81
+ return (
82
+ <>
83
+ {CustomComponent ? (
84
+ <CustomComponent key={i} {...data[i]} />
85
+ ) : (
86
+ <div
87
+ key={i}
88
+ className="backdrop_modal_manager"
89
+ onClick={(e) => {
90
+ handleCloseModal(i, e);
91
+ }}
92
+ >
93
+ <div
94
+ ref={(ref) => {
95
+ refReducer(i, ref);
96
+ }}
97
+ >
98
+ <Modal key={i} {...data[i]} />
99
+ </div>
100
+ </div>
101
+ )}
102
+ </>
103
+ );
104
+ })
105
+ );
106
+ };
107
+
108
+ export default ModalProvider;
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ import Manager from "./utils/service/Manager";
2
+ import modal from "./utils/service/ModalManager";
3
+ import ModalProvider from "./components/modal-provider";
4
+ import { setModalList } from "./utils/config/modal-list";
5
+ import { setModalActions } from "./utils/config/modal-actions";
6
+
7
+ export { Manager, modal, ModalProvider, setModalList, setModalActions };
@@ -0,0 +1,11 @@
1
+ let modalActions = {};
2
+
3
+ interface ModalActions {
4
+ [key: string]: string;
5
+ }
6
+
7
+ export const setModalActions = (actionList: ModalActions) => {
8
+ modalActions = { ...modalActions, ...actionList };
9
+ };
10
+
11
+ export default modalActions;
@@ -0,0 +1,11 @@
1
+ let modalList = {};
2
+
3
+ interface ModalList {
4
+ [key: string]: string;
5
+ }
6
+
7
+ export const setModalList = (_modalList: ModalList) => {
8
+ modalList = { ...modalList, ..._modalList };
9
+ };
10
+
11
+ export default modalList;
@@ -0,0 +1,30 @@
1
+ import { EventEmitter } from "events";
2
+
3
+ const Constants = {
4
+ CHANGE: "change",
5
+ CLOSE: "close",
6
+ };
7
+
8
+ type TData = {
9
+ [key: string]: any;
10
+ };
11
+
12
+ class Manager {
13
+ emitter: EventEmitter;
14
+ name: string;
15
+ data: { [key: string]: any };
16
+
17
+ constructor() {
18
+ this.emitter = new EventEmitter();
19
+ }
20
+
21
+ addEventListener(event: string, listener: (...args: any[]) => void) {
22
+ this.emitter.addListener(event, listener);
23
+ }
24
+
25
+ removeEventListener(event: string, listener: (...args: any[]) => void) {
26
+ this.emitter.removeListener(event, listener);
27
+ }
28
+ }
29
+
30
+ export default Manager;
@@ -0,0 +1,30 @@
1
+ import Manager from "./Manager";
2
+ import { v4 as uuidv4 } from "uuid";
3
+
4
+ const constants = {
5
+ CHANGE: "change",
6
+ CLOSE: "close",
7
+ };
8
+
9
+ class ModalManager extends Manager {
10
+ constructor() {
11
+ super();
12
+ }
13
+
14
+ create(name: string, data) {
15
+ this.name = name;
16
+ this.data = data;
17
+ this.emitter.emit(constants.CHANGE);
18
+ }
19
+
20
+ call(name: string, data: any = {}) {
21
+ this.create(name, { modalId: uuidv4(), data });
22
+ }
23
+
24
+ close(position?: number) {
25
+ this.emitter.emit(constants.CLOSE, position);
26
+ }
27
+ }
28
+
29
+ const modal = new ModalManager();
30
+ export default modal;