react-flow-modal 0.4.1 → 0.5.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/README.md CHANGED
@@ -22,7 +22,9 @@ yarn add react-flow-modal
22
22
  ## Basic Usage
23
23
 
24
24
  ```tsx
25
- import { ModalProvider, useModal, renderModals } from "react-flow-modal";
25
+ import { StrictMode } from 'react';
26
+ import { createRoot } from 'react-dom/client';
27
+ import { ModalProvider, useModal, ModalHost } from "react-flow-modal";
26
28
 
27
29
  function ConfirmModal({
28
30
  onConfirm,
@@ -66,6 +68,7 @@ function App() {
66
68
  const modal = useModal();
67
69
 
68
70
  const onClick = async () => {
71
+ // render modal and await resolve
69
72
  const result = await modal.open("confirm", (resolve) => (
70
73
  <ConfirmModal
71
74
  onConfirm={() => resolve(true)}
@@ -73,24 +76,22 @@ function App() {
73
76
  />
74
77
  ));
75
78
 
79
+ // flow resumed
76
80
  console.log("Result:", result);
77
81
  };
78
82
 
79
83
  return <button onClick={onClick}>Open Confirm Modal</button>;
80
84
  }
81
85
 
82
- function ModalRenderer() {
83
- return renderModals();
84
- }
85
-
86
- export default function Root() {
87
- return (
86
+ createRoot(document.getElementById('root')!).render(
87
+ <StrictMode>
88
88
  <ModalProvider>
89
89
  <App />
90
- <ModalRenderer />
90
+ <ModalHost />
91
91
  </ModalProvider>
92
- );
93
- }
92
+ </StrictMode>,
93
+ )
94
+
94
95
  ```
95
96
 
96
97
  ---
@@ -101,8 +102,10 @@ To support exit animations, modals must be rendered inside the same
101
102
  React tree as `AnimatePresence`.
102
103
 
103
104
  ```tsx
104
- import { ModalProvider, useModal, renderModals } from "react-flow-modal";
105
- import { motion, AnimatePresence } from "motion/react";
105
+ import { StrictMode } from 'react';
106
+ import { createRoot } from 'react-dom/client';
107
+ import { ModalHost, ModalProvider } from 'react-flow-modal';
108
+ import { AnimatePresence, motion } from 'motion/react';
106
109
 
107
110
  function ConfirmModal({
108
111
  onConfirm,
@@ -113,7 +116,7 @@ function ConfirmModal({
113
116
  }) {
114
117
  return (
115
118
  <motion.div
116
- key="modal"
119
+ key="confirm-modal-container"
117
120
  initial={{ opacity: 0 }}
118
121
  animate={{ opacity: 1 }}
119
122
  exit={{ opacity: 0 }}
@@ -127,7 +130,6 @@ function ConfirmModal({
127
130
  }}
128
131
  >
129
132
  <motion.div
130
- key="modal-content"
131
133
  initial={{ scale: 0.9, opacity: 0 }}
132
134
  animate={{ scale: 1, opacity: 1 }}
133
135
  exit={{ scale: 0.95, opacity: 0 }}
@@ -137,6 +139,7 @@ function ConfirmModal({
137
139
  padding: 24,
138
140
  borderRadius: 8,
139
141
  minWidth: 300,
142
+ color: "black",
140
143
  }}
141
144
  >
142
145
  <h3>Are you sure?</h3>
@@ -151,39 +154,24 @@ function ConfirmModal({
151
154
  );
152
155
  }
153
156
 
154
- function App() {
155
- const modal = useModal();
156
-
157
- const onClick = async () => {
158
- const result = await modal.open("confirm", (resolve) => (
159
- <ConfirmModal
160
- onConfirm={() => resolve(true)}
161
- onCancel={() => resolve(false)}
162
- />
163
- ));
164
-
165
- console.log("Result:", result);
166
- };
167
-
168
- return <button onClick={onClick}>Open Confirm Modal</button>;
169
- }
170
-
171
- function ModalRenderer() {
172
- return (
173
- <AnimatePresence>
174
- {renderModals()}
175
- </AnimatePresence>
176
- );
177
- }
157
+ ...
178
158
 
179
- export default function Root() {
180
- return (
159
+ createRoot(document.getElementById('root')!).render(
160
+ <StrictMode>
181
161
  <ModalProvider>
182
162
  <App />
183
- <ModalRenderer />
163
+ <ModalHost>
164
+ {(modals) => (
165
+ <AnimatePresence>
166
+ {modals}
167
+ </AnimatePresence>
168
+ )}
169
+ </ModalHost>
184
170
  </ModalProvider>
185
- );
186
- }
171
+ </StrictMode>,
172
+ )
173
+
174
+
187
175
  ```
188
176
 
189
177
  ---
@@ -210,11 +198,13 @@ Returns an object that controls the modal flow.
210
198
  }
211
199
  ```
212
200
 
213
- ### renderModals
201
+ ### ModalHost
214
202
  ```ts
215
- renderModals(): React.ReactNode
203
+ const ModalHost: FC<{
204
+ children?: (modals: ReactElement[]) => React.ReactNode;
205
+ }>;
216
206
  ```
217
- Renders the entire modal stack. This function should be rendered **once** in your React tree.
207
+ Renders the entire modal stack. This component should be rendered **once** in your React tree.
218
208
 
219
209
  ---
220
210
 
@@ -223,9 +213,6 @@ Renders the entire modal stack. This function should be rendered **once** in you
223
213
  > ⚠️ Always resolve or reject the promise.
224
214
  > Leaving it pending will block the async flow.
225
215
 
226
- > ⚠️ `renderModals()` should be rendered once.
227
- > Rendering it multiple times may result in duplicated modals.
228
-
229
216
  ---
230
217
 
231
218
  ## Why react-flow-modal?
package/dist/index.cjs CHANGED
@@ -22,8 +22,7 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  ModalHost: () => ModalHost,
24
24
  ModalProvider: () => ModalProvider,
25
- useModal: () => useModal,
26
- useModalHost: () => useModalHost
25
+ useModal: () => useModal
27
26
  });
28
27
  module.exports = __toCommonJS(index_exports);
29
28
 
@@ -44,6 +43,9 @@ var ModalProvider = ({ children }) => {
44
43
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalContext.Provider, { value: { stack, setStack }, children });
45
44
  };
46
45
 
46
+ // src/useModal.tsx
47
+ var import_react4 = require("react");
48
+
47
49
  // src/useModalContext.ts
48
50
  var import_react3 = require("react");
49
51
  var useModalContext = () => {
@@ -53,14 +55,9 @@ var useModalContext = () => {
53
55
  }
54
56
  return context;
55
57
  };
56
- var useModalHost = () => {
57
- const { stack } = useModalContext();
58
- return {
59
- render: () => stack.map((item) => item)
60
- };
61
- };
62
58
 
63
59
  // src/useModal.tsx
60
+ var import_jsx_runtime2 = require("react/jsx-runtime");
64
61
  var useModal = () => {
65
62
  const { setStack } = useModalContext();
66
63
  const pop = () => {
@@ -78,23 +75,22 @@ var useModal = () => {
78
75
  reject(reason);
79
76
  pop();
80
77
  });
81
- push(element);
78
+ push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react4.Fragment, { children: element }, `modal-${key}`));
82
79
  });
83
80
  };
84
81
  return { open };
85
82
  };
86
83
 
87
84
  // src/ModalHost.tsx
88
- var import_react4 = require("react");
89
- var import_jsx_runtime2 = require("react/jsx-runtime");
90
- var ModalHost = () => {
91
- const { render } = useModalHost();
92
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react4.Fragment, { children: render() });
85
+ var import_react5 = require("react");
86
+ var ModalHost = ({ children }) => {
87
+ const { stack } = useModalContext();
88
+ if (!children) return stack.filter(import_react5.isValidElement);
89
+ return children(stack.filter(import_react5.isValidElement));
93
90
  };
94
91
  // Annotate the CommonJS export names for ESM import in node:
95
92
  0 && (module.exports = {
96
93
  ModalHost,
97
94
  ModalProvider,
98
- useModal,
99
- useModalHost
95
+ useModal
100
96
  });
package/dist/index.d.cts CHANGED
@@ -1,17 +1,13 @@
1
- import * as react from 'react';
2
- import react__default, { FC, PropsWithChildren } from 'react';
1
+ import React$1, { FC, PropsWithChildren, ReactElement } from 'react';
3
2
 
4
3
  declare const ModalProvider: FC<PropsWithChildren>;
5
4
 
6
5
  declare const useModal: () => {
7
- open: <T>(key: string, render: (resolve: (value: T) => void, reject: (reason?: unknown) => void) => react__default.ReactNode) => Promise<T>;
6
+ open: <T>(key: string, render: (resolve: (value: T) => void, reject: (reason?: unknown) => void) => React$1.ReactNode) => Promise<T>;
8
7
  };
9
8
 
10
- /** @deprecated use renderModals instead */
11
- declare const ModalHost: FC;
9
+ declare const ModalHost: FC<{
10
+ children?: (modals: ReactElement[]) => React.ReactNode;
11
+ }>;
12
12
 
13
- declare const useModalHost: () => {
14
- render: () => react.ReactNode[];
15
- };
16
-
17
- export { ModalHost, ModalProvider, useModal, useModalHost };
13
+ export { ModalHost, ModalProvider, useModal };
package/dist/index.d.ts CHANGED
@@ -1,17 +1,13 @@
1
- import * as react from 'react';
2
- import react__default, { FC, PropsWithChildren } from 'react';
1
+ import React$1, { FC, PropsWithChildren, ReactElement } from 'react';
3
2
 
4
3
  declare const ModalProvider: FC<PropsWithChildren>;
5
4
 
6
5
  declare const useModal: () => {
7
- open: <T>(key: string, render: (resolve: (value: T) => void, reject: (reason?: unknown) => void) => react__default.ReactNode) => Promise<T>;
6
+ open: <T>(key: string, render: (resolve: (value: T) => void, reject: (reason?: unknown) => void) => React$1.ReactNode) => Promise<T>;
8
7
  };
9
8
 
10
- /** @deprecated use renderModals instead */
11
- declare const ModalHost: FC;
9
+ declare const ModalHost: FC<{
10
+ children?: (modals: ReactElement[]) => React.ReactNode;
11
+ }>;
12
12
 
13
- declare const useModalHost: () => {
14
- render: () => react.ReactNode[];
15
- };
16
-
17
- export { ModalHost, ModalProvider, useModal, useModalHost };
13
+ export { ModalHost, ModalProvider, useModal };
package/dist/index.js CHANGED
@@ -15,6 +15,9 @@ var ModalProvider = ({ children }) => {
15
15
  return /* @__PURE__ */ jsx(ModalContext.Provider, { value: { stack, setStack }, children });
16
16
  };
17
17
 
18
+ // src/useModal.tsx
19
+ import { Fragment } from "react";
20
+
18
21
  // src/useModalContext.ts
19
22
  import { useContext } from "react";
20
23
  var useModalContext = () => {
@@ -24,14 +27,9 @@ var useModalContext = () => {
24
27
  }
25
28
  return context;
26
29
  };
27
- var useModalHost = () => {
28
- const { stack } = useModalContext();
29
- return {
30
- render: () => stack.map((item) => item)
31
- };
32
- };
33
30
 
34
31
  // src/useModal.tsx
32
+ import { jsx as jsx2 } from "react/jsx-runtime";
35
33
  var useModal = () => {
36
34
  const { setStack } = useModalContext();
37
35
  const pop = () => {
@@ -49,22 +47,21 @@ var useModal = () => {
49
47
  reject(reason);
50
48
  pop();
51
49
  });
52
- push(element);
50
+ push(/* @__PURE__ */ jsx2(Fragment, { children: element }, `modal-${key}`));
53
51
  });
54
52
  };
55
53
  return { open };
56
54
  };
57
55
 
58
56
  // src/ModalHost.tsx
59
- import { Fragment } from "react";
60
- import { jsx as jsx2 } from "react/jsx-runtime";
61
- var ModalHost = () => {
62
- const { render } = useModalHost();
63
- return /* @__PURE__ */ jsx2(Fragment, { children: render() });
57
+ import { isValidElement } from "react";
58
+ var ModalHost = ({ children }) => {
59
+ const { stack } = useModalContext();
60
+ if (!children) return stack.filter(isValidElement);
61
+ return children(stack.filter(isValidElement));
64
62
  };
65
63
  export {
66
64
  ModalHost,
67
65
  ModalProvider,
68
- useModal,
69
- useModalHost
66
+ useModal
70
67
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-flow-modal",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Promise-based modal flows for React",
5
5
  "repository": {
6
6
  "type": "git",
package/src/ModalHost.tsx CHANGED
@@ -1,13 +1,9 @@
1
- import { FC, Fragment } from 'react';
2
- import { useModalHost } from './useModalContext';
1
+ import { FC, isValidElement, ReactElement } from 'react';
2
+ import { useModalContext } from './useModalContext';
3
3
 
4
- /** @deprecated use renderModals instead */
5
- export const ModalHost: FC = () => {
6
- const { render } = useModalHost();
4
+ export const ModalHost: FC<{ children?: (modals: ReactElement[]) => React.ReactNode }> = ({ children }) => {
5
+ const { stack } = useModalContext();
7
6
 
8
- return (
9
- <Fragment>
10
- {render()}
11
- </Fragment>
12
- );
7
+ if (!children) return stack.filter(isValidElement);
8
+ return children(stack.filter(isValidElement));
13
9
  };
package/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export { ModalProvider } from './ModalProvider';
2
2
  export { useModal } from './useModal';
3
- export { ModalHost } from './ModalHost';
4
- export { useModalHost } from './useModalContext';
3
+ export { ModalHost } from './ModalHost';
package/src/useModal.tsx CHANGED
@@ -29,7 +29,7 @@ export const useModal = () => {
29
29
  reject(reason);
30
30
  pop();
31
31
  });
32
- push(element);
32
+ push(<Fragment key={`modal-${key}`}>{element}</Fragment>);
33
33
  });
34
34
  };
35
35
 
@@ -9,12 +9,4 @@ export const useModalContext = () => {
9
9
  }
10
10
 
11
11
  return context;
12
- };
13
-
14
- export const useModalHost = () => {
15
- const { stack } = useModalContext();
16
-
17
- return {
18
- render: () => stack.map((item) => (item)),
19
- };
20
12
  };