@lerx/promise-modal 0.8.3 → 0.8.5
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 +53 -0
- package/dist/app/ModalManager.d.ts +5 -2
- package/dist/components/Anchor/style.d.ts +1 -0
- package/dist/core/handle/alert.d.ts +16 -148
- package/dist/core/handle/confirm.d.ts +18 -151
- package/dist/core/handle/index.d.ts +5 -3
- package/dist/core/handle/prompt.d.ts +23 -212
- package/dist/core/handle/static.d.ts +105 -0
- package/dist/core/handle/type.d.ts +99 -0
- package/dist/core/node/ModalNode/AbstractNode.d.ts +7 -5
- package/dist/core/node/ModalNode/AlertNode.d.ts +2 -2
- package/dist/core/node/ModalNode/ConfirmNode.d.ts +2 -2
- package/dist/core/node/ModalNode/PromptNode.d.ts +2 -2
- package/dist/helpers/closeModal.d.ts +2 -0
- package/dist/helpers/subscribeAbortSignal.d.ts +2 -0
- package/dist/hooks/useModal.d.ts +6 -0
- package/dist/index.cjs +238 -171
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +239 -173
- package/dist/providers/ConfigurationContext/ConfigurationContext.d.ts +4 -2
- package/dist/providers/ConfigurationContext/useConfigurationContext.d.ts +3 -1
- package/dist/providers/ModalManagerContext/ModalManagerContext.d.ts +0 -1
- package/dist/providers/ModalManagerContext/index.d.ts +1 -1
- package/dist/providers/ModalManagerContext/useModalManagerContext.d.ts +1 -1
- package/dist/providers/index.d.ts +1 -1
- package/dist/types/base.d.ts +2 -1
- package/dist/types/option.d.ts +2 -2
- package/package.json +2 -2
- package/dist/tsconfig.tsbuildinfo +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { createContext, useContext, useMemo, forwardRef, memo, useRef, useState, useLayoutEffect, useCallback, Fragment, useEffect, useImperativeHandle } from 'react';
|
|
3
3
|
import { convertMsFromDuration } from '@winglet/common-utils/convert';
|
|
4
|
-
import { useConstant, useSnapshot, useReference, useOnMountLayout, useHandle, useVersion, useOnMount } from '@winglet/react-utils/hook';
|
|
4
|
+
import { useConstant, useSnapshot, useReference, useOnMountLayout, useHandle, useVersion, useOnMount, useOnUnmount } from '@winglet/react-utils/hook';
|
|
5
5
|
import { polynomialHash } from '@winglet/common-utils/hash';
|
|
6
6
|
import { getRandomString, counterFactory } from '@winglet/common-utils/lib';
|
|
7
7
|
import { styleManagerFactory, destroyScope } from '@winglet/style-utils/style-manager';
|
|
8
8
|
import { compressCss, cxLite } from '@winglet/style-utils/util';
|
|
9
|
+
import { isPlainObject, isString, isFunction } from '@winglet/common-utils/filter';
|
|
9
10
|
import { createPortal } from 'react-dom';
|
|
10
11
|
import { map } from '@winglet/common-utils/array';
|
|
11
12
|
import { withErrorBoundary } from '@winglet/react-utils/hoc';
|
|
12
|
-
import { isString, isFunction } from '@winglet/common-utils/filter';
|
|
13
13
|
import { renderComponent } from '@winglet/react-utils/render';
|
|
14
14
|
|
|
15
15
|
class ModalManager {
|
|
16
16
|
static #anchor = null;
|
|
17
17
|
static #scope = `promise-modal-${getRandomString(36)}`;
|
|
18
18
|
static #hash = polynomialHash(ModalManager.#scope);
|
|
19
|
+
static #styleManager = styleManagerFactory(ModalManager.#scope);
|
|
20
|
+
static #styleSheetDefinition = new Map();
|
|
19
21
|
static anchor(options) {
|
|
20
22
|
if (ModalManager.#anchor !== null)
|
|
21
23
|
return ModalManager.#anchor;
|
|
@@ -34,13 +36,20 @@ class ModalManager {
|
|
|
34
36
|
static get prerender() {
|
|
35
37
|
return ModalManager.#prerenderList;
|
|
36
38
|
}
|
|
37
|
-
static #openHandler = (modal) =>
|
|
39
|
+
static #openHandler = ((modal) => {
|
|
40
|
+
ModalManager.#prerenderList.push(modal);
|
|
41
|
+
});
|
|
38
42
|
static set openHandler(handler) {
|
|
39
43
|
ModalManager.#openHandler = handler;
|
|
40
44
|
ModalManager.#prerenderList = [];
|
|
41
45
|
}
|
|
42
|
-
static #
|
|
43
|
-
static
|
|
46
|
+
static #refreshHandler;
|
|
47
|
+
static set refreshHandler(handler) {
|
|
48
|
+
ModalManager.#refreshHandler = handler;
|
|
49
|
+
}
|
|
50
|
+
static refresh() {
|
|
51
|
+
ModalManager.#refreshHandler?.();
|
|
52
|
+
}
|
|
44
53
|
static defineStyleSheet(styleId, css) {
|
|
45
54
|
ModalManager.#styleSheetDefinition.set(styleId, compressCss(css));
|
|
46
55
|
}
|
|
@@ -54,95 +63,113 @@ class ModalManager {
|
|
|
54
63
|
static reset() {
|
|
55
64
|
ModalManager.#anchor = null;
|
|
56
65
|
ModalManager.#prerenderList = [];
|
|
57
|
-
ModalManager.#openHandler = (modal) =>
|
|
66
|
+
ModalManager.#openHandler = ((modal) => {
|
|
67
|
+
ModalManager.#prerenderList.push(modal);
|
|
68
|
+
});
|
|
69
|
+
ModalManager.#refreshHandler = undefined;
|
|
58
70
|
destroyScope(ModalManager.#scope);
|
|
59
71
|
}
|
|
60
72
|
static open(modal) {
|
|
61
|
-
ModalManager.#openHandler(modal);
|
|
73
|
+
return ModalManager.#openHandler(modal);
|
|
62
74
|
}
|
|
63
75
|
}
|
|
64
76
|
|
|
65
|
-
const
|
|
66
|
-
|
|
77
|
+
const closeModal = (modalNode, refresh = true) => {
|
|
78
|
+
if (modalNode.visible === false)
|
|
79
|
+
return;
|
|
80
|
+
modalNode.onClose();
|
|
81
|
+
modalNode.onHide();
|
|
82
|
+
if (refresh)
|
|
83
|
+
ModalManager.refresh();
|
|
84
|
+
if (modalNode.manualDestroy || modalNode.alive === false)
|
|
85
|
+
return;
|
|
86
|
+
return setTimeout(() => modalNode.onDestroy(), modalNode.duration);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const subscribeAbortSignal = (modalNode, signal) => {
|
|
90
|
+
if (signal === undefined)
|
|
91
|
+
return null;
|
|
92
|
+
const handleAbort = () => closeModal(modalNode);
|
|
93
|
+
signal.addEventListener('abort', handleAbort, { once: true });
|
|
94
|
+
return () => signal.removeEventListener('abort', handleAbort);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const alertHandler = (args) => {
|
|
98
|
+
const modalNode = ModalManager.open({
|
|
99
|
+
...args,
|
|
100
|
+
type: 'alert',
|
|
101
|
+
});
|
|
102
|
+
const unsubscribe = subscribeAbortSignal(modalNode, args.signal);
|
|
103
|
+
const promiseHandler = new Promise((resolve, reject) => {
|
|
67
104
|
try {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
subtitle,
|
|
75
|
-
content,
|
|
76
|
-
background,
|
|
77
|
-
footer,
|
|
78
|
-
dimmed,
|
|
79
|
-
manualDestroy,
|
|
80
|
-
closeOnBackdropClick,
|
|
81
|
-
ForegroundComponent,
|
|
82
|
-
BackgroundComponent,
|
|
83
|
-
});
|
|
105
|
+
modalNode.handleResolve = () => {
|
|
106
|
+
unsubscribe?.();
|
|
107
|
+
resolve();
|
|
108
|
+
};
|
|
109
|
+
if (args.signal?.aborted)
|
|
110
|
+
closeModal(modalNode);
|
|
84
111
|
}
|
|
85
112
|
catch (error) {
|
|
113
|
+
closeModal(modalNode);
|
|
114
|
+
unsubscribe?.();
|
|
86
115
|
reject(error);
|
|
87
116
|
}
|
|
88
117
|
});
|
|
118
|
+
return { modalNode, promiseHandler };
|
|
89
119
|
};
|
|
90
120
|
|
|
91
|
-
const
|
|
92
|
-
|
|
121
|
+
const confirmHandler = (args) => {
|
|
122
|
+
const modalNode = ModalManager.open({
|
|
123
|
+
...args,
|
|
124
|
+
type: 'confirm',
|
|
125
|
+
});
|
|
126
|
+
const unsubscribe = subscribeAbortSignal(modalNode, args.signal);
|
|
127
|
+
const promiseHandler = new Promise((resolve, reject) => {
|
|
93
128
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
subtitle,
|
|
101
|
-
content,
|
|
102
|
-
background,
|
|
103
|
-
footer,
|
|
104
|
-
dimmed,
|
|
105
|
-
manualDestroy,
|
|
106
|
-
closeOnBackdropClick,
|
|
107
|
-
ForegroundComponent,
|
|
108
|
-
BackgroundComponent,
|
|
109
|
-
});
|
|
129
|
+
modalNode.handleResolve = (result) => {
|
|
130
|
+
unsubscribe?.();
|
|
131
|
+
resolve(result ?? false);
|
|
132
|
+
};
|
|
133
|
+
if (args.signal?.aborted)
|
|
134
|
+
closeModal(modalNode);
|
|
110
135
|
}
|
|
111
136
|
catch (error) {
|
|
137
|
+
closeModal(modalNode);
|
|
138
|
+
unsubscribe?.();
|
|
112
139
|
reject(error);
|
|
113
140
|
}
|
|
114
141
|
});
|
|
142
|
+
return { modalNode, promiseHandler };
|
|
115
143
|
};
|
|
116
144
|
|
|
117
|
-
const
|
|
118
|
-
|
|
145
|
+
const promptHandler = (args) => {
|
|
146
|
+
const modalNode = ModalManager.open({
|
|
147
|
+
...args,
|
|
148
|
+
type: 'prompt',
|
|
149
|
+
});
|
|
150
|
+
const unsubscribe = subscribeAbortSignal(modalNode, args.signal);
|
|
151
|
+
const promiseHandler = new Promise((resolve, reject) => {
|
|
119
152
|
try {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
content,
|
|
127
|
-
Input,
|
|
128
|
-
defaultValue,
|
|
129
|
-
disabled,
|
|
130
|
-
returnOnCancel,
|
|
131
|
-
background,
|
|
132
|
-
footer,
|
|
133
|
-
dimmed,
|
|
134
|
-
manualDestroy,
|
|
135
|
-
closeOnBackdropClick,
|
|
136
|
-
ForegroundComponent,
|
|
137
|
-
BackgroundComponent,
|
|
138
|
-
});
|
|
153
|
+
modalNode.handleResolve = (result) => {
|
|
154
|
+
unsubscribe?.();
|
|
155
|
+
resolve(result);
|
|
156
|
+
};
|
|
157
|
+
if (args.signal?.aborted)
|
|
158
|
+
closeModal(modalNode);
|
|
139
159
|
}
|
|
140
160
|
catch (error) {
|
|
161
|
+
closeModal(modalNode);
|
|
162
|
+
unsubscribe?.();
|
|
141
163
|
reject(error);
|
|
142
164
|
}
|
|
143
165
|
});
|
|
166
|
+
return { modalNode, promiseHandler };
|
|
144
167
|
};
|
|
145
168
|
|
|
169
|
+
const alert = (args) => alertHandler(args).promiseHandler;
|
|
170
|
+
const confirm = (args) => confirmHandler(args).promiseHandler;
|
|
171
|
+
const prompt = (args) => promptHandler(args).promiseHandler;
|
|
172
|
+
|
|
146
173
|
class AbstractNode {
|
|
147
174
|
id;
|
|
148
175
|
group;
|
|
@@ -150,9 +177,10 @@ class AbstractNode {
|
|
|
150
177
|
title;
|
|
151
178
|
subtitle;
|
|
152
179
|
background;
|
|
180
|
+
dimmed;
|
|
181
|
+
duration;
|
|
153
182
|
manualDestroy;
|
|
154
183
|
closeOnBackdropClick;
|
|
155
|
-
dimmed;
|
|
156
184
|
ForegroundComponent;
|
|
157
185
|
BackgroundComponent;
|
|
158
186
|
#alive;
|
|
@@ -163,9 +191,12 @@ class AbstractNode {
|
|
|
163
191
|
get visible() {
|
|
164
192
|
return this.#visible;
|
|
165
193
|
}
|
|
166
|
-
#
|
|
194
|
+
#handleResolve;
|
|
195
|
+
set handleResolve(handleResolve) {
|
|
196
|
+
this.#handleResolve = handleResolve;
|
|
197
|
+
}
|
|
167
198
|
#listeners = new Set();
|
|
168
|
-
constructor({ id, initiator, group, title, subtitle, background, dimmed = true, manualDestroy = false, closeOnBackdropClick = true,
|
|
199
|
+
constructor({ id, initiator, group, title, subtitle, background, dimmed = true, duration = 0, manualDestroy = false, closeOnBackdropClick = true, handleResolve, ForegroundComponent, BackgroundComponent, }) {
|
|
169
200
|
this.id = id;
|
|
170
201
|
this.group = group;
|
|
171
202
|
this.initiator = initiator;
|
|
@@ -173,13 +204,17 @@ class AbstractNode {
|
|
|
173
204
|
this.subtitle = subtitle;
|
|
174
205
|
this.background = background;
|
|
175
206
|
this.dimmed = dimmed;
|
|
207
|
+
this.duration = duration;
|
|
176
208
|
this.manualDestroy = manualDestroy;
|
|
177
209
|
this.closeOnBackdropClick = closeOnBackdropClick;
|
|
178
210
|
this.ForegroundComponent = ForegroundComponent;
|
|
179
211
|
this.BackgroundComponent = BackgroundComponent;
|
|
180
212
|
this.#alive = true;
|
|
181
213
|
this.#visible = true;
|
|
182
|
-
this.#
|
|
214
|
+
this.#handleResolve = handleResolve;
|
|
215
|
+
}
|
|
216
|
+
onResolve(result) {
|
|
217
|
+
this.#handleResolve?.(result);
|
|
183
218
|
}
|
|
184
219
|
subscribe(listener) {
|
|
185
220
|
this.#listeners.add(listener);
|
|
@@ -191,9 +226,6 @@ class AbstractNode {
|
|
|
191
226
|
for (const listener of this.#listeners)
|
|
192
227
|
listener();
|
|
193
228
|
}
|
|
194
|
-
resolve(result) {
|
|
195
|
-
this.#resolve(result);
|
|
196
|
-
}
|
|
197
229
|
onDestroy() {
|
|
198
230
|
const needPublish = this.#alive === true;
|
|
199
231
|
this.#alive = false;
|
|
@@ -219,7 +251,7 @@ class AlertNode extends AbstractNode {
|
|
|
219
251
|
subtype;
|
|
220
252
|
content;
|
|
221
253
|
footer;
|
|
222
|
-
constructor({ id, group, initiator, type, subtype, title, subtitle, content, footer, background, dimmed, manualDestroy, closeOnBackdropClick,
|
|
254
|
+
constructor({ id, group, initiator, type, subtype, title, subtitle, content, footer, background, dimmed, duration, manualDestroy, closeOnBackdropClick, handleResolve, ForegroundComponent, BackgroundComponent, }) {
|
|
223
255
|
super({
|
|
224
256
|
id,
|
|
225
257
|
group,
|
|
@@ -228,9 +260,10 @@ class AlertNode extends AbstractNode {
|
|
|
228
260
|
subtitle,
|
|
229
261
|
background,
|
|
230
262
|
dimmed,
|
|
263
|
+
duration,
|
|
231
264
|
manualDestroy,
|
|
232
265
|
closeOnBackdropClick,
|
|
233
|
-
|
|
266
|
+
handleResolve,
|
|
234
267
|
ForegroundComponent,
|
|
235
268
|
BackgroundComponent,
|
|
236
269
|
});
|
|
@@ -240,10 +273,10 @@ class AlertNode extends AbstractNode {
|
|
|
240
273
|
this.footer = footer;
|
|
241
274
|
}
|
|
242
275
|
onClose() {
|
|
243
|
-
this.
|
|
276
|
+
this.onResolve(null);
|
|
244
277
|
}
|
|
245
278
|
onConfirm() {
|
|
246
|
-
this.
|
|
279
|
+
this.onResolve(null);
|
|
247
280
|
}
|
|
248
281
|
}
|
|
249
282
|
|
|
@@ -252,7 +285,7 @@ class ConfirmNode extends AbstractNode {
|
|
|
252
285
|
subtype;
|
|
253
286
|
content;
|
|
254
287
|
footer;
|
|
255
|
-
constructor({ id, group, initiator, type, subtype, title, subtitle, content, footer, background, dimmed, manualDestroy, closeOnBackdropClick,
|
|
288
|
+
constructor({ id, group, initiator, type, subtype, title, subtitle, content, footer, background, dimmed, duration, manualDestroy, closeOnBackdropClick, handleResolve, ForegroundComponent, BackgroundComponent, }) {
|
|
256
289
|
super({
|
|
257
290
|
id,
|
|
258
291
|
group,
|
|
@@ -261,9 +294,10 @@ class ConfirmNode extends AbstractNode {
|
|
|
261
294
|
subtitle,
|
|
262
295
|
background,
|
|
263
296
|
dimmed,
|
|
297
|
+
duration,
|
|
264
298
|
manualDestroy,
|
|
265
299
|
closeOnBackdropClick,
|
|
266
|
-
|
|
300
|
+
handleResolve,
|
|
267
301
|
ForegroundComponent,
|
|
268
302
|
BackgroundComponent,
|
|
269
303
|
});
|
|
@@ -273,10 +307,10 @@ class ConfirmNode extends AbstractNode {
|
|
|
273
307
|
this.footer = footer;
|
|
274
308
|
}
|
|
275
309
|
onClose() {
|
|
276
|
-
this.
|
|
310
|
+
this.onResolve(false);
|
|
277
311
|
}
|
|
278
312
|
onConfirm() {
|
|
279
|
-
this.
|
|
313
|
+
this.onResolve(true);
|
|
280
314
|
}
|
|
281
315
|
}
|
|
282
316
|
|
|
@@ -289,7 +323,7 @@ class PromptNode extends AbstractNode {
|
|
|
289
323
|
returnOnCancel;
|
|
290
324
|
footer;
|
|
291
325
|
#value;
|
|
292
|
-
constructor({ id, group, initiator, type, title, subtitle, content, defaultValue, Input, disabled, returnOnCancel, footer, background, dimmed, manualDestroy, closeOnBackdropClick,
|
|
326
|
+
constructor({ id, group, initiator, type, title, subtitle, content, defaultValue, Input, disabled, returnOnCancel, footer, background, dimmed, duration, manualDestroy, closeOnBackdropClick, handleResolve, ForegroundComponent, BackgroundComponent, }) {
|
|
293
327
|
super({
|
|
294
328
|
id,
|
|
295
329
|
group,
|
|
@@ -298,9 +332,10 @@ class PromptNode extends AbstractNode {
|
|
|
298
332
|
subtitle,
|
|
299
333
|
background,
|
|
300
334
|
dimmed,
|
|
335
|
+
duration,
|
|
301
336
|
manualDestroy,
|
|
302
337
|
closeOnBackdropClick,
|
|
303
|
-
|
|
338
|
+
handleResolve,
|
|
304
339
|
ForegroundComponent,
|
|
305
340
|
BackgroundComponent,
|
|
306
341
|
});
|
|
@@ -317,13 +352,13 @@ class PromptNode extends AbstractNode {
|
|
|
317
352
|
this.#value = value;
|
|
318
353
|
}
|
|
319
354
|
onConfirm() {
|
|
320
|
-
this.
|
|
355
|
+
this.onResolve(this.#value ?? null);
|
|
321
356
|
}
|
|
322
357
|
onClose() {
|
|
323
358
|
if (this.returnOnCancel)
|
|
324
|
-
this.
|
|
359
|
+
this.onResolve(this.#value ?? null);
|
|
325
360
|
else
|
|
326
|
-
this.
|
|
361
|
+
this.onResolve(null);
|
|
327
362
|
}
|
|
328
363
|
}
|
|
329
364
|
|
|
@@ -362,8 +397,8 @@ const FallbackFooter = ({ confirmLabel, hideConfirm = false, cancelLabel, hideCa
|
|
|
362
397
|
const ModalManagerContext = createContext({});
|
|
363
398
|
|
|
364
399
|
const useModalManagerContext = () => useContext(ModalManagerContext);
|
|
365
|
-
const
|
|
366
|
-
const { getModal } =
|
|
400
|
+
const useModalManager = (id) => {
|
|
401
|
+
const { getModal } = useContext(ModalManagerContext);
|
|
367
402
|
return useMemo(() => getModal(id), [id, getModal]);
|
|
368
403
|
};
|
|
369
404
|
|
|
@@ -427,20 +462,28 @@ const ConfigurationContextProvider = memo(({ ForegroundComponent, BackgroundComp
|
|
|
427
462
|
FooterComponent: memo(FooterComponent || FallbackFooter),
|
|
428
463
|
});
|
|
429
464
|
const options = useSnapshot(inputOptions);
|
|
430
|
-
const value = useMemo(() =>
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
465
|
+
const value = useMemo(() => {
|
|
466
|
+
const { backdrop: defaultBackdrop, ...defaultOptions } = DEFAULT_OPTIONS;
|
|
467
|
+
const backdrop = getBackdropStyle(options?.backdrop, defaultBackdrop);
|
|
468
|
+
return {
|
|
469
|
+
ForegroundComponent: constant.ForegroundComponent,
|
|
470
|
+
BackgroundComponent: constant.BackgroundComponent,
|
|
471
|
+
TitleComponent: constant.TitleComponent,
|
|
472
|
+
SubtitleComponent: constant.SubtitleComponent,
|
|
473
|
+
ContentComponent: constant.ContentComponent,
|
|
474
|
+
FooterComponent: constant.FooterComponent,
|
|
475
|
+
options: { ...defaultOptions, ...options, backdrop },
|
|
476
|
+
};
|
|
477
|
+
}, [constant, options]);
|
|
442
478
|
return (jsx(ConfigurationContext.Provider, { value: value, children: children }));
|
|
443
479
|
});
|
|
480
|
+
const getBackdropStyle = (backdrop, defaultBackdrop) => {
|
|
481
|
+
if (isPlainObject(backdrop))
|
|
482
|
+
return backdrop;
|
|
483
|
+
if (isString(backdrop))
|
|
484
|
+
return { backgroundColor: backdrop };
|
|
485
|
+
return defaultBackdrop;
|
|
486
|
+
};
|
|
444
487
|
|
|
445
488
|
const useConfigurationContext = () => useContext(ConfigurationContext);
|
|
446
489
|
const useConfigurationOptions = () => {
|
|
@@ -472,32 +515,26 @@ const ModalManagerContextProvider = memo(({ usePathname, children, }) => {
|
|
|
472
515
|
const { manualDestroy, closeOnBackdropClick } = options;
|
|
473
516
|
for (const data of ModalManager.prerender) {
|
|
474
517
|
const modal = nodeFactory({
|
|
518
|
+
duration,
|
|
519
|
+
manualDestroy,
|
|
520
|
+
closeOnBackdropClick,
|
|
475
521
|
...data,
|
|
476
522
|
id: modalIdSequence.current++,
|
|
477
523
|
initiator: initiator.current,
|
|
478
|
-
manualDestroy: data.manualDestroy !== undefined
|
|
479
|
-
? data.manualDestroy
|
|
480
|
-
: manualDestroy,
|
|
481
|
-
closeOnBackdropClick: data.closeOnBackdropClick !== undefined
|
|
482
|
-
? data.closeOnBackdropClick
|
|
483
|
-
: closeOnBackdropClick,
|
|
484
524
|
});
|
|
485
525
|
modalDictionary.current.set(modal.id, modal);
|
|
486
526
|
setModalIds((ids) => [...ids, modal.id]);
|
|
487
527
|
}
|
|
488
528
|
ModalManager.openHandler = (data) => {
|
|
489
|
-
const
|
|
529
|
+
const modalNode = nodeFactory({
|
|
530
|
+
duration,
|
|
531
|
+
manualDestroy,
|
|
532
|
+
closeOnBackdropClick,
|
|
490
533
|
...data,
|
|
491
534
|
id: modalIdSequence.current++,
|
|
492
535
|
initiator: initiator.current,
|
|
493
|
-
manualDestroy: data.manualDestroy !== undefined
|
|
494
|
-
? data.manualDestroy
|
|
495
|
-
: manualDestroy,
|
|
496
|
-
closeOnBackdropClick: data.closeOnBackdropClick !== undefined
|
|
497
|
-
? data.closeOnBackdropClick
|
|
498
|
-
: closeOnBackdropClick,
|
|
499
536
|
});
|
|
500
|
-
modalDictionary.current.set(
|
|
537
|
+
modalDictionary.current.set(modalNode.id, modalNode);
|
|
501
538
|
setModalIds((ids) => {
|
|
502
539
|
const aliveIds = [];
|
|
503
540
|
for (let i = 0, l = ids.length; i < l; i++) {
|
|
@@ -508,8 +545,9 @@ const ModalManagerContextProvider = memo(({ usePathname, children, }) => {
|
|
|
508
545
|
else
|
|
509
546
|
aliveIds.push(id);
|
|
510
547
|
}
|
|
511
|
-
return [...aliveIds,
|
|
548
|
+
return [...aliveIds, modalNode.id];
|
|
512
549
|
});
|
|
550
|
+
return modalNode;
|
|
513
551
|
};
|
|
514
552
|
});
|
|
515
553
|
useLayoutEffect(() => {
|
|
@@ -524,78 +562,62 @@ const ModalManagerContextProvider = memo(({ usePathname, children, }) => {
|
|
|
524
562
|
}
|
|
525
563
|
initiator.current = pathname;
|
|
526
564
|
}, [pathname]);
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
}, []);
|
|
530
|
-
const onDestroy = useCallback((modalId) => {
|
|
565
|
+
const getModalNodeRef = useRef((modalId) => modalDictionary.current.get(modalId));
|
|
566
|
+
const onDestroyRef = useRef((modalId) => {
|
|
531
567
|
const modal = modalDictionary.current.get(modalId);
|
|
532
568
|
if (!modal)
|
|
533
569
|
return;
|
|
534
570
|
modal.onDestroy();
|
|
535
|
-
|
|
536
|
-
}
|
|
537
|
-
const
|
|
538
|
-
const hideModal = useCallback((modalId) => {
|
|
571
|
+
ModalManager.refresh();
|
|
572
|
+
});
|
|
573
|
+
const hideModalRef = useRef((modalId) => {
|
|
539
574
|
const modal = modalDictionary.current.get(modalId);
|
|
540
575
|
if (!modal)
|
|
541
576
|
return;
|
|
542
577
|
modal.onHide();
|
|
543
|
-
|
|
544
|
-
if (
|
|
545
|
-
setTimeout(() =>
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
}, [duration]);
|
|
549
|
-
const onChange = useCallback((modalId, value) => {
|
|
578
|
+
ModalManager.refresh();
|
|
579
|
+
if (modal.manualDestroy === false)
|
|
580
|
+
setTimeout(() => modal.onDestroy(), modal.duration);
|
|
581
|
+
});
|
|
582
|
+
const onChangeRef = useRef((modalId, value) => {
|
|
550
583
|
const modal = modalDictionary.current.get(modalId);
|
|
551
584
|
if (!modal)
|
|
552
585
|
return;
|
|
553
586
|
if (modal.type === 'prompt')
|
|
554
587
|
modal.onChange(value);
|
|
555
|
-
}
|
|
556
|
-
const
|
|
588
|
+
});
|
|
589
|
+
const onConfirmRef = useRef((modalId) => {
|
|
557
590
|
const modal = modalDictionary.current.get(modalId);
|
|
558
591
|
if (!modal)
|
|
559
592
|
return;
|
|
560
593
|
modal.onConfirm();
|
|
561
|
-
|
|
562
|
-
}
|
|
563
|
-
const
|
|
594
|
+
hideModalRef.current(modalId);
|
|
595
|
+
});
|
|
596
|
+
const onCloseRef = useRef((modalId) => {
|
|
564
597
|
const modal = modalDictionary.current.get(modalId);
|
|
565
598
|
if (!modal)
|
|
566
599
|
return;
|
|
567
600
|
modal.onClose();
|
|
568
|
-
|
|
569
|
-
}
|
|
570
|
-
const
|
|
571
|
-
modal:
|
|
572
|
-
onConfirm: () =>
|
|
573
|
-
onClose: () =>
|
|
574
|
-
onChange: (value) =>
|
|
575
|
-
onDestroy: () =>
|
|
576
|
-
})
|
|
601
|
+
hideModalRef.current(modalId);
|
|
602
|
+
});
|
|
603
|
+
const getModalRef = useRef((modalId) => ({
|
|
604
|
+
modal: getModalNodeRef.current(modalId),
|
|
605
|
+
onConfirm: () => onConfirmRef.current(modalId),
|
|
606
|
+
onClose: () => onCloseRef.current(modalId),
|
|
607
|
+
onChange: (value) => onChangeRef.current(modalId, value),
|
|
608
|
+
onDestroy: () => onDestroyRef.current(modalId),
|
|
609
|
+
}));
|
|
577
610
|
const value = useMemo(() => {
|
|
578
611
|
return {
|
|
579
612
|
modalIds,
|
|
580
|
-
getModalNode,
|
|
581
|
-
onChange,
|
|
582
|
-
onConfirm,
|
|
583
|
-
onClose,
|
|
584
|
-
onDestroy,
|
|
585
|
-
getModal,
|
|
586
|
-
setUpdater: (updater) => {
|
|
587
|
-
updaterRef.current = updater;
|
|
588
|
-
},
|
|
613
|
+
getModalNode: getModalNodeRef.current,
|
|
614
|
+
onChange: onChangeRef.current,
|
|
615
|
+
onConfirm: onConfirmRef.current,
|
|
616
|
+
onClose: onCloseRef.current,
|
|
617
|
+
onDestroy: onDestroyRef.current,
|
|
618
|
+
getModal: getModalRef.current,
|
|
589
619
|
};
|
|
590
|
-
}, [
|
|
591
|
-
modalIds,
|
|
592
|
-
getModal,
|
|
593
|
-
getModalNode,
|
|
594
|
-
onChange,
|
|
595
|
-
onConfirm,
|
|
596
|
-
onClose,
|
|
597
|
-
onDestroy,
|
|
598
|
-
]);
|
|
620
|
+
}, [modalIds]);
|
|
599
621
|
return (jsx(ModalManagerContext.Provider, { value: value, children: children }));
|
|
600
622
|
});
|
|
601
623
|
|
|
@@ -664,7 +686,7 @@ ModalManager.defineStyleSheet('background', style$3);
|
|
|
664
686
|
const BackgroundFrame = ({ modalId, onChangeOrder, }) => {
|
|
665
687
|
const { BackgroundComponent } = useConfigurationContext();
|
|
666
688
|
const { context: userDefinedContext } = useUserDefinedContext();
|
|
667
|
-
const { modal, onClose, onChange, onConfirm, onDestroy } =
|
|
689
|
+
const { modal, onClose, onChange, onConfirm, onDestroy } = useModalManager(modalId);
|
|
668
690
|
const handleClose = useCallback((event) => {
|
|
669
691
|
if (modal && modal.closeOnBackdropClick && modal.visible)
|
|
670
692
|
onClose();
|
|
@@ -780,7 +802,7 @@ ModalManager.defineStyleSheet('foreground', style$2);
|
|
|
780
802
|
const ForegroundFrame = ({ modalId, onChangeOrder, }) => {
|
|
781
803
|
const { ForegroundComponent } = useConfigurationContext();
|
|
782
804
|
const { context: userDefinedContext } = useUserDefinedContext();
|
|
783
|
-
const { modal, onChange, onConfirm, onClose, onDestroy } =
|
|
805
|
+
const { modal, onChange, onConfirm, onClose, onDestroy } = useModalManager(modalId);
|
|
784
806
|
const Foreground = useMemo(() => modal?.ForegroundComponent || ForegroundComponent, [ForegroundComponent, modal]);
|
|
785
807
|
if (!modal)
|
|
786
808
|
return null;
|
|
@@ -812,7 +834,7 @@ ModalManager.defineStyleSheet('presenter', style$1);
|
|
|
812
834
|
const Presenter = memo(({ modalId, getValue, increment }) => {
|
|
813
835
|
const ref = useRef(null);
|
|
814
836
|
const options = useConfigurationOptions();
|
|
815
|
-
const { modal } =
|
|
837
|
+
const { modal } = useModalManager(modalId);
|
|
816
838
|
useSubscribeModal(modal);
|
|
817
839
|
useOnMountLayout(() => {
|
|
818
840
|
if (ref.current === null)
|
|
@@ -840,27 +862,41 @@ const style = `
|
|
|
840
862
|
inset: 0;
|
|
841
863
|
pointer-events: none;
|
|
842
864
|
z-index: var(--z-index);
|
|
843
|
-
|
|
865
|
+
}`;
|
|
866
|
+
const backdrop = ModalManager.getHashedClassNames('backdrop');
|
|
867
|
+
const backdropStyle = `
|
|
868
|
+
.${backdrop} {
|
|
869
|
+
position: fixed;
|
|
870
|
+
inset: 0;
|
|
871
|
+
opacity: 0;
|
|
872
|
+
transition-property: opacity;
|
|
873
|
+
transition-duration: var(--transition-duration);
|
|
874
|
+
transition-timing-function: ease-in-out;
|
|
875
|
+
pointer-events: none;
|
|
844
876
|
}`;
|
|
845
877
|
ModalManager.defineStyleSheet('anchor', style);
|
|
878
|
+
ModalManager.defineStyleSheet('backdrop', backdropStyle);
|
|
846
879
|
|
|
847
880
|
const { getValue, increment, reset } = counterFactory(0);
|
|
848
881
|
const AnchorInner = () => {
|
|
849
882
|
const [version, update] = useVersion();
|
|
850
|
-
const { modalIds
|
|
883
|
+
const { modalIds } = useModalManagerContext();
|
|
851
884
|
useEffect(() => {
|
|
852
|
-
|
|
853
|
-
}, [
|
|
885
|
+
ModalManager.refreshHandler = update;
|
|
886
|
+
}, [update]);
|
|
854
887
|
const options = useConfigurationOptions();
|
|
855
888
|
const dimmed = useActiveModalCount(validateDimmable, version);
|
|
856
889
|
if (!dimmed)
|
|
857
890
|
reset();
|
|
858
|
-
const
|
|
859
|
-
...(dimmed ? options.backdrop : {}),
|
|
891
|
+
const anchorStyle = useMemo(() => ({
|
|
860
892
|
'--z-index': options.zIndex,
|
|
861
|
-
|
|
893
|
+
'--transition-duration': options.duration,
|
|
894
|
+
}), [options]);
|
|
895
|
+
const backdropStyle = useMemo(() => ({
|
|
896
|
+
...options.backdrop,
|
|
897
|
+
opacity: dimmed ? 1 : 0,
|
|
862
898
|
}), [dimmed, options]);
|
|
863
|
-
return (
|
|
899
|
+
return (jsxs("div", { className: anchor, style: anchorStyle, children: [jsx("div", { className: backdrop, style: backdropStyle }), map(modalIds, (id) => (jsx(Presenter, { modalId: id, getValue: getValue, increment: increment, reset: reset }, id)))] }));
|
|
864
900
|
};
|
|
865
901
|
const validateDimmable = (modal) => modal?.visible && modal.dimmed;
|
|
866
902
|
const Anchor = memo(withErrorBoundary(AnchorInner));
|
|
@@ -947,8 +983,38 @@ const useBootstrap = ({ usePathname: useExternalPathname, ForegroundComponent, B
|
|
|
947
983
|
return { portal, initialize };
|
|
948
984
|
};
|
|
949
985
|
|
|
986
|
+
const useModal = () => {
|
|
987
|
+
const modalNodesRef = useRef([]);
|
|
988
|
+
const alertRef = useRef((args) => {
|
|
989
|
+
const { modalNode, promiseHandler } = alertHandler(args);
|
|
990
|
+
modalNodesRef.current.push(modalNode);
|
|
991
|
+
return promiseHandler;
|
|
992
|
+
});
|
|
993
|
+
const confirmRef = useRef((args) => {
|
|
994
|
+
const { modalNode, promiseHandler } = confirmHandler(args);
|
|
995
|
+
modalNodesRef.current.push(modalNode);
|
|
996
|
+
return promiseHandler;
|
|
997
|
+
});
|
|
998
|
+
const promptRef = useRef((args) => {
|
|
999
|
+
const { modalNode, promiseHandler } = promptHandler(args);
|
|
1000
|
+
modalNodesRef.current.push(modalNode);
|
|
1001
|
+
return promiseHandler;
|
|
1002
|
+
});
|
|
1003
|
+
useOnUnmount(() => {
|
|
1004
|
+
for (const node of modalNodesRef.current)
|
|
1005
|
+
closeModal(node, false);
|
|
1006
|
+
ModalManager.refresh();
|
|
1007
|
+
modalNodesRef.current = [];
|
|
1008
|
+
});
|
|
1009
|
+
return {
|
|
1010
|
+
alert: alertRef.current,
|
|
1011
|
+
confirm: confirmRef.current,
|
|
1012
|
+
prompt: promptRef.current,
|
|
1013
|
+
};
|
|
1014
|
+
};
|
|
1015
|
+
|
|
950
1016
|
const useDestroyAfter = (modalId, duration) => {
|
|
951
|
-
const { modal, onDestroy } =
|
|
1017
|
+
const { modal, onDestroy } = useModalManager(modalId);
|
|
952
1018
|
const tick = useSubscribeModal(modal);
|
|
953
1019
|
const reference = useRef({
|
|
954
1020
|
modal,
|
|
@@ -989,4 +1055,4 @@ const useModalAnimation = (visible, handler) => {
|
|
|
989
1055
|
}, [visible]);
|
|
990
1056
|
};
|
|
991
1057
|
|
|
992
|
-
export { BootstrapProvider as ModalProvider, alert, confirm, prompt, useActiveModalCount, useDestroyAfter, useBootstrap as useInitializeModal, useModalAnimation, useConfigurationBackdrop as useModalBackdrop, useConfigurationDuration as useModalDuration, useConfigurationOptions as useModalOptions, useSubscribeModal };
|
|
1058
|
+
export { BootstrapProvider as ModalProvider, alert, confirm, prompt, useActiveModalCount, useDestroyAfter, useBootstrap as useInitializeModal, useModal, useModalAnimation, useConfigurationBackdrop as useModalBackdrop, useConfigurationDuration as useModalDuration, useConfigurationOptions as useModalOptions, useSubscribeModal };
|