react-modal-orchestrator 1.0.0 → 1.0.2
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/README.md +2 -2
- package/package.json +7 -1
- package/.idea/ModalLib.iml +0 -9
- package/.idea/copilot.data.migration.agent.xml +0 -6
- package/.idea/copilot.data.migration.ask.xml +0 -6
- package/.idea/copilot.data.migration.ask2agent.xml +0 -6
- package/.idea/copilot.data.migration.edit.xml +0 -6
- package/.idea/misc.xml +0 -15
- package/.idea/modules.xml +0 -8
- package/src/MODAL_README.md +0 -97
- package/src/Modal/ModalHandler.tsx +0 -17
- package/src/Modal/ModalOrchestrator.tsx +0 -33
- package/src/contexts/ModalContext.ts +0 -14
- package/src/hooks/useModal.tsx +0 -65
- package/src/index.ts +0 -3
- package/src/types.ts +0 -7
- package/tsconfig.json +0 -17
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# react-modal-orchestrator
|
|
2
2
|
|
|
3
3
|
A centralized and flexible modal management system for React applications, now with lazy loading!
|
|
4
4
|
|
|
@@ -14,7 +14,7 @@ A centralized and flexible modal management system for React applications, now w
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
npm install
|
|
17
|
+
npm install react-modal-orchestrator
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
## Setup
|
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-modal-orchestrator",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/index.js"
|
|
11
|
+
},
|
|
6
12
|
"scripts": {
|
|
7
13
|
"build": "tsc",
|
|
8
14
|
"prepublishOnly": "npm run build",
|
package/.idea/ModalLib.iml
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<module type="JAVA_MODULE" version="4">
|
|
3
|
-
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
4
|
-
<exclude-output />
|
|
5
|
-
<content url="file://$MODULE_DIR$" />
|
|
6
|
-
<orderEntry type="inheritedJdk" />
|
|
7
|
-
<orderEntry type="sourceFolder" forTests="false" />
|
|
8
|
-
</component>
|
|
9
|
-
</module>
|
package/.idea/misc.xml
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="MaterialThemeProjectNewConfig">
|
|
4
|
-
<option name="metadata">
|
|
5
|
-
<MTProjectMetadataState>
|
|
6
|
-
<option name="migrated" value="true" />
|
|
7
|
-
<option name="pristineConfig" value="false" />
|
|
8
|
-
<option name="userId" value="1f7785cf:191c2f026d3:-7ffe" />
|
|
9
|
-
</MTProjectMetadataState>
|
|
10
|
-
</option>
|
|
11
|
-
</component>
|
|
12
|
-
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="temurin-17" project-jdk-type="JavaSDK">
|
|
13
|
-
<output url="file://$PROJECT_DIR$/out" />
|
|
14
|
-
</component>
|
|
15
|
-
</project>
|
package/.idea/modules.xml
DELETED
package/src/MODAL_README.md
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# What to do when creating a modal.
|
|
2
|
-
|
|
3
|
-
# 1. Create a new file named `MyModalComponent.tsx` in the component folder.
|
|
4
|
-
|
|
5
|
-
code template:
|
|
6
|
-
|
|
7
|
-
(do not pass: isOpen or setIsOpen args)
|
|
8
|
-
|
|
9
|
-
- set the `ModalWindow` isOpen to true
|
|
10
|
-
- use `closeModal` from `ModalContext` to close the modal
|
|
11
|
-
|
|
12
|
-
```javascript
|
|
13
|
-
const ModalComponent = () => {
|
|
14
|
-
const { closeModal } = useContext(ModalContext);
|
|
15
|
-
|
|
16
|
-
return (
|
|
17
|
-
<AEMPage pagePath={pagePath} aemHost={getAEMHost()}>
|
|
18
|
-
<ModalWindow variant={"large"} isOpen={true} onClose={closeModal}>
|
|
19
|
-
<ModalHeader onClose={closeModal}>
|
|
20
|
-
<div className={styles.modalHeader}>
|
|
21
|
-
MODAL HEADER
|
|
22
|
-
</div>
|
|
23
|
-
<button onClick={()=> closeModal()}>CLOSE</button>
|
|
24
|
-
</ModalHeader>
|
|
25
|
-
<ModalBody>
|
|
26
|
-
<div>
|
|
27
|
-
MODAL BODY
|
|
28
|
-
</div>
|
|
29
|
-
</ModalBody>
|
|
30
|
-
<ModalFooter placement="right">
|
|
31
|
-
<div>
|
|
32
|
-
MODAL FOOTER
|
|
33
|
-
</div>
|
|
34
|
-
</ModalFooter>
|
|
35
|
-
</ModalWindow>
|
|
36
|
-
</AEMPage>
|
|
37
|
-
);
|
|
38
|
-
};
|
|
39
|
-
export default ModalComponent;
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
# 2. Add the new modal to the constant `modals` in `ModalDictionary.tsx`.
|
|
43
|
-
# 3. Add a definition to the RenderingDictionary.
|
|
44
|
-
|
|
45
|
-
When adding the new modal to `bootstrap` for local rendering
|
|
46
|
-
- the aemComponent and/or localComponent should be the ModalHandler
|
|
47
|
-
- the modal will be prefixed with an alias to the group, to specify which modal it is
|
|
48
|
-
|
|
49
|
-
# 4. How to trigger your modal?
|
|
50
|
-
|
|
51
|
-
- use the `openModal` method from `ModalContext` to trigger the modal; `openModal` takes the name of the modal as defined in the
|
|
52
|
-
modalDictionary, optionally you can also pass in props to the modal when you are opening it.
|
|
53
|
-
|
|
54
|
-
```javascript
|
|
55
|
-
const { openModal } = useContext(ModalContext);
|
|
56
|
-
|
|
57
|
-
const handleClick = () => openModal("PST_MODAL", {
|
|
58
|
-
data: "myDatal"
|
|
59
|
-
});
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## What if my modal needs data?
|
|
63
|
-
It is not recommended to access state and/or functionality using the`useContext` hook from within your modal component (this includes accessing context from any custom hooks employed by the modal component). It is very likely that the provider supplying the context will not be available when the modal is rendered, leading to errors. Instead, you should use
|
|
64
|
-
optional props of the `openModal` method, allowing your modal to receive data when it is rendered. The props will be accessible in the modal component through the `props` argument. The only `useContext` hook you should use in your modal component is the `ModalContext` to access the `closeModal` method.
|
|
65
|
-
|
|
66
|
-
When passing optional props to the modal, you can access them in the modal component like this:
|
|
67
|
-
|
|
68
|
-
```javascript
|
|
69
|
-
const ModalComponent = ({data}: {data:string}) => {
|
|
70
|
-
console.log(data); // "myData" <<==== ACCESSING THE DATA PASSED TO THE MODAL
|
|
71
|
-
const { closeModal } = useContext(ModalContext); // <<==== ONLY useContext hook useage. ACCESSING THE CLOSE MODAL FUNCTION
|
|
72
|
-
const { data } = modalProps;
|
|
73
|
-
|
|
74
|
-
return (
|
|
75
|
-
<AEMPage pagePath={pagePath} aemHost={getAEMHost()}>
|
|
76
|
-
<ModalWindow variant={"large"} isOpen={true} onClose={closeModal}>
|
|
77
|
-
<ModalHeader onClose={closeModal}>
|
|
78
|
-
<div className={styles.modalHeader}>
|
|
79
|
-
MODAL HEADER
|
|
80
|
-
</div>
|
|
81
|
-
</ModalHeader>
|
|
82
|
-
<ModalBody>
|
|
83
|
-
<div>
|
|
84
|
-
MODAL BODY with data: {data}
|
|
85
|
-
</div>
|
|
86
|
-
</ModalBody>
|
|
87
|
-
<ModalFooter placement="right">
|
|
88
|
-
<div>
|
|
89
|
-
MODAL FOOTER
|
|
90
|
-
</div>
|
|
91
|
-
</ModalFooter>
|
|
92
|
-
</ModalWindow>
|
|
93
|
-
</AEMPage>
|
|
94
|
-
);
|
|
95
|
-
};
|
|
96
|
-
export default ModalComponent;
|
|
97
|
-
```
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { useContext, Suspense } from "react";
|
|
2
|
-
import {ModalDispatchContext, ModalStateContext} from "../contexts/ModalContext";
|
|
3
|
-
|
|
4
|
-
const ModalHandler = () => {
|
|
5
|
-
const { modal, ModalComponent } = useContext(ModalStateContext);
|
|
6
|
-
const { closeModal } = useContext(ModalDispatchContext);
|
|
7
|
-
|
|
8
|
-
if (!modal || !ModalComponent) return null;
|
|
9
|
-
if (modal) document.body.style.removeProperty("overflow");
|
|
10
|
-
|
|
11
|
-
return (
|
|
12
|
-
<Suspense fallback={<div>Loading...</div>}>
|
|
13
|
-
<ModalComponent onClose={closeModal} {...modal.props} />
|
|
14
|
-
</Suspense>
|
|
15
|
-
);
|
|
16
|
-
};
|
|
17
|
-
export default ModalHandler;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { type ReactNode, useMemo } from "react";
|
|
2
|
-
import {useModal} from "../hooks/useModal";
|
|
3
|
-
import {type GenericObjectType} from "../types";
|
|
4
|
-
import {ModalDispatchContext, ModalStateContext } from "../contexts/ModalContext";
|
|
5
|
-
|
|
6
|
-
const ModalOrchestrator = ({
|
|
7
|
-
modals,
|
|
8
|
-
children,
|
|
9
|
-
}: {
|
|
10
|
-
modals: GenericObjectType;
|
|
11
|
-
children: ReactNode;
|
|
12
|
-
}) => {
|
|
13
|
-
const { modal, ModalComponent, openModal, closeModal } = useModal(modals);
|
|
14
|
-
|
|
15
|
-
const state = useMemo(
|
|
16
|
-
() => ({ modal, ModalComponent }),
|
|
17
|
-
[modal, ModalComponent],
|
|
18
|
-
);
|
|
19
|
-
const dispatch = useMemo(
|
|
20
|
-
() => ({ openModal, closeModal }),
|
|
21
|
-
[openModal, closeModal],
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<ModalStateContext.Provider value={state}>
|
|
26
|
-
<ModalDispatchContext.Provider value={dispatch}>
|
|
27
|
-
{children}
|
|
28
|
-
</ModalDispatchContext.Provider>
|
|
29
|
-
</ModalStateContext.Provider>
|
|
30
|
-
);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export default ModalOrchestrator;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { createContext } from "react";
|
|
2
|
-
import { useModal } from "../hooks/useModal";
|
|
3
|
-
|
|
4
|
-
type ModalContextType = ReturnType<typeof useModal>;
|
|
5
|
-
|
|
6
|
-
// This context will hold the stateful values that cause re-renders.
|
|
7
|
-
export const ModalStateContext = createContext<
|
|
8
|
-
Pick<ModalContextType, "modal" | "ModalComponent">
|
|
9
|
-
>(null!);
|
|
10
|
-
|
|
11
|
-
// This context will hold the stable dispatch functions.
|
|
12
|
-
export const ModalDispatchContext = createContext<
|
|
13
|
-
Pick<ModalContextType, "openModal" | "closeModal">
|
|
14
|
-
>(null!);
|
package/src/hooks/useModal.tsx
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { type FC, useRef, useState } from "react";
|
|
2
|
-
import { type GenericModal, type GenericObjectType } from "../types";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* A custom hook to manage modals in a React application.
|
|
6
|
-
* It allows opening and closing modals, and keeps track of the modal stack.
|
|
7
|
-
*
|
|
8
|
-
* @param {GenericObjectType} modals - An object containing modal components.
|
|
9
|
-
* @returns {Object} - An object containing the current modal component, openModal and closeModal functions.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
type UseModalReturnType = {
|
|
13
|
-
ModalComponent: FC<any> | null;
|
|
14
|
-
modal: GenericModal | null;
|
|
15
|
-
openModal: (name: string, props?: object) => void;
|
|
16
|
-
closeModal: () => void;
|
|
17
|
-
};
|
|
18
|
-
export const smallGreyFont = "color: grey; font-size: 85%";
|
|
19
|
-
export const keyFont = "color: orange;font-weight: bold;";
|
|
20
|
-
|
|
21
|
-
export const useModal = (modals: GenericObjectType): UseModalReturnType => {
|
|
22
|
-
const modalStack = useRef<GenericModal[]>([]); // For purpose of keeping track of the modal stack, especially when there are multiple modals open
|
|
23
|
-
const [modal, setModal] = useState<GenericModal | null>(null);
|
|
24
|
-
const ModalLookup: GenericObjectType = { ...modals };
|
|
25
|
-
const modalName = modal ? modal.name : "";
|
|
26
|
-
const ModalComponent = ModalLookup[modalName];
|
|
27
|
-
|
|
28
|
-
const openModal = (name: string, props = {}) => {
|
|
29
|
-
// Check if the modal is already open
|
|
30
|
-
const existingModal = modalStack.current.find(
|
|
31
|
-
(modal: GenericModal) => modal.name === name,
|
|
32
|
-
);
|
|
33
|
-
if (existingModal) {
|
|
34
|
-
// If the modal is already open, just update its props
|
|
35
|
-
// additionally we don't need try/catch here, because we already know the modal name exists
|
|
36
|
-
existingModal.props = { ...existingModal.props, ...props };
|
|
37
|
-
setModal(existingModal);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
if (name in ModalLookup) {
|
|
43
|
-
modalStack.current.push({ name, props });
|
|
44
|
-
setModal({ name, props });
|
|
45
|
-
} else {
|
|
46
|
-
console.log("%cModalManager %copening:", keyFont, smallGreyFont, name);
|
|
47
|
-
console.log("%cModalStack", smallGreyFont, modalStack.current);
|
|
48
|
-
throw new Error(
|
|
49
|
-
`Modal with name "${name}" does not exist in ModalLookup.`,
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
} catch (error) {
|
|
53
|
-
console.log("Failed to open modal:", error);
|
|
54
|
-
console.error("Failed to open modal:", error);
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const closeModal = () => {
|
|
59
|
-
console.log("closeModal");
|
|
60
|
-
modalStack.current.pop();
|
|
61
|
-
setModal(modalStack.current[modalStack.current.length - 1] ?? null);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
return { ModalComponent, modal, openModal, closeModal };
|
|
65
|
-
};
|
package/src/index.ts
DELETED
package/src/types.ts
DELETED
package/tsconfig.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"declaration": true,
|
|
4
|
-
"emitDeclarationOnly": true,
|
|
5
|
-
"esModuleInterop": true,
|
|
6
|
-
"forceConsistentCasingInFileNames": true,
|
|
7
|
-
"isolatedModules": true,
|
|
8
|
-
"jsx": "react-jsx",
|
|
9
|
-
"lib": ["DOM", "ESNext"],
|
|
10
|
-
"module": "CommonJS",
|
|
11
|
-
"moduleResolution": "node",
|
|
12
|
-
"noFallthroughCasesInSwitch": true,
|
|
13
|
-
"outDir": "./dist",
|
|
14
|
-
"strict": true,
|
|
15
|
-
"target": "ESNext"
|
|
16
|
-
}
|
|
17
|
-
}
|