react-flow-modal 0.4.0 → 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,6 +116,7 @@ function ConfirmModal({
113
116
  }) {
114
117
  return (
115
118
  <motion.div
119
+ key="confirm-modal-container"
116
120
  initial={{ opacity: 0 }}
117
121
  animate={{ opacity: 1 }}
118
122
  exit={{ opacity: 0 }}
@@ -135,6 +139,7 @@ function ConfirmModal({
135
139
  padding: 24,
136
140
  borderRadius: 8,
137
141
  minWidth: 300,
142
+ color: "black",
138
143
  }}
139
144
  >
140
145
  <h3>Are you sure?</h3>
@@ -149,39 +154,24 @@ function ConfirmModal({
149
154
  );
150
155
  }
151
156
 
152
- function App() {
153
- const modal = useModal();
154
-
155
- const onClick = async () => {
156
- const result = await modal.open("confirm", (resolve) => (
157
- <ConfirmModal
158
- onConfirm={() => resolve(true)}
159
- onCancel={() => resolve(false)}
160
- />
161
- ));
162
-
163
- console.log("Result:", result);
164
- };
165
-
166
- return <button onClick={onClick}>Open Confirm Modal</button>;
167
- }
168
-
169
- function ModalRenderer() {
170
- return (
171
- <AnimatePresence>
172
- {renderModals()}
173
- </AnimatePresence>
174
- );
175
- }
157
+ ...
176
158
 
177
- export default function Root() {
178
- return (
159
+ createRoot(document.getElementById('root')!).render(
160
+ <StrictMode>
179
161
  <ModalProvider>
180
162
  <App />
181
- <ModalRenderer />
163
+ <ModalHost>
164
+ {(modals) => (
165
+ <AnimatePresence>
166
+ {modals}
167
+ </AnimatePresence>
168
+ )}
169
+ </ModalHost>
182
170
  </ModalProvider>
183
- );
184
- }
171
+ </StrictMode>,
172
+ )
173
+
174
+
185
175
  ```
186
176
 
187
177
  ---
@@ -208,11 +198,13 @@ Returns an object that controls the modal flow.
208
198
  }
209
199
  ```
210
200
 
211
- ### renderModals
201
+ ### ModalHost
212
202
  ```ts
213
- renderModals(): React.ReactNode
203
+ const ModalHost: FC<{
204
+ children?: (modals: ReactElement[]) => React.ReactNode;
205
+ }>;
214
206
  ```
215
- 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.
216
208
 
217
209
  ---
218
210
 
@@ -221,9 +213,6 @@ Renders the entire modal stack. This function should be rendered **once** in you
221
213
  > ⚠️ Always resolve or reject the promise.
222
214
  > Leaving it pending will block the async flow.
223
215
 
224
- > ⚠️ `renderModals()` should be rendered once.
225
- > Rendering it multiple times may result in duplicated modals.
226
-
227
216
  ---
228
217
 
229
218
  ## Why react-flow-modal?
package/dist/index.cjs CHANGED
@@ -22,7 +22,6 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  ModalHost: () => ModalHost,
24
24
  ModalProvider: () => ModalProvider,
25
- renderModals: () => renderModals,
26
25
  useModal: () => useModal
27
26
  });
28
27
  module.exports = __toCommonJS(index_exports);
@@ -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,12 +55,9 @@ var useModalContext = () => {
53
55
  }
54
56
  return context;
55
57
  };
56
- var renderModals = () => {
57
- const { stack } = useModalContext();
58
- return stack.map((item) => item);
59
- };
60
58
 
61
59
  // src/useModal.tsx
60
+ var import_jsx_runtime2 = require("react/jsx-runtime");
62
61
  var useModal = () => {
63
62
  const { setStack } = useModalContext();
64
63
  const pop = () => {
@@ -76,23 +75,22 @@ var useModal = () => {
76
75
  reject(reason);
77
76
  pop();
78
77
  });
79
- push(element);
78
+ push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react4.Fragment, { children: element }, `modal-${key}`));
80
79
  });
81
80
  };
82
81
  return { open };
83
82
  };
84
83
 
85
84
  // src/ModalHost.tsx
86
- var import_react4 = require("react");
87
- var import_jsx_runtime2 = require("react/jsx-runtime");
88
- var ModalHost = () => {
85
+ var import_react5 = require("react");
86
+ var ModalHost = ({ children }) => {
89
87
  const { stack } = useModalContext();
90
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react4.Fragment, { children: stack.map((item) => item) });
88
+ if (!children) return stack.filter(import_react5.isValidElement);
89
+ return children(stack.filter(import_react5.isValidElement));
91
90
  };
92
91
  // Annotate the CommonJS export names for ESM import in node:
93
92
  0 && (module.exports = {
94
93
  ModalHost,
95
94
  ModalProvider,
96
- renderModals,
97
95
  useModal
98
96
  });
package/dist/index.d.cts CHANGED
@@ -1,15 +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 renderModals: () => react.ReactNode[];
14
-
15
- export { ModalHost, ModalProvider, renderModals, useModal };
13
+ export { ModalHost, ModalProvider, useModal };
package/dist/index.d.ts CHANGED
@@ -1,15 +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 renderModals: () => react.ReactNode[];
14
-
15
- export { ModalHost, ModalProvider, renderModals, useModal };
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,12 +27,9 @@ var useModalContext = () => {
24
27
  }
25
28
  return context;
26
29
  };
27
- var renderModals = () => {
28
- const { stack } = useModalContext();
29
- return stack.map((item) => item);
30
- };
31
30
 
32
31
  // src/useModal.tsx
32
+ import { jsx as jsx2 } from "react/jsx-runtime";
33
33
  var useModal = () => {
34
34
  const { setStack } = useModalContext();
35
35
  const pop = () => {
@@ -47,22 +47,21 @@ var useModal = () => {
47
47
  reject(reason);
48
48
  pop();
49
49
  });
50
- push(element);
50
+ push(/* @__PURE__ */ jsx2(Fragment, { children: element }, `modal-${key}`));
51
51
  });
52
52
  };
53
53
  return { open };
54
54
  };
55
55
 
56
56
  // src/ModalHost.tsx
57
- import { Fragment } from "react";
58
- import { jsx as jsx2 } from "react/jsx-runtime";
59
- var ModalHost = () => {
57
+ import { isValidElement } from "react";
58
+ var ModalHost = ({ children }) => {
60
59
  const { stack } = useModalContext();
61
- return /* @__PURE__ */ jsx2(Fragment, { children: stack.map((item) => item) });
60
+ if (!children) return stack.filter(isValidElement);
61
+ return children(stack.filter(isValidElement));
62
62
  };
63
63
  export {
64
64
  ModalHost,
65
65
  ModalProvider,
66
- renderModals,
67
66
  useModal
68
67
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-flow-modal",
3
- "version": "0.4.0",
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 React, { FC, Fragment } from 'react';
1
+ import { FC, isValidElement, ReactElement } from 'react';
2
2
  import { useModalContext } from './useModalContext';
3
3
 
4
- /** @deprecated use renderModals instead */
5
- export const ModalHost: FC = () => {
4
+ export const ModalHost: FC<{ children?: (modals: ReactElement[]) => React.ReactNode }> = ({ children }) => {
6
5
  const { stack } = useModalContext();
7
6
 
8
- return (
9
- <Fragment>
10
- {stack.map((item) => (item))}
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 { renderModals } 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,10 +9,4 @@ export const useModalContext = () => {
9
9
  }
10
10
 
11
11
  return context;
12
- };
13
-
14
- export const renderModals = () => {
15
- const { stack } = useModalContext();
16
-
17
- return stack.map((item) => (item));
18
12
  };