@okyrychenko-dev/react-modal-manager 0.1.0 → 0.2.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/CHANGELOG.md +32 -0
- package/README.md +143 -49
- package/dist/index.cjs +234 -275
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -6
- package/dist/index.d.ts +8 -6
- package/dist/index.js +235 -276
- package/dist/index.js.map +1 -1
- package/package.json +43 -28
package/dist/index.cjs
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var typeUtils = require('@okyrychenko-dev/type-utils');
|
|
3
4
|
var react = require('react');
|
|
4
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
-
var zustand = require('zustand');
|
|
6
|
-
var vanilla = require('zustand/vanilla');
|
|
7
6
|
|
|
8
7
|
// src/registry/createModal.ts
|
|
9
8
|
function createGeneratedModalId() {
|
|
@@ -16,73 +15,56 @@ function createModal(options) {
|
|
|
16
15
|
};
|
|
17
16
|
return {
|
|
18
17
|
...definition,
|
|
19
|
-
open: (manager,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// src/registry/createModalController.constants.ts
|
|
24
|
-
var MODAL_CONTROLLER_UNBOUND_ERROR = "Modal registry is not bound to a mounted ModalProvider";
|
|
25
|
-
|
|
26
|
-
// src/registry/createModalController.ts
|
|
27
|
-
function createModalController() {
|
|
28
|
-
const managerStack = [];
|
|
29
|
-
const getActiveManager = () => {
|
|
30
|
-
if (managerStack.length === 0) {
|
|
31
|
-
throw new Error(MODAL_CONTROLLER_UNBOUND_ERROR);
|
|
32
|
-
}
|
|
33
|
-
return managerStack[managerStack.length - 1];
|
|
34
|
-
};
|
|
35
|
-
return {
|
|
36
|
-
bind: (manager) => {
|
|
37
|
-
managerStack.push(manager);
|
|
38
|
-
return () => {
|
|
39
|
-
const managerIndex = managerStack.lastIndexOf(manager);
|
|
40
|
-
if (managerIndex >= 0) {
|
|
41
|
-
managerStack.splice(managerIndex, 1);
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
},
|
|
45
|
-
closeAll: (reason) => {
|
|
46
|
-
getActiveManager().closeAll(reason);
|
|
47
|
-
},
|
|
48
|
-
confirm: (params) => getActiveManager().confirm(params),
|
|
49
|
-
dismiss: (instanceId, reason) => {
|
|
50
|
-
getActiveManager().dismiss(instanceId, reason);
|
|
51
|
-
},
|
|
52
|
-
isReady: () => managerStack.length > 0,
|
|
53
|
-
open: (modal, input) => getActiveManager().open(modal, input)
|
|
18
|
+
open: (manager, ...args) => manager.open(definition, ...args)
|
|
54
19
|
};
|
|
55
20
|
}
|
|
56
21
|
|
|
57
22
|
// src/registry/createModalRegistry.constants.ts
|
|
58
23
|
var MODAL_REGISTRY_UNKNOWN_KEY_ERROR = "Modal registry does not contain modal";
|
|
24
|
+
var MODAL_CONTROLLER_UNBOUND_ERROR = "Modal registry is not bound to a mounted ModalProvider";
|
|
59
25
|
|
|
60
|
-
// src/registry/
|
|
61
|
-
var
|
|
62
|
-
function
|
|
63
|
-
|
|
26
|
+
// src/registry/createModalRegistry.ts
|
|
27
|
+
var MODAL_REGISTRY_ATTACH = /* @__PURE__ */ Symbol("modal-registry-attach");
|
|
28
|
+
function isModalRegistryAttachable(value) {
|
|
29
|
+
return typeUtils.isObject(value) && typeUtils.isFunction(value[MODAL_REGISTRY_ATTACH]);
|
|
64
30
|
}
|
|
65
|
-
function
|
|
66
|
-
return
|
|
31
|
+
function attachModalRegistry(registry, manager) {
|
|
32
|
+
return registry[MODAL_REGISTRY_ATTACH](manager);
|
|
67
33
|
}
|
|
68
|
-
|
|
69
|
-
// src/registry/createModalRegistry.ts
|
|
70
34
|
function createModalRegistry(definitions) {
|
|
71
|
-
|
|
35
|
+
let attachments = [];
|
|
36
|
+
const activeManager = () => {
|
|
37
|
+
typeUtils.assertTrue(typeUtils.isNonEmptyArray(attachments), MODAL_CONTROLLER_UNBOUND_ERROR);
|
|
38
|
+
return attachments[attachments.length - 1].manager;
|
|
39
|
+
};
|
|
40
|
+
const attach = (manager) => {
|
|
41
|
+
const attachment = { manager };
|
|
42
|
+
attachments.push(attachment);
|
|
43
|
+
return () => {
|
|
44
|
+
attachments = attachments.filter((candidate) => candidate !== attachment);
|
|
45
|
+
};
|
|
46
|
+
};
|
|
72
47
|
function open(key, input) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
48
|
+
typeUtils.assertTrue(
|
|
49
|
+
typeUtils.hasProperty(definitions, key),
|
|
50
|
+
() => `${MODAL_REGISTRY_UNKNOWN_KEY_ERROR}: ${key}`
|
|
51
|
+
);
|
|
52
|
+
return definitions[key].open(activeManager(), input);
|
|
77
53
|
}
|
|
78
54
|
const registry = {
|
|
79
|
-
closeAll:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
55
|
+
closeAll: (reason) => {
|
|
56
|
+
activeManager().closeAll(reason);
|
|
57
|
+
},
|
|
58
|
+
confirm: (params) => {
|
|
59
|
+
return activeManager().confirm(params);
|
|
60
|
+
},
|
|
61
|
+
dismiss: (instanceId, reason) => {
|
|
62
|
+
activeManager().dismiss(instanceId, reason);
|
|
63
|
+
},
|
|
64
|
+
isReady: () => typeUtils.isNonEmptyArray(attachments),
|
|
65
|
+
open,
|
|
66
|
+
[MODAL_REGISTRY_ATTACH]: attach
|
|
84
67
|
};
|
|
85
|
-
bindModalRegistry(registry, controller);
|
|
86
68
|
return registry;
|
|
87
69
|
}
|
|
88
70
|
|
|
@@ -110,7 +92,7 @@ function ConfirmModal(props) {
|
|
|
110
92
|
const confirmText = input.confirmText ?? DEFAULT_CONFIRM_TEXT;
|
|
111
93
|
const variant = input.variant ?? "default";
|
|
112
94
|
const dismissible = input.dismissible !== false;
|
|
113
|
-
const hasDescription = input.description
|
|
95
|
+
const hasDescription = typeUtils.isDefined(input.description);
|
|
114
96
|
const titleId = react.useId();
|
|
115
97
|
const descriptionId = react.useId();
|
|
116
98
|
const dialogRef = react.useRef(null);
|
|
@@ -124,7 +106,7 @@ function ConfirmModal(props) {
|
|
|
124
106
|
}
|
|
125
107
|
initialFocusRef.current?.focus();
|
|
126
108
|
return () => {
|
|
127
|
-
if (previouslyFocused
|
|
109
|
+
if (typeUtils.isInstanceOf(previouslyFocused, HTMLElement)) {
|
|
128
110
|
previouslyFocused.focus();
|
|
129
111
|
}
|
|
130
112
|
};
|
|
@@ -146,11 +128,11 @@ function ConfirmModal(props) {
|
|
|
146
128
|
handleDismiss();
|
|
147
129
|
};
|
|
148
130
|
const handleTab = (event) => {
|
|
149
|
-
if (dialogRef.current
|
|
131
|
+
if (!typeUtils.isDefined(dialogRef.current)) {
|
|
150
132
|
return;
|
|
151
133
|
}
|
|
152
134
|
const focusable = getFocusableElements(dialogRef.current);
|
|
153
|
-
if (focusable
|
|
135
|
+
if (!typeUtils.isNonEmptyArray(focusable)) {
|
|
154
136
|
return;
|
|
155
137
|
}
|
|
156
138
|
const first = focusable[0];
|
|
@@ -225,117 +207,173 @@ var ModalRejectError = class extends Error {
|
|
|
225
207
|
this.value = value;
|
|
226
208
|
}
|
|
227
209
|
};
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
210
|
+
function createModalLifecycle(options) {
|
|
211
|
+
let nextInstanceIndex = 0;
|
|
212
|
+
let instances = [];
|
|
213
|
+
let disposed = false;
|
|
214
|
+
let closeDelayMs = options.closeDelayMs;
|
|
215
|
+
const serverSnapshot = { instances: [] };
|
|
216
|
+
let snapshot = serverSnapshot;
|
|
217
|
+
const observers = /* @__PURE__ */ new Set();
|
|
218
|
+
const removalTimers = /* @__PURE__ */ new Map();
|
|
219
|
+
const dismissers = /* @__PURE__ */ new Map();
|
|
220
|
+
const notifyObservers = () => {
|
|
221
|
+
for (const observer of observers) {
|
|
222
|
+
observer();
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const publishState = () => {
|
|
226
|
+
if (disposed) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
snapshot = { instances: [...instances] };
|
|
230
|
+
notifyObservers();
|
|
231
|
+
};
|
|
232
|
+
const removeInstance = (instanceId) => {
|
|
233
|
+
const timer = removalTimers.get(instanceId);
|
|
234
|
+
if (typeUtils.isDefined(timer)) {
|
|
235
|
+
globalThis.clearTimeout(timer);
|
|
236
|
+
removalTimers.delete(instanceId);
|
|
237
|
+
}
|
|
238
|
+
dismissers.delete(instanceId);
|
|
239
|
+
instances = instances.filter(
|
|
240
|
+
(candidate) => candidate.instanceId !== instanceId
|
|
241
|
+
);
|
|
242
|
+
publishState();
|
|
243
|
+
};
|
|
244
|
+
const settleInstance = (instanceId, settle) => {
|
|
245
|
+
const instance = instances.find(
|
|
246
|
+
(candidate) => candidate.instanceId === instanceId
|
|
247
|
+
);
|
|
248
|
+
if (!typeUtils.isDefined(instance) || instance.status === "closing") {
|
|
248
249
|
return;
|
|
249
250
|
}
|
|
250
|
-
|
|
251
|
-
|
|
251
|
+
instances = instances.map((candidate) => {
|
|
252
|
+
if (candidate.instanceId === instanceId) {
|
|
253
|
+
return { ...candidate, status: "closing" };
|
|
254
|
+
}
|
|
255
|
+
return candidate;
|
|
256
|
+
});
|
|
257
|
+
publishState();
|
|
258
|
+
settle();
|
|
259
|
+
if (closeDelayMs <= 0) {
|
|
260
|
+
removeInstance(instanceId);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const timer = globalThis.setTimeout(() => {
|
|
264
|
+
removeInstance(instanceId);
|
|
265
|
+
}, closeDelayMs);
|
|
266
|
+
removalTimers.set(instanceId, timer);
|
|
267
|
+
};
|
|
268
|
+
const dismissOpenInstances = (reason) => {
|
|
269
|
+
const openInstanceIds = instances.filter((instance) => instance.status === "open").map((instance) => instance.instanceId);
|
|
270
|
+
for (const instanceId of openInstanceIds) {
|
|
271
|
+
dismissers.get(instanceId)?.(reason);
|
|
272
|
+
}
|
|
252
273
|
};
|
|
253
274
|
return {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
modals: [...state.modals, { ...modal, status: "open" }]
|
|
257
|
-
}));
|
|
258
|
-
},
|
|
259
|
-
allocateInstanceId: () => {
|
|
260
|
-
const { nextInstanceIndex } = get();
|
|
261
|
-
set({ nextInstanceIndex: nextInstanceIndex + 1 });
|
|
262
|
-
return `modal-${String(nextInstanceIndex)}`;
|
|
275
|
+
closeAll: (reason = "close-all") => {
|
|
276
|
+
dismissOpenInstances(reason);
|
|
263
277
|
},
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
278
|
+
dispose: () => {
|
|
279
|
+
if (disposed) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
disposed = true;
|
|
283
|
+
dismissOpenInstances("provider-unmount");
|
|
284
|
+
for (const timer of removalTimers.values()) {
|
|
285
|
+
globalThis.clearTimeout(timer);
|
|
268
286
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
287
|
+
removalTimers.clear();
|
|
288
|
+
dismissers.clear();
|
|
289
|
+
instances = [];
|
|
290
|
+
snapshot = { instances: [] };
|
|
291
|
+
notifyObservers();
|
|
292
|
+
observers.clear();
|
|
275
293
|
},
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
modals: state.modals.map((modal) => {
|
|
279
|
-
if (modal.instanceId === instanceId) {
|
|
280
|
-
return { ...modal, status: "closing" };
|
|
281
|
-
}
|
|
282
|
-
return modal;
|
|
283
|
-
})
|
|
284
|
-
}));
|
|
294
|
+
dismiss: (instanceId, reason) => {
|
|
295
|
+
dismissers.get(instanceId)?.(reason);
|
|
285
296
|
},
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
297
|
+
getSnapshot: () => snapshot,
|
|
298
|
+
getServerSnapshot: () => serverSnapshot,
|
|
299
|
+
open: (modal, ...args) => {
|
|
300
|
+
const input = args[0];
|
|
301
|
+
const instanceId = `modal-${String(nextInstanceIndex)}`;
|
|
302
|
+
nextInstanceIndex += 1;
|
|
303
|
+
if (disposed) {
|
|
304
|
+
const result2 = Promise.reject(
|
|
305
|
+
new ModalDismissError("provider-unmount")
|
|
306
|
+
);
|
|
307
|
+
return Object.assign(result2, {
|
|
308
|
+
dismiss: () => void 0,
|
|
309
|
+
instanceId
|
|
310
|
+
});
|
|
291
311
|
}
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
312
|
+
const result = new Promise((resolve, reject) => {
|
|
313
|
+
const dismiss = (reason = "dismiss") => {
|
|
314
|
+
settleInstance(instanceId, () => {
|
|
315
|
+
reject(new ModalDismissError(reason));
|
|
316
|
+
});
|
|
317
|
+
};
|
|
318
|
+
dismissers.set(instanceId, dismiss);
|
|
319
|
+
const instance = {
|
|
320
|
+
definitionId: modal.id,
|
|
321
|
+
instanceId,
|
|
322
|
+
render: () => react.createElement(modal.component, {
|
|
323
|
+
close: (modalResult) => {
|
|
324
|
+
settleInstance(instanceId, () => {
|
|
325
|
+
resolve(modalResult);
|
|
326
|
+
});
|
|
327
|
+
},
|
|
328
|
+
dismiss,
|
|
329
|
+
input,
|
|
330
|
+
instanceId,
|
|
331
|
+
reject: (error) => {
|
|
332
|
+
settleInstance(instanceId, () => {
|
|
333
|
+
reject(typeUtils.isError(error) ? error : new ModalRejectError(error));
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}),
|
|
337
|
+
status: "open"
|
|
338
|
+
};
|
|
339
|
+
instances = [...instances, instance];
|
|
340
|
+
publishState();
|
|
341
|
+
});
|
|
342
|
+
return Object.assign(result, {
|
|
343
|
+
dismiss: (reason) => {
|
|
344
|
+
dismissers.get(instanceId)?.(reason);
|
|
345
|
+
},
|
|
346
|
+
instanceId
|
|
347
|
+
});
|
|
303
348
|
},
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
set({ modals: [] });
|
|
349
|
+
setCloseDelayMs: (nextCloseDelayMs) => {
|
|
350
|
+
closeDelayMs = nextCloseDelayMs;
|
|
307
351
|
},
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
352
|
+
subscribe: (observer) => {
|
|
353
|
+
if (disposed) {
|
|
354
|
+
return () => void 0;
|
|
311
355
|
}
|
|
312
|
-
|
|
356
|
+
observers.add(observer);
|
|
357
|
+
return () => {
|
|
358
|
+
observers.delete(observer);
|
|
359
|
+
};
|
|
313
360
|
}
|
|
314
361
|
};
|
|
315
362
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
// src/store/modalStore.ts
|
|
324
|
-
function createModalStore() {
|
|
325
|
-
return vanilla.createStore((set, get) => ({
|
|
326
|
-
...MODAL_STORE_DEFAULTS,
|
|
327
|
-
...createModalStoreActions(set, get)
|
|
328
|
-
}));
|
|
363
|
+
var ModalLifecycleContext = react.createContext(void 0);
|
|
364
|
+
function useModalLifecycle() {
|
|
365
|
+
const lifecycle = react.useContext(ModalLifecycleContext);
|
|
366
|
+
typeUtils.assertDefined(lifecycle, "Modal lifecycle must be used within ModalProvider");
|
|
367
|
+
return lifecycle;
|
|
329
368
|
}
|
|
330
|
-
function
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
369
|
+
function useModalLifecycleState() {
|
|
370
|
+
const lifecycle = useModalLifecycle();
|
|
371
|
+
return react.useSyncExternalStore(
|
|
372
|
+
lifecycle.subscribe,
|
|
373
|
+
lifecycle.getSnapshot,
|
|
374
|
+
lifecycle.getServerSnapshot
|
|
375
|
+
);
|
|
335
376
|
}
|
|
336
|
-
|
|
337
|
-
// src/store/modalStore.selectors.ts
|
|
338
|
-
var useModals = () => useModalStore((state) => state.modals);
|
|
339
377
|
var ModalRuntimeConfigContext = react.createContext({
|
|
340
378
|
closeDelayMs: 0,
|
|
341
379
|
confirmModal
|
|
@@ -346,104 +384,22 @@ function useModalRuntimeConfig() {
|
|
|
346
384
|
return react.useContext(ModalRuntimeConfigContext);
|
|
347
385
|
}
|
|
348
386
|
|
|
349
|
-
// src/hooks/useModalManager/useModalManager.
|
|
350
|
-
var DEFAULT_DISMISS_REASON = "dismiss";
|
|
387
|
+
// src/hooks/useModalManager/useModalManager.tsx
|
|
351
388
|
function useModalManager() {
|
|
352
|
-
const
|
|
353
|
-
const {
|
|
354
|
-
const scheduleRemove = react.useCallback(
|
|
355
|
-
(instanceId) => {
|
|
356
|
-
store.getState().scheduleRemove(instanceId, closeDelayMs);
|
|
357
|
-
},
|
|
358
|
-
[closeDelayMs, store]
|
|
359
|
-
);
|
|
360
|
-
const settleInstance = react.useCallback(
|
|
361
|
-
(instanceId, settle) => {
|
|
362
|
-
const instance = store.getState().modals.find((modal) => modal.instanceId === instanceId);
|
|
363
|
-
if (instance === void 0 || instance.status === "closing") {
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
store.getState().markModalClosing(instanceId);
|
|
367
|
-
settle(instance);
|
|
368
|
-
scheduleRemove(instanceId);
|
|
369
|
-
},
|
|
370
|
-
[scheduleRemove, store]
|
|
371
|
-
);
|
|
372
|
-
const dismiss = react.useCallback(
|
|
373
|
-
(instanceId, reason = DEFAULT_DISMISS_REASON) => {
|
|
374
|
-
settleInstance(instanceId, (instance) => {
|
|
375
|
-
instance.dismiss(reason);
|
|
376
|
-
});
|
|
377
|
-
},
|
|
378
|
-
[settleInstance]
|
|
379
|
-
);
|
|
380
|
-
const closeAll = react.useCallback(
|
|
381
|
-
(reason) => {
|
|
382
|
-
const dismissReason = reason ?? "close-all";
|
|
383
|
-
const openInstanceIds = store.getState().modals.filter((modal) => modal.status === "open").map((modal) => modal.instanceId);
|
|
384
|
-
store.getState().dismissAll(dismissReason);
|
|
385
|
-
for (const instanceId of openInstanceIds) {
|
|
386
|
-
scheduleRemove(instanceId);
|
|
387
|
-
}
|
|
388
|
-
},
|
|
389
|
-
[scheduleRemove, store]
|
|
390
|
-
);
|
|
391
|
-
const open = react.useCallback(
|
|
392
|
-
(modal, input) => {
|
|
393
|
-
const storeState = store.getState();
|
|
394
|
-
const instanceId = storeState.allocateInstanceId();
|
|
395
|
-
const result = new Promise((resolve, reject) => {
|
|
396
|
-
const Component = modal.component;
|
|
397
|
-
const handleClose = (modalResult) => {
|
|
398
|
-
settleInstance(instanceId, () => {
|
|
399
|
-
resolve(modalResult);
|
|
400
|
-
});
|
|
401
|
-
};
|
|
402
|
-
const handleDismiss = (reason = DEFAULT_DISMISS_REASON) => {
|
|
403
|
-
settleInstance(instanceId, () => {
|
|
404
|
-
reject(new ModalDismissError(reason));
|
|
405
|
-
});
|
|
406
|
-
};
|
|
407
|
-
const handleReject = (error) => {
|
|
408
|
-
settleInstance(instanceId, () => {
|
|
409
|
-
reject(
|
|
410
|
-
error instanceof Error ? error : new ModalRejectError(error)
|
|
411
|
-
);
|
|
412
|
-
});
|
|
413
|
-
};
|
|
414
|
-
storeState.addModal({
|
|
415
|
-
instanceId,
|
|
416
|
-
status: "open",
|
|
417
|
-
definitionId: modal.id,
|
|
418
|
-
render: () => /* @__PURE__ */ jsxRuntime.jsx(
|
|
419
|
-
Component,
|
|
420
|
-
{
|
|
421
|
-
close: handleClose,
|
|
422
|
-
dismiss: handleDismiss,
|
|
423
|
-
instanceId,
|
|
424
|
-
input,
|
|
425
|
-
reject: handleReject
|
|
426
|
-
}
|
|
427
|
-
),
|
|
428
|
-
dismiss: (reason) => {
|
|
429
|
-
reject(new ModalDismissError(reason));
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
});
|
|
433
|
-
const dismissHandle = (reason) => {
|
|
434
|
-
dismiss(instanceId, reason);
|
|
435
|
-
};
|
|
436
|
-
return Object.assign(result, { dismiss: dismissHandle, instanceId });
|
|
437
|
-
},
|
|
438
|
-
[dismiss, settleInstance, store]
|
|
439
|
-
);
|
|
389
|
+
const lifecycle = useModalLifecycle();
|
|
390
|
+
const { confirmModal: confirmModal2 } = useModalRuntimeConfig();
|
|
440
391
|
const confirm = react.useCallback(
|
|
441
|
-
(params) => open(confirmModal2, params),
|
|
442
|
-
[confirmModal2,
|
|
392
|
+
(params) => lifecycle.open(confirmModal2, params),
|
|
393
|
+
[confirmModal2, lifecycle]
|
|
443
394
|
);
|
|
444
395
|
return react.useMemo(
|
|
445
|
-
() => ({
|
|
446
|
-
|
|
396
|
+
() => ({
|
|
397
|
+
closeAll: lifecycle.closeAll,
|
|
398
|
+
confirm,
|
|
399
|
+
dismiss: lifecycle.dismiss,
|
|
400
|
+
open: lifecycle.open
|
|
401
|
+
}),
|
|
402
|
+
[confirm, lifecycle]
|
|
447
403
|
);
|
|
448
404
|
}
|
|
449
405
|
function DefaultModalRenderer({ children }) {
|
|
@@ -452,7 +408,7 @@ function DefaultModalRenderer({ children }) {
|
|
|
452
408
|
function ModalViewport({
|
|
453
409
|
renderer: Renderer = DefaultModalRenderer
|
|
454
410
|
}) {
|
|
455
|
-
const modals =
|
|
411
|
+
const { instances: modals } = useModalLifecycleState();
|
|
456
412
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: modals.map((modal) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
457
413
|
Renderer,
|
|
458
414
|
{
|
|
@@ -467,32 +423,35 @@ function ModalViewport({
|
|
|
467
423
|
)) });
|
|
468
424
|
}
|
|
469
425
|
function ModalRegistryBinder(props) {
|
|
470
|
-
const {
|
|
426
|
+
const { registry } = props;
|
|
471
427
|
const manager = useModalManager();
|
|
472
428
|
react.useEffect(() => {
|
|
473
|
-
const unbind =
|
|
429
|
+
const unbind = attachModalRegistry(registry, manager);
|
|
474
430
|
return () => {
|
|
475
431
|
unbind();
|
|
476
432
|
};
|
|
477
|
-
}, [
|
|
433
|
+
}, [registry, manager]);
|
|
478
434
|
return null;
|
|
479
435
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
436
|
+
function useModalLifecycleOwner(closeDelayMs) {
|
|
437
|
+
const [lifecycle] = react.useState(() => createModalLifecycle({ closeDelayMs }));
|
|
438
|
+
const mountGeneration = react.useRef(0);
|
|
439
|
+
react.useEffect(() => {
|
|
440
|
+
lifecycle.setCloseDelayMs(closeDelayMs);
|
|
441
|
+
}, [closeDelayMs, lifecycle]);
|
|
442
|
+
react.useEffect(() => {
|
|
443
|
+
mountGeneration.current += 1;
|
|
444
|
+
return () => {
|
|
445
|
+
mountGeneration.current += 1;
|
|
446
|
+
const cleanupGeneration = mountGeneration.current;
|
|
447
|
+
globalThis.queueMicrotask(() => {
|
|
448
|
+
if (mountGeneration.current === cleanupGeneration) {
|
|
449
|
+
lifecycle.dispose();
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
};
|
|
453
|
+
}, [lifecycle]);
|
|
454
|
+
return lifecycle;
|
|
496
455
|
}
|
|
497
456
|
function ModalProvider(props) {
|
|
498
457
|
const {
|
|
@@ -502,9 +461,9 @@ function ModalProvider(props) {
|
|
|
502
461
|
registry,
|
|
503
462
|
renderer
|
|
504
463
|
} = props;
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
464
|
+
if (typeUtils.isDefined(registry)) {
|
|
465
|
+
typeUtils.assertTrue(
|
|
466
|
+
isModalRegistryAttachable(registry),
|
|
508
467
|
"ModalProvider registry must be created by createModalRegistry"
|
|
509
468
|
);
|
|
510
469
|
}
|
|
@@ -512,11 +471,11 @@ function ModalProvider(props) {
|
|
|
512
471
|
() => ({ closeDelayMs, confirmModal: confirmModal2 }),
|
|
513
472
|
[closeDelayMs, confirmModal2]
|
|
514
473
|
);
|
|
515
|
-
|
|
474
|
+
const lifecycle = useModalLifecycleOwner(closeDelayMs);
|
|
475
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ModalLifecycleContext.Provider, { value: lifecycle, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalRuntimeConfigContext.Provider, { value: runtimeConfig, children: [
|
|
516
476
|
children,
|
|
517
|
-
|
|
518
|
-
/* @__PURE__ */ jsxRuntime.jsx(ModalViewport, { renderer })
|
|
519
|
-
/* @__PURE__ */ jsxRuntime.jsx(ModalStoreCleanup, {})
|
|
477
|
+
typeUtils.isDefined(registry) && /* @__PURE__ */ jsxRuntime.jsx(ModalRegistryBinder, { registry }),
|
|
478
|
+
/* @__PURE__ */ jsxRuntime.jsx(ModalViewport, { renderer })
|
|
520
479
|
] }) });
|
|
521
480
|
}
|
|
522
481
|
|