@lerx/promise-modal 0.8.4 → 0.8.6

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
@@ -18,6 +18,8 @@ class ModalManager {
18
18
  static #anchor = null;
19
19
  static #scope = `promise-modal-${lib.getRandomString(36)}`;
20
20
  static #hash = hash.polynomialHash(ModalManager.#scope);
21
+ static #styleManager = styleManager.styleManagerFactory(ModalManager.#scope);
22
+ static #styleSheetDefinition = new Map();
21
23
  static anchor(options) {
22
24
  if (ModalManager.#anchor !== null)
23
25
  return ModalManager.#anchor;
@@ -36,13 +38,20 @@ class ModalManager {
36
38
  static get prerender() {
37
39
  return ModalManager.#prerenderList;
38
40
  }
39
- static #openHandler = (modal) => ModalManager.#prerenderList.push(modal);
41
+ static #openHandler = ((modal) => {
42
+ ModalManager.#prerenderList.push(modal);
43
+ });
40
44
  static set openHandler(handler) {
41
45
  ModalManager.#openHandler = handler;
42
46
  ModalManager.#prerenderList = [];
43
47
  }
44
- static #styleManager = styleManager.styleManagerFactory(ModalManager.#scope);
45
- static #styleSheetDefinition = new Map();
48
+ static #refreshHandler;
49
+ static set refreshHandler(handler) {
50
+ ModalManager.#refreshHandler = handler;
51
+ }
52
+ static refresh() {
53
+ ModalManager.#refreshHandler?.();
54
+ }
46
55
  static defineStyleSheet(styleId, css) {
47
56
  ModalManager.#styleSheetDefinition.set(styleId, util.compressCss(css));
48
57
  }
@@ -56,95 +65,113 @@ class ModalManager {
56
65
  static reset() {
57
66
  ModalManager.#anchor = null;
58
67
  ModalManager.#prerenderList = [];
59
- ModalManager.#openHandler = (modal) => ModalManager.#prerenderList.push(modal);
68
+ ModalManager.#openHandler = ((modal) => {
69
+ ModalManager.#prerenderList.push(modal);
70
+ });
71
+ ModalManager.#refreshHandler = undefined;
60
72
  styleManager.destroyScope(ModalManager.#scope);
61
73
  }
62
74
  static open(modal) {
63
- ModalManager.#openHandler(modal);
75
+ return ModalManager.#openHandler(modal);
64
76
  }
65
77
  }
66
78
 
67
- const alert = ({ group, subtype, title, subtitle, content, background, footer, dimmed, manualDestroy, closeOnBackdropClick, ForegroundComponent, BackgroundComponent, }) => {
68
- return new Promise((resolve, reject) => {
79
+ const closeModal = (modalNode, refresh = true) => {
80
+ if (modalNode.visible === false)
81
+ return;
82
+ modalNode.onClose();
83
+ modalNode.onHide();
84
+ if (refresh)
85
+ ModalManager.refresh();
86
+ if (modalNode.manualDestroy || modalNode.alive === false)
87
+ return;
88
+ return setTimeout(() => modalNode.onDestroy(), modalNode.duration);
89
+ };
90
+
91
+ const subscribeAbortSignal = (modalNode, signal) => {
92
+ if (signal === undefined)
93
+ return null;
94
+ const handleAbort = () => closeModal(modalNode);
95
+ signal.addEventListener('abort', handleAbort, { once: true });
96
+ return () => signal.removeEventListener('abort', handleAbort);
97
+ };
98
+
99
+ const alertHandler = (args) => {
100
+ const modalNode = ModalManager.open({
101
+ ...args,
102
+ type: 'alert',
103
+ });
104
+ const unsubscribe = subscribeAbortSignal(modalNode, args.signal);
105
+ const promiseHandler = new Promise((resolve, reject) => {
69
106
  try {
70
- ModalManager.open({
71
- type: 'alert',
72
- group,
73
- subtype,
74
- resolve: () => resolve(),
75
- title,
76
- subtitle,
77
- content,
78
- background,
79
- footer,
80
- dimmed,
81
- manualDestroy,
82
- closeOnBackdropClick,
83
- ForegroundComponent,
84
- BackgroundComponent,
85
- });
107
+ modalNode.handleResolve = () => {
108
+ unsubscribe?.();
109
+ resolve();
110
+ };
111
+ if (args.signal?.aborted)
112
+ closeModal(modalNode);
86
113
  }
87
114
  catch (error) {
115
+ closeModal(modalNode);
116
+ unsubscribe?.();
88
117
  reject(error);
89
118
  }
90
119
  });
120
+ return { modalNode, promiseHandler };
91
121
  };
92
122
 
93
- const confirm = ({ group, subtype, title, subtitle, content, background, footer, dimmed, manualDestroy, closeOnBackdropClick, ForegroundComponent, BackgroundComponent, }) => {
94
- return new Promise((resolve, reject) => {
123
+ const confirmHandler = (args) => {
124
+ const modalNode = ModalManager.open({
125
+ ...args,
126
+ type: 'confirm',
127
+ });
128
+ const unsubscribe = subscribeAbortSignal(modalNode, args.signal);
129
+ const promiseHandler = new Promise((resolve, reject) => {
95
130
  try {
96
- ModalManager.open({
97
- type: 'confirm',
98
- group,
99
- subtype,
100
- resolve: (result) => resolve(result ?? false),
101
- title,
102
- subtitle,
103
- content,
104
- background,
105
- footer,
106
- dimmed,
107
- manualDestroy,
108
- closeOnBackdropClick,
109
- ForegroundComponent,
110
- BackgroundComponent,
111
- });
131
+ modalNode.handleResolve = (result) => {
132
+ unsubscribe?.();
133
+ resolve(result ?? false);
134
+ };
135
+ if (args.signal?.aborted)
136
+ closeModal(modalNode);
112
137
  }
113
138
  catch (error) {
139
+ closeModal(modalNode);
140
+ unsubscribe?.();
114
141
  reject(error);
115
142
  }
116
143
  });
144
+ return { modalNode, promiseHandler };
117
145
  };
118
146
 
119
- const prompt = ({ group, title, subtitle, content, defaultValue, Input, disabled, returnOnCancel, background, footer, dimmed, manualDestroy, closeOnBackdropClick, ForegroundComponent, BackgroundComponent, }) => {
120
- return new Promise((resolve, reject) => {
147
+ const promptHandler = (args) => {
148
+ const modalNode = ModalManager.open({
149
+ ...args,
150
+ type: 'prompt',
151
+ });
152
+ const unsubscribe = subscribeAbortSignal(modalNode, args.signal);
153
+ const promiseHandler = new Promise((resolve, reject) => {
121
154
  try {
122
- ModalManager.open({
123
- type: 'prompt',
124
- group,
125
- resolve: (result) => resolve(result),
126
- title,
127
- subtitle,
128
- content,
129
- Input,
130
- defaultValue,
131
- disabled,
132
- returnOnCancel,
133
- background,
134
- footer,
135
- dimmed,
136
- manualDestroy,
137
- closeOnBackdropClick,
138
- ForegroundComponent,
139
- BackgroundComponent,
140
- });
155
+ modalNode.handleResolve = (result) => {
156
+ unsubscribe?.();
157
+ resolve(result);
158
+ };
159
+ if (args.signal?.aborted)
160
+ closeModal(modalNode);
141
161
  }
142
162
  catch (error) {
163
+ closeModal(modalNode);
164
+ unsubscribe?.();
143
165
  reject(error);
144
166
  }
145
167
  });
168
+ return { modalNode, promiseHandler };
146
169
  };
147
170
 
171
+ const alert = (args) => alertHandler(args).promiseHandler;
172
+ const confirm = (args) => confirmHandler(args).promiseHandler;
173
+ const prompt = (args) => promptHandler(args).promiseHandler;
174
+
148
175
  class AbstractNode {
149
176
  id;
150
177
  group;
@@ -152,9 +179,10 @@ class AbstractNode {
152
179
  title;
153
180
  subtitle;
154
181
  background;
182
+ dimmed;
183
+ duration;
155
184
  manualDestroy;
156
185
  closeOnBackdropClick;
157
- dimmed;
158
186
  ForegroundComponent;
159
187
  BackgroundComponent;
160
188
  #alive;
@@ -165,9 +193,12 @@ class AbstractNode {
165
193
  get visible() {
166
194
  return this.#visible;
167
195
  }
168
- #resolve;
196
+ #handleResolve;
197
+ set handleResolve(handleResolve) {
198
+ this.#handleResolve = handleResolve;
199
+ }
169
200
  #listeners = new Set();
170
- constructor({ id, initiator, group, title, subtitle, background, dimmed = true, manualDestroy = false, closeOnBackdropClick = true, resolve, ForegroundComponent, BackgroundComponent, }) {
201
+ constructor({ id, initiator, group, title, subtitle, background, dimmed = true, duration = 0, manualDestroy = false, closeOnBackdropClick = true, handleResolve, ForegroundComponent, BackgroundComponent, }) {
171
202
  this.id = id;
172
203
  this.group = group;
173
204
  this.initiator = initiator;
@@ -175,13 +206,17 @@ class AbstractNode {
175
206
  this.subtitle = subtitle;
176
207
  this.background = background;
177
208
  this.dimmed = dimmed;
209
+ this.duration = duration;
178
210
  this.manualDestroy = manualDestroy;
179
211
  this.closeOnBackdropClick = closeOnBackdropClick;
180
212
  this.ForegroundComponent = ForegroundComponent;
181
213
  this.BackgroundComponent = BackgroundComponent;
182
214
  this.#alive = true;
183
215
  this.#visible = true;
184
- this.#resolve = resolve;
216
+ this.#handleResolve = handleResolve;
217
+ }
218
+ onResolve(result) {
219
+ this.#handleResolve?.(result);
185
220
  }
186
221
  subscribe(listener) {
187
222
  this.#listeners.add(listener);
@@ -193,9 +228,6 @@ class AbstractNode {
193
228
  for (const listener of this.#listeners)
194
229
  listener();
195
230
  }
196
- resolve(result) {
197
- this.#resolve(result);
198
- }
199
231
  onDestroy() {
200
232
  const needPublish = this.#alive === true;
201
233
  this.#alive = false;
@@ -221,7 +253,7 @@ class AlertNode extends AbstractNode {
221
253
  subtype;
222
254
  content;
223
255
  footer;
224
- constructor({ id, group, initiator, type, subtype, title, subtitle, content, footer, background, dimmed, manualDestroy, closeOnBackdropClick, resolve, ForegroundComponent, BackgroundComponent, }) {
256
+ constructor({ id, group, initiator, type, subtype, title, subtitle, content, footer, background, dimmed, duration, manualDestroy, closeOnBackdropClick, handleResolve, ForegroundComponent, BackgroundComponent, }) {
225
257
  super({
226
258
  id,
227
259
  group,
@@ -230,9 +262,10 @@ class AlertNode extends AbstractNode {
230
262
  subtitle,
231
263
  background,
232
264
  dimmed,
265
+ duration,
233
266
  manualDestroy,
234
267
  closeOnBackdropClick,
235
- resolve,
268
+ handleResolve,
236
269
  ForegroundComponent,
237
270
  BackgroundComponent,
238
271
  });
@@ -242,10 +275,10 @@ class AlertNode extends AbstractNode {
242
275
  this.footer = footer;
243
276
  }
244
277
  onClose() {
245
- this.resolve(null);
278
+ this.onResolve(null);
246
279
  }
247
280
  onConfirm() {
248
- this.resolve(null);
281
+ this.onResolve(null);
249
282
  }
250
283
  }
251
284
 
@@ -254,7 +287,7 @@ class ConfirmNode extends AbstractNode {
254
287
  subtype;
255
288
  content;
256
289
  footer;
257
- constructor({ id, group, initiator, type, subtype, title, subtitle, content, footer, background, dimmed, manualDestroy, closeOnBackdropClick, resolve, ForegroundComponent, BackgroundComponent, }) {
290
+ constructor({ id, group, initiator, type, subtype, title, subtitle, content, footer, background, dimmed, duration, manualDestroy, closeOnBackdropClick, handleResolve, ForegroundComponent, BackgroundComponent, }) {
258
291
  super({
259
292
  id,
260
293
  group,
@@ -263,9 +296,10 @@ class ConfirmNode extends AbstractNode {
263
296
  subtitle,
264
297
  background,
265
298
  dimmed,
299
+ duration,
266
300
  manualDestroy,
267
301
  closeOnBackdropClick,
268
- resolve,
302
+ handleResolve,
269
303
  ForegroundComponent,
270
304
  BackgroundComponent,
271
305
  });
@@ -275,10 +309,10 @@ class ConfirmNode extends AbstractNode {
275
309
  this.footer = footer;
276
310
  }
277
311
  onClose() {
278
- this.resolve(false);
312
+ this.onResolve(false);
279
313
  }
280
314
  onConfirm() {
281
- this.resolve(true);
315
+ this.onResolve(true);
282
316
  }
283
317
  }
284
318
 
@@ -291,7 +325,7 @@ class PromptNode extends AbstractNode {
291
325
  returnOnCancel;
292
326
  footer;
293
327
  #value;
294
- constructor({ id, group, initiator, type, title, subtitle, content, defaultValue, Input, disabled, returnOnCancel, footer, background, dimmed, manualDestroy, closeOnBackdropClick, resolve, ForegroundComponent, BackgroundComponent, }) {
328
+ constructor({ id, group, initiator, type, title, subtitle, content, defaultValue, Input, disabled, returnOnCancel, footer, background, dimmed, duration, manualDestroy, closeOnBackdropClick, handleResolve, ForegroundComponent, BackgroundComponent, }) {
295
329
  super({
296
330
  id,
297
331
  group,
@@ -300,9 +334,10 @@ class PromptNode extends AbstractNode {
300
334
  subtitle,
301
335
  background,
302
336
  dimmed,
337
+ duration,
303
338
  manualDestroy,
304
339
  closeOnBackdropClick,
305
- resolve,
340
+ handleResolve,
306
341
  ForegroundComponent,
307
342
  BackgroundComponent,
308
343
  });
@@ -319,13 +354,13 @@ class PromptNode extends AbstractNode {
319
354
  this.#value = value;
320
355
  }
321
356
  onConfirm() {
322
- this.resolve(this.#value ?? null);
357
+ this.onResolve(this.#value ?? null);
323
358
  }
324
359
  onClose() {
325
360
  if (this.returnOnCancel)
326
- this.resolve(this.#value ?? null);
361
+ this.onResolve(this.#value ?? null);
327
362
  else
328
- this.resolve(null);
363
+ this.onResolve(null);
329
364
  }
330
365
  }
331
366
 
@@ -364,8 +399,8 @@ const FallbackFooter = ({ confirmLabel, hideConfirm = false, cancelLabel, hideCa
364
399
  const ModalManagerContext = react.createContext({});
365
400
 
366
401
  const useModalManagerContext = () => react.useContext(ModalManagerContext);
367
- const useModal = (id) => {
368
- const { getModal } = useModalManagerContext();
402
+ const useModalManager = (id) => {
403
+ const { getModal } = react.useContext(ModalManagerContext);
369
404
  return react.useMemo(() => getModal(id), [id, getModal]);
370
405
  };
371
406
 
@@ -482,32 +517,26 @@ const ModalManagerContextProvider = react.memo(({ usePathname, children, }) => {
482
517
  const { manualDestroy, closeOnBackdropClick } = options;
483
518
  for (const data of ModalManager.prerender) {
484
519
  const modal = nodeFactory({
520
+ duration,
521
+ manualDestroy,
522
+ closeOnBackdropClick,
485
523
  ...data,
486
524
  id: modalIdSequence.current++,
487
525
  initiator: initiator.current,
488
- manualDestroy: data.manualDestroy !== undefined
489
- ? data.manualDestroy
490
- : manualDestroy,
491
- closeOnBackdropClick: data.closeOnBackdropClick !== undefined
492
- ? data.closeOnBackdropClick
493
- : closeOnBackdropClick,
494
526
  });
495
527
  modalDictionary.current.set(modal.id, modal);
496
528
  setModalIds((ids) => [...ids, modal.id]);
497
529
  }
498
530
  ModalManager.openHandler = (data) => {
499
- const modal = nodeFactory({
531
+ const modalNode = nodeFactory({
532
+ duration,
533
+ manualDestroy,
534
+ closeOnBackdropClick,
500
535
  ...data,
501
536
  id: modalIdSequence.current++,
502
537
  initiator: initiator.current,
503
- manualDestroy: data.manualDestroy !== undefined
504
- ? data.manualDestroy
505
- : manualDestroy,
506
- closeOnBackdropClick: data.closeOnBackdropClick !== undefined
507
- ? data.closeOnBackdropClick
508
- : closeOnBackdropClick,
509
538
  });
510
- modalDictionary.current.set(modal.id, modal);
539
+ modalDictionary.current.set(modalNode.id, modalNode);
511
540
  setModalIds((ids) => {
512
541
  const aliveIds = [];
513
542
  for (let i = 0, l = ids.length; i < l; i++) {
@@ -518,8 +547,9 @@ const ModalManagerContextProvider = react.memo(({ usePathname, children, }) => {
518
547
  else
519
548
  aliveIds.push(id);
520
549
  }
521
- return [...aliveIds, modal.id];
550
+ return [...aliveIds, modalNode.id];
522
551
  });
552
+ return modalNode;
523
553
  };
524
554
  });
525
555
  react.useLayoutEffect(() => {
@@ -534,78 +564,62 @@ const ModalManagerContextProvider = react.memo(({ usePathname, children, }) => {
534
564
  }
535
565
  initiator.current = pathname;
536
566
  }, [pathname]);
537
- const getModalNode = react.useCallback((modalId) => {
538
- return modalDictionary.current.get(modalId);
539
- }, []);
540
- const onDestroy = react.useCallback((modalId) => {
567
+ const getModalNodeRef = react.useRef((modalId) => modalDictionary.current.get(modalId));
568
+ const onDestroyRef = react.useRef((modalId) => {
541
569
  const modal = modalDictionary.current.get(modalId);
542
570
  if (!modal)
543
571
  return;
544
572
  modal.onDestroy();
545
- updaterRef.current?.();
546
- }, []);
547
- const updaterRef = react.useRef(undefined);
548
- const hideModal = react.useCallback((modalId) => {
573
+ ModalManager.refresh();
574
+ });
575
+ const hideModalRef = react.useRef((modalId) => {
549
576
  const modal = modalDictionary.current.get(modalId);
550
577
  if (!modal)
551
578
  return;
552
579
  modal.onHide();
553
- updaterRef.current?.();
554
- if (!modal.manualDestroy)
555
- setTimeout(() => {
556
- modal.onDestroy();
557
- }, duration);
558
- }, [duration]);
559
- const onChange = react.useCallback((modalId, value) => {
580
+ ModalManager.refresh();
581
+ if (modal.manualDestroy === false)
582
+ setTimeout(() => modal.onDestroy(), modal.duration);
583
+ });
584
+ const onChangeRef = react.useRef((modalId, value) => {
560
585
  const modal = modalDictionary.current.get(modalId);
561
586
  if (!modal)
562
587
  return;
563
588
  if (modal.type === 'prompt')
564
589
  modal.onChange(value);
565
- }, []);
566
- const onConfirm = react.useCallback((modalId) => {
590
+ });
591
+ const onConfirmRef = react.useRef((modalId) => {
567
592
  const modal = modalDictionary.current.get(modalId);
568
593
  if (!modal)
569
594
  return;
570
595
  modal.onConfirm();
571
- hideModal(modalId);
572
- }, [hideModal]);
573
- const onClose = react.useCallback((modalId) => {
596
+ hideModalRef.current(modalId);
597
+ });
598
+ const onCloseRef = react.useRef((modalId) => {
574
599
  const modal = modalDictionary.current.get(modalId);
575
600
  if (!modal)
576
601
  return;
577
602
  modal.onClose();
578
- hideModal(modalId);
579
- }, [hideModal]);
580
- const getModal = react.useCallback((modalId) => ({
581
- modal: getModalNode(modalId),
582
- onConfirm: () => onConfirm(modalId),
583
- onClose: () => onClose(modalId),
584
- onChange: (value) => onChange(modalId, value),
585
- onDestroy: () => onDestroy(modalId),
586
- }), [getModalNode, onConfirm, onClose, onChange, onDestroy]);
603
+ hideModalRef.current(modalId);
604
+ });
605
+ const getModalRef = react.useRef((modalId) => ({
606
+ modal: getModalNodeRef.current(modalId),
607
+ onConfirm: () => onConfirmRef.current(modalId),
608
+ onClose: () => onCloseRef.current(modalId),
609
+ onChange: (value) => onChangeRef.current(modalId, value),
610
+ onDestroy: () => onDestroyRef.current(modalId),
611
+ }));
587
612
  const value = react.useMemo(() => {
588
613
  return {
589
614
  modalIds,
590
- getModalNode,
591
- onChange,
592
- onConfirm,
593
- onClose,
594
- onDestroy,
595
- getModal,
596
- setUpdater: (updater) => {
597
- updaterRef.current = updater;
598
- },
615
+ getModalNode: getModalNodeRef.current,
616
+ onChange: onChangeRef.current,
617
+ onConfirm: onConfirmRef.current,
618
+ onClose: onCloseRef.current,
619
+ onDestroy: onDestroyRef.current,
620
+ getModal: getModalRef.current,
599
621
  };
600
- }, [
601
- modalIds,
602
- getModal,
603
- getModalNode,
604
- onChange,
605
- onConfirm,
606
- onClose,
607
- onDestroy,
608
- ]);
622
+ }, [modalIds]);
609
623
  return (jsxRuntime.jsx(ModalManagerContext.Provider, { value: value, children: children }));
610
624
  });
611
625
 
@@ -674,7 +688,7 @@ ModalManager.defineStyleSheet('background', style$3);
674
688
  const BackgroundFrame = ({ modalId, onChangeOrder, }) => {
675
689
  const { BackgroundComponent } = useConfigurationContext();
676
690
  const { context: userDefinedContext } = useUserDefinedContext();
677
- const { modal, onClose, onChange, onConfirm, onDestroy } = useModal(modalId);
691
+ const { modal, onClose, onChange, onConfirm, onDestroy } = useModalManager(modalId);
678
692
  const handleClose = react.useCallback((event) => {
679
693
  if (modal && modal.closeOnBackdropClick && modal.visible)
680
694
  onClose();
@@ -790,7 +804,7 @@ ModalManager.defineStyleSheet('foreground', style$2);
790
804
  const ForegroundFrame = ({ modalId, onChangeOrder, }) => {
791
805
  const { ForegroundComponent } = useConfigurationContext();
792
806
  const { context: userDefinedContext } = useUserDefinedContext();
793
- const { modal, onChange, onConfirm, onClose, onDestroy } = useModal(modalId);
807
+ const { modal, onChange, onConfirm, onClose, onDestroy } = useModalManager(modalId);
794
808
  const Foreground = react.useMemo(() => modal?.ForegroundComponent || ForegroundComponent, [ForegroundComponent, modal]);
795
809
  if (!modal)
796
810
  return null;
@@ -822,7 +836,7 @@ ModalManager.defineStyleSheet('presenter', style$1);
822
836
  const Presenter = react.memo(({ modalId, getValue, increment }) => {
823
837
  const ref = react.useRef(null);
824
838
  const options = useConfigurationOptions();
825
- const { modal } = useModal(modalId);
839
+ const { modal } = useModalManager(modalId);
826
840
  useSubscribeModal(modal);
827
841
  hook.useOnMountLayout(() => {
828
842
  if (ref.current === null)
@@ -868,10 +882,10 @@ ModalManager.defineStyleSheet('backdrop', backdropStyle);
868
882
  const { getValue, increment, reset } = lib.counterFactory(0);
869
883
  const AnchorInner = () => {
870
884
  const [version, update] = hook.useVersion();
871
- const { modalIds, setUpdater } = useModalManagerContext();
885
+ const { modalIds } = useModalManagerContext();
872
886
  react.useEffect(() => {
873
- setUpdater(update);
874
- }, [setUpdater, update]);
887
+ ModalManager.refreshHandler = update;
888
+ }, [update]);
875
889
  const options = useConfigurationOptions();
876
890
  const dimmed = useActiveModalCount(validateDimmable, version);
877
891
  if (!dimmed)
@@ -971,8 +985,39 @@ const useBootstrap = ({ usePathname: useExternalPathname, ForegroundComponent, B
971
985
  return { portal, initialize };
972
986
  };
973
987
 
988
+ const useModal = (configuration) => {
989
+ const modalNodesRef = react.useRef([]);
990
+ const baseArgsRef = react.useRef(configuration);
991
+ const alertRef = react.useRef((args) => {
992
+ const { modalNode, promiseHandler } = alertHandler(baseArgsRef.current ? { ...baseArgsRef.current, ...args } : args);
993
+ modalNodesRef.current.push(modalNode);
994
+ return promiseHandler;
995
+ });
996
+ const confirmRef = react.useRef((args) => {
997
+ const { modalNode, promiseHandler } = confirmHandler(baseArgsRef.current ? { ...baseArgsRef.current, ...args } : args);
998
+ modalNodesRef.current.push(modalNode);
999
+ return promiseHandler;
1000
+ });
1001
+ const promptRef = react.useRef((args) => {
1002
+ const { modalNode, promiseHandler } = promptHandler(baseArgsRef.current ? { ...baseArgsRef.current, ...args } : args);
1003
+ modalNodesRef.current.push(modalNode);
1004
+ return promiseHandler;
1005
+ });
1006
+ hook.useOnUnmount(() => {
1007
+ for (const node of modalNodesRef.current)
1008
+ closeModal(node, false);
1009
+ ModalManager.refresh();
1010
+ modalNodesRef.current = [];
1011
+ });
1012
+ return {
1013
+ alert: alertRef.current,
1014
+ confirm: confirmRef.current,
1015
+ prompt: promptRef.current,
1016
+ };
1017
+ };
1018
+
974
1019
  const useDestroyAfter = (modalId, duration) => {
975
- const { modal, onDestroy } = useModal(modalId);
1020
+ const { modal, onDestroy } = useModalManager(modalId);
976
1021
  const tick = useSubscribeModal(modal);
977
1022
  const reference = react.useRef({
978
1023
  modal,
@@ -1013,6 +1058,17 @@ const useModalAnimation = (visible, handler) => {
1013
1058
  }, [visible]);
1014
1059
  };
1015
1060
 
1061
+ const useModalDuration = (id) => {
1062
+ const globalDuration = useConfigurationDuration();
1063
+ if (id === undefined)
1064
+ return globalDuration;
1065
+ const { modal } = useModalManager(id);
1066
+ if (modal === undefined)
1067
+ return globalDuration;
1068
+ const duration = modal.duration;
1069
+ return { duration, milliseconds: duration + 'ms' };
1070
+ };
1071
+
1016
1072
  exports.ModalProvider = BootstrapProvider;
1017
1073
  exports.alert = alert;
1018
1074
  exports.confirm = confirm;
@@ -1020,8 +1076,9 @@ exports.prompt = prompt;
1020
1076
  exports.useActiveModalCount = useActiveModalCount;
1021
1077
  exports.useDestroyAfter = useDestroyAfter;
1022
1078
  exports.useInitializeModal = useBootstrap;
1079
+ exports.useModal = useModal;
1023
1080
  exports.useModalAnimation = useModalAnimation;
1024
1081
  exports.useModalBackdrop = useConfigurationBackdrop;
1025
- exports.useModalDuration = useConfigurationDuration;
1082
+ exports.useModalDuration = useModalDuration;
1026
1083
  exports.useModalOptions = useConfigurationOptions;
1027
1084
  exports.useSubscribeModal = useSubscribeModal;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
- export { useConfigurationOptions as useModalOptions, useConfigurationDuration as useModalDuration, useConfigurationBackdrop as useModalBackdrop, } from './providers';
1
+ export { useConfigurationOptions as useModalOptions, useConfigurationBackdrop as useModalBackdrop, } from './providers';
2
2
  export { useBootstrap as useInitializeModal, BootstrapProvider as ModalProvider, type BootstrapProviderHandle as ModalProviderHandle, type BootstrapProviderProps as ModalProviderProps, } from './bootstrap';
3
+ export { useModal } from './hooks/useModal';
3
4
  export { useActiveModalCount } from './hooks/useActiveModalCount';
4
5
  export { useDestroyAfter } from './hooks/useDestroyAfter';
5
6
  export { useModalAnimation } from './hooks/useModalAnimation';
7
+ export { useModalDuration } from './hooks/useModalDuration';
6
8
  export { useSubscribeModal } from './hooks/useSubscribeModal';
7
9
  export { alert, confirm, prompt } from './core';
8
10
  export type { ModalOptions, ModalFrameProps, FooterComponentProps, ModalBackground, PromptInputProps, AlertContentProps, ConfirmContentProps, PromptContentProps, WrapperComponentProps, } from './types';