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