@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.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, input) => manager.open(definition, input)
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/modalRegistryBinding.ts
61
- var registryControllers = /* @__PURE__ */ new WeakMap();
62
- function bindModalRegistry(registry, controller) {
63
- registryControllers.set(registry, controller);
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 getModalRegistryController(registry) {
66
- return registryControllers.get(registry);
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
- const controller = createModalController();
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
- if (!Object.prototype.hasOwnProperty.call(definitions, key)) {
74
- throw new Error(`${MODAL_REGISTRY_UNKNOWN_KEY_ERROR}: ${key}`);
75
- }
76
- return definitions[key].open(controller, input);
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: controller.closeAll,
80
- confirm: controller.confirm,
81
- dismiss: controller.dismiss,
82
- isReady: controller.isReady,
83
- open
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 !== void 0;
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 instanceof HTMLElement) {
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 === null) {
131
+ if (!typeUtils.isDefined(dialogRef.current)) {
150
132
  return;
151
133
  }
152
134
  const focusable = getFocusableElements(dialogRef.current);
153
- if (focusable.length === 0) {
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
- var ModalStoreContext = react.createContext(void 0);
229
-
230
- // src/store/useModalStore.ts
231
- function useModalStoreApi() {
232
- const store = react.useContext(ModalStoreContext);
233
- if (store === void 0) {
234
- throw new Error("Modal store must be used within ModalProvider");
235
- }
236
- return store;
237
- }
238
- function useModalStore(selector) {
239
- return zustand.useStore(useModalStoreApi(), selector);
240
- }
241
-
242
- // src/store/modalStore.actions.ts
243
- function createModalStoreActions(set, get) {
244
- const removeTimerIds = /* @__PURE__ */ new Map();
245
- const clearRemoveTimer = (instanceId) => {
246
- const timerId = removeTimerIds.get(instanceId);
247
- if (timerId === void 0) {
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
- globalThis.clearTimeout(timerId);
251
- removeTimerIds.delete(instanceId);
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
- addModal: (modal) => {
255
- set((state) => ({
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
- dismissAll: (reason) => {
265
- const modals = get().modals.filter((item) => item.status === "open");
266
- for (const modal of modals) {
267
- modal.dismiss(reason);
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
- set((state) => ({
270
- modals: state.modals.map((modal) => ({
271
- ...modal,
272
- status: "closing"
273
- }))
274
- }));
287
+ removalTimers.clear();
288
+ dismissers.clear();
289
+ instances = [];
290
+ snapshot = { instances: [] };
291
+ notifyObservers();
292
+ observers.clear();
275
293
  },
276
- markModalClosing: (instanceId) => {
277
- set((state) => ({
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
- scheduleRemove: (instanceId, delayMs) => {
287
- clearRemoveTimer(instanceId);
288
- if (delayMs <= 0) {
289
- get().removeModal(instanceId);
290
- return;
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 timerId = globalThis.setTimeout(() => {
293
- removeTimerIds.delete(instanceId);
294
- get().removeModal(instanceId);
295
- }, delayMs);
296
- removeTimerIds.set(instanceId, timerId);
297
- },
298
- removeModal: (instanceId) => {
299
- clearRemoveTimer(instanceId);
300
- set((state) => ({
301
- modals: state.modals.filter((modal) => modal.instanceId !== instanceId)
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
- clearModals: () => {
305
- get().clearRemoveTimers();
306
- set({ modals: [] });
349
+ setCloseDelayMs: (nextCloseDelayMs) => {
350
+ closeDelayMs = nextCloseDelayMs;
307
351
  },
308
- clearRemoveTimers: () => {
309
- for (const timerId of removeTimerIds.values()) {
310
- globalThis.clearTimeout(timerId);
352
+ subscribe: (observer) => {
353
+ if (disposed) {
354
+ return () => void 0;
311
355
  }
312
- removeTimerIds.clear();
356
+ observers.add(observer);
357
+ return () => {
358
+ observers.delete(observer);
359
+ };
313
360
  }
314
361
  };
315
362
  }
316
-
317
- // src/store/modalStore.constants.ts
318
- var MODAL_STORE_DEFAULTS = {
319
- modals: [],
320
- nextInstanceIndex: 0
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 ModalStoreProvider({
331
- children
332
- }) {
333
- const [store] = react.useState(createModalStore);
334
- return /* @__PURE__ */ jsxRuntime.jsx(ModalStoreContext.Provider, { value: store, children });
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.constants.ts
350
- var DEFAULT_DISMISS_REASON = "dismiss";
387
+ // src/hooks/useModalManager/useModalManager.tsx
351
388
  function useModalManager() {
352
- const store = useModalStoreApi();
353
- const { closeDelayMs, confirmModal: confirmModal2 } = useModalRuntimeConfig();
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, open]
392
+ (params) => lifecycle.open(confirmModal2, params),
393
+ [confirmModal2, lifecycle]
443
394
  );
444
395
  return react.useMemo(
445
- () => ({ closeAll, confirm, dismiss, open }),
446
- [closeAll, confirm, dismiss, open]
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 = useModals();
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 { controller } = props;
426
+ const { registry } = props;
471
427
  const manager = useModalManager();
472
428
  react.useEffect(() => {
473
- const unbind = controller.bind(manager);
429
+ const unbind = attachModalRegistry(registry, manager);
474
430
  return () => {
475
431
  unbind();
476
432
  };
477
- }, [controller, manager]);
433
+ }, [registry, manager]);
478
434
  return null;
479
435
  }
480
-
481
- // src/provider/ModalStoreCleanup.constants.ts
482
- var PROVIDER_UNMOUNT_DISMISS_REASON = "provider-unmount";
483
-
484
- // src/provider/ModalStoreCleanup.tsx
485
- function ModalStoreCleanup() {
486
- const store = useModalStoreApi();
487
- react.useEffect(
488
- () => () => {
489
- store.getState().dismissAll(PROVIDER_UNMOUNT_DISMISS_REASON);
490
- store.getState().clearRemoveTimers();
491
- store.getState().clearModals();
492
- },
493
- [store]
494
- );
495
- return null;
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
- const registryController = registry === void 0 ? void 0 : getModalRegistryController(registry);
506
- if (registry !== void 0 && registryController === void 0) {
507
- throw new Error(
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
- return /* @__PURE__ */ jsxRuntime.jsx(ModalStoreProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(ModalRuntimeConfigContext.Provider, { value: runtimeConfig, children: [
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
- registryController && /* @__PURE__ */ jsxRuntime.jsx(ModalRegistryBinder, { controller: registryController }),
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