react-confirm-alert 3.1.1 → 3.3.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/Readme.md +42 -7
- package/dist/index.esm.js +147 -40
- package/lib/index.js +142 -34
- package/package.json +2 -1
- package/src/react-confirm-alert.css +233 -0
- package/style.css +233 -0
- package/typings/DialogFrame.d.ts +2 -0
- package/typings/DialogLayout.d.ts +4 -0
- package/typings/api.d.ts +1 -0
- package/typings/classNames.d.ts +7 -1
- package/typings/compat.d.ts +2 -0
- package/typings/index.d.ts +2 -1
- package/typings/types.d.ts +19 -1
package/Readme.md
CHANGED
|
@@ -16,20 +16,55 @@ npm install react-confirm-alert
|
|
|
16
16
|
|
|
17
17
|
```tsx
|
|
18
18
|
import { confirm } from 'react-confirm-alert'
|
|
19
|
-
import 'react-confirm-alert/
|
|
19
|
+
import 'react-confirm-alert/style.css'
|
|
20
20
|
|
|
21
21
|
if (await confirm({ title: 'Delete file?', message: 'This cannot be undone.', tone: 'danger' })) {
|
|
22
22
|
remove(file)
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
`style.css` needs 3.1.1 or later. The older path, `react-confirm-alert/src/react-confirm-alert.css`, still works.
|
|
27
|
+
|
|
26
28
|
`confirm()` resolves `true` or `false`. `alert()` and `prompt()` work the same way, and `<DialogHost />` placed inside your providers lets dialogs read their context.
|
|
27
29
|
|
|
30
|
+
## Custom UI
|
|
31
|
+
|
|
32
|
+
Put your own form, list or warning in a dialog. Plain HTML gets the default look, even under Tailwind v4 preflight, and any class you add wins:
|
|
33
|
+
|
|
34
|
+
```jsx
|
|
35
|
+
import { DialogLayout, openDialog } from 'react-confirm-alert'
|
|
36
|
+
|
|
37
|
+
const colour = await openDialog({
|
|
38
|
+
render: ({ close, dismiss }) => (
|
|
39
|
+
<DialogLayout title="Pick a colour" actions={[{ label: 'Cancel', onClick: dismiss }, { label: 'Blue', variant: 'primary', onClick: () => close('blue') }]}>
|
|
40
|
+
<p>Used for the team badge.</p>
|
|
41
|
+
</DialogLayout>
|
|
42
|
+
)
|
|
43
|
+
}).result
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
3.0 `customUI` still works. Add `skin: true` for the new look:
|
|
47
|
+
|
|
48
|
+
```jsx
|
|
49
|
+
confirmAlert({
|
|
50
|
+
skin: true,
|
|
51
|
+
customUI: ({ onClose }) => (
|
|
52
|
+
<>
|
|
53
|
+
<h1>Leave the board?</h1>
|
|
54
|
+
<p>You can join again from the invite link.</p>
|
|
55
|
+
<button onClick={onClose}>Stay</button>
|
|
56
|
+
</>
|
|
57
|
+
)
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`confirm`, `alert` and `prompt` take `content` for JSX between the message and the buttons. See [Custom UI](https://ga-mo.github.io/react-confirm-alert/docs/custom-ui/).
|
|
62
|
+
|
|
28
63
|
## 3.0 code keeps working
|
|
29
64
|
|
|
30
65
|
```jsx
|
|
31
66
|
import { confirmAlert } from 'react-confirm-alert'
|
|
32
|
-
import 'react-confirm-alert/
|
|
67
|
+
import 'react-confirm-alert/style.css'
|
|
33
68
|
|
|
34
69
|
confirmAlert({
|
|
35
70
|
title: 'Confirm to submit',
|
|
@@ -47,7 +82,7 @@ Same options, DOM, class names and CSS path as 3.0.
|
|
|
47
82
|
|
|
48
83
|
```css
|
|
49
84
|
@import 'tailwindcss';
|
|
50
|
-
@import 'react-confirm-alert/
|
|
85
|
+
@import 'react-confirm-alert/style.css' layer(components);
|
|
51
86
|
```
|
|
52
87
|
|
|
53
88
|
```tsx
|
|
@@ -60,11 +95,11 @@ Importing the CSS into `layer(components)` lets Tailwind utilities win without `
|
|
|
60
95
|
|
|
61
96
|
| Import | gzip |
|
|
62
97
|
|---|---|
|
|
63
|
-
| `import { confirmAlert }` | 3,
|
|
64
|
-
| `import { confirm }` |
|
|
65
|
-
| CSS |
|
|
98
|
+
| `import { confirmAlert }` | 3,769 B |
|
|
99
|
+
| `import { confirm }` | 4,042 B |
|
|
100
|
+
| CSS (the shipped file, not minified) | 2,909 B |
|
|
66
101
|
|
|
67
|
-
Measured on 2026-10-23 with size-limit 14.3.0 (`npx size-limit`, config in `.size-limit.json`): the ESM build bundled and minified with React and React DOM excluded, then gzipped. 3.0.6 measured the same way is 2,396 B, including `prop-types`. The extra bytes are the native modal, focus handling, stacked and queued dialogs,
|
|
102
|
+
Measured on 2026-10-23 with size-limit 14.3.0 (`npx size-limit`, config in `.size-limit.json`): the ESM build bundled and minified with React and React DOM excluded, then gzipped. 3.0.6 measured the same way is 2,396 B, including `prop-types`. The extra bytes are the native modal, focus handling, stacked and queued dialogs, dialogs that render inside your providers, and the default look for your own content.
|
|
68
103
|
|
|
69
104
|
## Older versions
|
|
70
105
|
|
package/dist/index.esm.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { Component, createContext, useContext, useEffect, useId, useLayoutEffect, useReducer, useRef, useState, useSyncExternalStore } from "react";
|
|
2
|
+
import { Component, Fragment, createContext, useContext, useEffect, useId, useLayoutEffect, useReducer, useRef, useState, useSyncExternalStore } from "react";
|
|
3
3
|
import { flushSync } from "react-dom";
|
|
4
4
|
import { createRoot } from "react-dom/client";
|
|
5
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
// src/store.ts
|
|
7
7
|
var emptyState = {
|
|
8
8
|
entries: [],
|
|
@@ -159,6 +159,7 @@ var slotsFor = (layers) => (slot, extra) => ({
|
|
|
159
159
|
});
|
|
160
160
|
var SlotContext = createContext(slotsFor([]));
|
|
161
161
|
var useSlot = () => useContext(SlotContext);
|
|
162
|
+
var FrameContext = createContext({});
|
|
162
163
|
function configureDialogs(defaults) {
|
|
163
164
|
runtime().defaults = defaults;
|
|
164
165
|
}
|
|
@@ -171,7 +172,7 @@ function DialogStack({ target, host }) {
|
|
|
171
172
|
if (!(host ? hosts[hosts.length - 1] === host : target !== null || hosts.length === 0)) return null;
|
|
172
173
|
const openIds = entries.filter((e) => e.phase === "open").map((e) => e.id);
|
|
173
174
|
const top = openIds[openIds.length - 1];
|
|
174
|
-
return /* @__PURE__ */ jsx(Fragment, { children: entries.filter((e) => e.target === target && e.phase !== "queued").map((e) => /* @__PURE__ */ jsx(EntryView, {
|
|
175
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: entries.filter((e) => e.target === target && e.phase !== "queued").map((e) => /* @__PURE__ */ jsx(EntryView, {
|
|
175
176
|
entry: e,
|
|
176
177
|
depth: openIds.indexOf(e.id),
|
|
177
178
|
topmost: e.id === top
|
|
@@ -213,6 +214,7 @@ function EntryView({ entry, depth, topmost }) {
|
|
|
213
214
|
closeOnClickOutside: (_ref2 = (_options$closeOnClick = options.closeOnClickOutside) !== null && _options$closeOnClick !== void 0 ? _options$closeOnClick : defaults.closeOnClickOutside) !== null && _ref2 !== void 0 ? _ref2 : true,
|
|
214
215
|
closeOnEscape: (_ref3 = (_options$closeOnEscap = options.closeOnEscape) !== null && _options$closeOnEscap !== void 0 ? _options$closeOnEscap : defaults.closeOnEscape) !== null && _ref3 !== void 0 ? _ref3 : true,
|
|
215
216
|
legacy: !!options.legacy,
|
|
217
|
+
skin: options.skin,
|
|
216
218
|
onClickOutside: options.onClickOutside,
|
|
217
219
|
onDismiss: dismiss,
|
|
218
220
|
children: /* @__PURE__ */ jsx(Render, {
|
|
@@ -221,6 +223,7 @@ function EntryView({ entry, depth, topmost }) {
|
|
|
221
223
|
descriptionId,
|
|
222
224
|
title: options.title,
|
|
223
225
|
message: options.message,
|
|
226
|
+
content: options.content,
|
|
224
227
|
buttons: (_options$buttons = options.buttons) !== null && _options$buttons !== void 0 ? _options$buttons : [],
|
|
225
228
|
close,
|
|
226
229
|
dismiss,
|
|
@@ -348,7 +351,7 @@ function closeDialog$1(id, { sync = true } = {}) {
|
|
|
348
351
|
commit(() => store.set(remove(store.get(), id)), sync);
|
|
349
352
|
return;
|
|
350
353
|
}
|
|
351
|
-
Promise.all(exits.map((a) => a.finished)).
|
|
354
|
+
Promise.all(exits.map((a) => a.finished.catch(() => {}))).then(() => store.set(remove(store.get(), id)));
|
|
352
355
|
}
|
|
353
356
|
var reopenQueued = false;
|
|
354
357
|
function reopenClosedFrames() {
|
|
@@ -374,12 +377,15 @@ function animationsOf({ frame, panel }) {
|
|
|
374
377
|
// src/DialogFrame.tsx
|
|
375
378
|
var canShowModal = () => typeof HTMLDialogElement !== "undefined" && typeof HTMLDialogElement.prototype.showModal === "function";
|
|
376
379
|
function DialogFrame(props) {
|
|
377
|
-
var _props$tone, _props$depth, _props$topmost;
|
|
380
|
+
var _props$labelledBy, _props$tone, _props$depth, _props$topmost, _props$labelledBy2;
|
|
378
381
|
const frame = useRef(null);
|
|
379
382
|
const panel = useRef(null);
|
|
380
383
|
const pressedOn = useRef(null);
|
|
381
384
|
const stay = useRef(null);
|
|
382
385
|
const native = props.modal && canShowModal();
|
|
386
|
+
const layoutTitleId = useId();
|
|
387
|
+
const [layoutTitles, setLayoutTitles] = useState(0);
|
|
388
|
+
const labelledBy = (_props$labelledBy = props.labelledBy) !== null && _props$labelledBy !== void 0 ? _props$labelledBy : props.label || layoutTitles === 0 ? void 0 : layoutTitleId;
|
|
383
389
|
useLayoutEffect(() => {
|
|
384
390
|
var _panel$current, _panel$current2, _panel$current3;
|
|
385
391
|
const element = frame.current;
|
|
@@ -440,7 +446,10 @@ function DialogFrame(props) {
|
|
|
440
446
|
const isBusy = () => !!props.id && runtime().busy.has(props.id);
|
|
441
447
|
const onKeyDown = (e) => {
|
|
442
448
|
var _props$onKeyDown;
|
|
443
|
-
(_props$onKeyDown = props.onKeyDown) === null || _props$onKeyDown === void 0 || _props$onKeyDown.call(props, e,
|
|
449
|
+
(_props$onKeyDown = props.onKeyDown) === null || _props$onKeyDown === void 0 || _props$onKeyDown.call(props, e, () => {
|
|
450
|
+
e.preventDefault();
|
|
451
|
+
props.onDismiss();
|
|
452
|
+
});
|
|
444
453
|
if (!native && !props.legacy && e.key === "Escape" && props.closeOnEscape && !isBusy()) props.onDismiss();
|
|
445
454
|
};
|
|
446
455
|
const slot = slotsFor(props.layers);
|
|
@@ -448,11 +457,12 @@ function DialogFrame(props) {
|
|
|
448
457
|
...slot("dialog", props.extraClass),
|
|
449
458
|
role: props.role,
|
|
450
459
|
"aria-label": props.label,
|
|
451
|
-
"aria-labelledby":
|
|
460
|
+
"aria-labelledby": labelledBy,
|
|
452
461
|
"aria-describedby": props.describedBy,
|
|
453
462
|
"data-rca": "",
|
|
454
463
|
"data-state": props.state,
|
|
455
464
|
"data-kind": props.kind,
|
|
465
|
+
"data-skin": props.legacy && !props.skin ? void 0 : "",
|
|
456
466
|
"data-tone": (_props$tone = props.tone) !== null && _props$tone !== void 0 ? _props$tone : "default",
|
|
457
467
|
"data-depth": String((_props$depth = props.depth) !== null && _props$depth !== void 0 ? _props$depth : 0),
|
|
458
468
|
"data-topmost": ((_props$topmost = props.topmost) !== null && _props$topmost !== void 0 ? _props$topmost : true) ? "" : void 0,
|
|
@@ -466,7 +476,14 @@ function DialogFrame(props) {
|
|
|
466
476
|
tabIndex: -1,
|
|
467
477
|
children: /* @__PURE__ */ jsx(SlotContext.Provider, {
|
|
468
478
|
value: slot,
|
|
469
|
-
children:
|
|
479
|
+
children: /* @__PURE__ */ jsx(FrameContext.Provider, {
|
|
480
|
+
value: {
|
|
481
|
+
id: props.id,
|
|
482
|
+
titleId: (_props$labelledBy2 = props.labelledBy) !== null && _props$labelledBy2 !== void 0 ? _props$labelledBy2 : layoutTitleId,
|
|
483
|
+
countTitle: setLayoutTitles
|
|
484
|
+
},
|
|
485
|
+
children: props.children
|
|
486
|
+
})
|
|
470
487
|
})
|
|
471
488
|
});
|
|
472
489
|
return native ? /* @__PURE__ */ jsx("dialog", {
|
|
@@ -494,9 +511,9 @@ var defaultButtons = [{
|
|
|
494
511
|
onClick: () => null
|
|
495
512
|
}];
|
|
496
513
|
function CustomUIHost({ render, args }) {
|
|
497
|
-
return /* @__PURE__ */ jsx(Fragment, { children: render(args) });
|
|
514
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: render(args) });
|
|
498
515
|
}
|
|
499
|
-
function LegacyContent({ props, titleId, close, id }) {
|
|
516
|
+
function LegacyContent({ props, titleId, close, id, skin }) {
|
|
500
517
|
var _props$buttons;
|
|
501
518
|
const latest = useRef({
|
|
502
519
|
props,
|
|
@@ -510,7 +527,12 @@ function LegacyContent({ props, titleId, close, id }) {
|
|
|
510
527
|
const keyboard = (event) => {
|
|
511
528
|
var _topmost, _props$keyCodeForClos, _props$closeOnEscape, _props$onkeyPress;
|
|
512
529
|
if (id && ((_topmost = topmost(store.get())) === null || _topmost === void 0 ? void 0 : _topmost.id) !== id) return;
|
|
513
|
-
|
|
530
|
+
if (id && runtime().busy.has(id)) return;
|
|
531
|
+
const { props } = latest.current;
|
|
532
|
+
const close = () => {
|
|
533
|
+
event.preventDefault();
|
|
534
|
+
latest.current.close();
|
|
535
|
+
};
|
|
514
536
|
const keyCode = event.keyCode;
|
|
515
537
|
if (((_props$keyCodeForClos = props.keyCodeForClose) !== null && _props$keyCodeForClos !== void 0 ? _props$keyCodeForClos : []).includes(keyCode)) close();
|
|
516
538
|
if (((_props$closeOnEscape = props.closeOnEscape) !== null && _props$closeOnEscape !== void 0 ? _props$closeOnEscape : true) && keyCode === 27) {
|
|
@@ -524,17 +546,30 @@ function LegacyContent({ props, titleId, close, id }) {
|
|
|
524
546
|
return () => document.removeEventListener("keydown", keyboard, false);
|
|
525
547
|
}, []);
|
|
526
548
|
const slot = useSlot();
|
|
549
|
+
const frame = useContext(FrameContext);
|
|
527
550
|
const { title, message, customUI, childrenElement } = props;
|
|
528
551
|
const buttons = (_props$buttons = props.buttons) !== null && _props$buttons !== void 0 ? _props$buttons : defaultButtons;
|
|
529
|
-
if (customUI)
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
552
|
+
if (customUI) {
|
|
553
|
+
const ui = /* @__PURE__ */ jsx(CustomUIHost, {
|
|
554
|
+
render: customUI,
|
|
555
|
+
args: {
|
|
556
|
+
title,
|
|
557
|
+
message,
|
|
558
|
+
buttons,
|
|
559
|
+
onClose: close
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
return skin ? /* @__PURE__ */ jsx("div", {
|
|
563
|
+
...slot("body"),
|
|
564
|
+
children: /* @__PURE__ */ jsx(FrameContext.Provider, {
|
|
565
|
+
value: {
|
|
566
|
+
...frame,
|
|
567
|
+
inBody: true
|
|
568
|
+
},
|
|
569
|
+
children: ui
|
|
570
|
+
})
|
|
571
|
+
}) : ui;
|
|
572
|
+
}
|
|
538
573
|
return /* @__PURE__ */ jsxs("div", {
|
|
539
574
|
...slot("body"),
|
|
540
575
|
children: [
|
|
@@ -561,19 +596,21 @@ function LegacyContent({ props, titleId, close, id }) {
|
|
|
561
596
|
});
|
|
562
597
|
}
|
|
563
598
|
function confirmAlert(properties) {
|
|
564
|
-
var _ref, _properties$
|
|
599
|
+
var _ref, _properties$skin, _runtime$defaults$con, _ref2, _properties$modal, _runtime$defaults$con2, _properties$closeOnCl, _properties$closeOnEs, _properties$targetId, _ref3, _properties$strategy, _runtime$defaults$con3;
|
|
600
|
+
const skin = (_ref = (_properties$skin = properties.skin) !== null && _properties$skin !== void 0 ? _properties$skin : (_runtime$defaults$con = runtime().defaults.confirmAlert) === null || _runtime$defaults$con === void 0 ? void 0 : _runtime$defaults$con.skin) !== null && _ref !== void 0 ? _ref : false;
|
|
565
601
|
function Content({ id, titleId, dismiss }) {
|
|
566
602
|
return /* @__PURE__ */ jsx(LegacyContent, {
|
|
567
603
|
props: properties,
|
|
568
604
|
titleId,
|
|
569
605
|
close: dismiss,
|
|
570
|
-
id
|
|
606
|
+
id,
|
|
607
|
+
skin
|
|
571
608
|
});
|
|
572
609
|
}
|
|
573
610
|
openEntry({
|
|
574
611
|
kind: "custom",
|
|
575
612
|
title: properties.title,
|
|
576
|
-
modal: (
|
|
613
|
+
modal: (_ref2 = (_properties$modal = properties.modal) !== null && _properties$modal !== void 0 ? _properties$modal : (_runtime$defaults$con2 = runtime().defaults.confirmAlert) === null || _runtime$defaults$con2 === void 0 ? void 0 : _runtime$defaults$con2.modal) !== null && _ref2 !== void 0 ? _ref2 : false,
|
|
577
614
|
unstyled: properties.unstyled,
|
|
578
615
|
classNames: properties.classNames,
|
|
579
616
|
closeOnClickOutside: (_properties$closeOnCl = properties.closeOnClickOutside) !== null && _properties$closeOnCl !== void 0 ? _properties$closeOnCl : true,
|
|
@@ -581,18 +618,20 @@ function confirmAlert(properties) {
|
|
|
581
618
|
overlayClassName: properties.overlayClassName,
|
|
582
619
|
onClickOutside: properties.onClickOutside,
|
|
583
620
|
legacy: true,
|
|
621
|
+
skin,
|
|
584
622
|
willUnmount: properties.willUnmount,
|
|
585
623
|
afterClose: properties.afterClose,
|
|
586
624
|
render: Content
|
|
587
|
-
}, (_properties$targetId = properties.targetId) !== null && _properties$targetId !== void 0 ? _properties$targetId : null, (
|
|
625
|
+
}, (_properties$targetId = properties.targetId) !== null && _properties$targetId !== void 0 ? _properties$targetId : null, (_ref3 = (_properties$strategy = properties.strategy) !== null && _properties$strategy !== void 0 ? _properties$strategy : (_runtime$defaults$con3 = runtime().defaults.confirmAlert) === null || _runtime$defaults$con3 === void 0 ? void 0 : _runtime$defaults$con3.strategy) !== null && _ref3 !== void 0 ? _ref3 : "replace");
|
|
588
626
|
}
|
|
589
627
|
function DeclarativeDialog(props) {
|
|
590
|
-
var _props$modal, _props$closeOnClickOu, _props$closeOnEscape2;
|
|
628
|
+
var _ref4, _props$skin, _runtime$defaults$con4, _props$modal, _props$closeOnClickOu, _props$closeOnEscape2;
|
|
591
629
|
const titleId = useId();
|
|
592
630
|
const close = () => {
|
|
593
631
|
var _props$afterClose;
|
|
594
632
|
return (_props$afterClose = props.afterClose) === null || _props$afterClose === void 0 ? void 0 : _props$afterClose.call(props);
|
|
595
633
|
};
|
|
634
|
+
const skin = (_ref4 = (_props$skin = props.skin) !== null && _props$skin !== void 0 ? _props$skin : (_runtime$defaults$con4 = runtime().defaults.confirmAlert) === null || _runtime$defaults$con4 === void 0 ? void 0 : _runtime$defaults$con4.skin) !== null && _ref4 !== void 0 ? _ref4 : false;
|
|
596
635
|
return /* @__PURE__ */ jsx(DialogFrame, {
|
|
597
636
|
modal: (_props$modal = props.modal) !== null && _props$modal !== void 0 ? _props$modal : false,
|
|
598
637
|
state: "open",
|
|
@@ -606,13 +645,15 @@ function DeclarativeDialog(props) {
|
|
|
606
645
|
closeOnClickOutside: (_props$closeOnClickOu = props.closeOnClickOutside) !== null && _props$closeOnClickOu !== void 0 ? _props$closeOnClickOu : true,
|
|
607
646
|
closeOnEscape: (_props$closeOnEscape2 = props.closeOnEscape) !== null && _props$closeOnEscape2 !== void 0 ? _props$closeOnEscape2 : true,
|
|
608
647
|
legacy: true,
|
|
648
|
+
skin,
|
|
609
649
|
role: "dialog",
|
|
610
650
|
onClickOutside: props.onClickOutside,
|
|
611
651
|
onDismiss: close,
|
|
612
652
|
children: /* @__PURE__ */ jsx(LegacyContent, {
|
|
613
653
|
props,
|
|
614
654
|
titleId,
|
|
615
|
-
close
|
|
655
|
+
close,
|
|
656
|
+
skin
|
|
616
657
|
})
|
|
617
658
|
});
|
|
618
659
|
}
|
|
@@ -648,7 +689,7 @@ function open(options, dismissValue, body) {
|
|
|
648
689
|
(_options$signal = options.signal) === null || _options$signal === void 0 || _options$signal.removeEventListener("abort", onAbort);
|
|
649
690
|
resolve(value === void 0 ? dismissValue : value);
|
|
650
691
|
};
|
|
651
|
-
const render = (props) => /* @__PURE__ */ jsx(Fragment, { children: body(props, controller.signal) });
|
|
692
|
+
const render = (props) => /* @__PURE__ */ jsx(Fragment$1, { children: body(props, controller.signal) });
|
|
652
693
|
const onAbort = () => closeDialog$1(id);
|
|
653
694
|
const id = openEntry({
|
|
654
695
|
...options,
|
|
@@ -663,6 +704,7 @@ function open(options, dismissValue, body) {
|
|
|
663
704
|
}
|
|
664
705
|
function Body({ props, children }) {
|
|
665
706
|
const slot = useSlot();
|
|
707
|
+
const frame = useContext(FrameContext);
|
|
666
708
|
return /* @__PURE__ */ jsxs("div", {
|
|
667
709
|
...slot("body"),
|
|
668
710
|
children: [
|
|
@@ -671,22 +713,42 @@ function Body({ props, children }) {
|
|
|
671
713
|
...slot("title"),
|
|
672
714
|
children: props.title
|
|
673
715
|
}),
|
|
674
|
-
props.message != null && /* @__PURE__ */ jsx("
|
|
716
|
+
props.message != null && (typeof props.message === "object" ? /* @__PURE__ */ jsx("div", {
|
|
717
|
+
id: props.descriptionId,
|
|
718
|
+
...slot("message"),
|
|
719
|
+
children: props.message
|
|
720
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
675
721
|
id: props.descriptionId,
|
|
676
722
|
...slot("message"),
|
|
677
723
|
children: props.message
|
|
724
|
+
})),
|
|
725
|
+
props.content != null && /* @__PURE__ */ jsx(FrameContext.Provider, {
|
|
726
|
+
value: {
|
|
727
|
+
...frame,
|
|
728
|
+
inBody: true
|
|
729
|
+
},
|
|
730
|
+
children: props.content
|
|
678
731
|
}),
|
|
679
732
|
children
|
|
680
733
|
]
|
|
681
734
|
});
|
|
682
735
|
}
|
|
683
|
-
function
|
|
684
|
-
const slot = useSlot();
|
|
736
|
+
function useBusy(id) {
|
|
685
737
|
const [busy, setBusy] = useState(null);
|
|
686
|
-
const
|
|
687
|
-
|
|
688
|
-
|
|
738
|
+
const mark = (index) => {
|
|
739
|
+
if (id) {
|
|
740
|
+
var _runtime$frames$get;
|
|
741
|
+
(_runtime$frames$get = runtime().frames.get(id)) === null || _runtime$frames$get === void 0 || _runtime$frames$get.frame.toggleAttribute("data-busy", index !== null);
|
|
742
|
+
if (index === null) runtime().busy.delete(id);
|
|
743
|
+
else runtime().busy.add(id);
|
|
744
|
+
}
|
|
745
|
+
setBusy(index);
|
|
689
746
|
};
|
|
747
|
+
return [busy, mark];
|
|
748
|
+
}
|
|
749
|
+
function Buttons({ props, signal: getSignal, focus }) {
|
|
750
|
+
const slot = useSlot();
|
|
751
|
+
const [busy, setBusy] = useBusy(props.id);
|
|
690
752
|
const press = async (button, index) => {
|
|
691
753
|
const signal = getSignal();
|
|
692
754
|
let waiting = false;
|
|
@@ -703,16 +765,11 @@ function Buttons({ props, signal: getSignal, focus }) {
|
|
|
703
765
|
}
|
|
704
766
|
waiting = true;
|
|
705
767
|
setBusy(index);
|
|
706
|
-
markBusy(true);
|
|
707
|
-
runtime().busy.add(props.id);
|
|
708
768
|
if (await outcome !== false && !signal.aborted) props.close(button.value);
|
|
709
769
|
} catch (error) {
|
|
710
770
|
console.error(error);
|
|
711
771
|
} finally {
|
|
712
|
-
if (
|
|
713
|
-
runtime().busy.delete(props.id);
|
|
714
|
-
markBusy(false);
|
|
715
|
-
if (!signal.aborted) setBusy(null);
|
|
772
|
+
if (waiting) setBusy(null);
|
|
716
773
|
}
|
|
717
774
|
};
|
|
718
775
|
return /* @__PURE__ */ jsx("div", {
|
|
@@ -984,6 +1041,7 @@ function ConfirmDialog(props) {
|
|
|
984
1041
|
descriptionId,
|
|
985
1042
|
title: props.title,
|
|
986
1043
|
message: props.message,
|
|
1044
|
+
content: props.content,
|
|
987
1045
|
dismiss: hide,
|
|
988
1046
|
onClose: hide
|
|
989
1047
|
};
|
|
@@ -1055,4 +1113,53 @@ function ConfirmDialog(props) {
|
|
|
1055
1113
|
children: body
|
|
1056
1114
|
});
|
|
1057
1115
|
}
|
|
1058
|
-
|
|
1116
|
+
// src/DialogLayout.tsx
|
|
1117
|
+
/** The default dialog layout for your own content: title, message, your children, then the actions. */
|
|
1118
|
+
function DialogLayout({ title, message, actions, children }) {
|
|
1119
|
+
const slot = useSlot();
|
|
1120
|
+
const frame = useContext(FrameContext);
|
|
1121
|
+
const [busy, setBusy] = useBusy(frame.id);
|
|
1122
|
+
const hasTitle = title != null;
|
|
1123
|
+
const { countTitle } = frame;
|
|
1124
|
+
useLayoutEffect(() => {
|
|
1125
|
+
if (!hasTitle || !countTitle) return;
|
|
1126
|
+
countTitle((n) => n + 1);
|
|
1127
|
+
return () => countTitle((n) => n - 1);
|
|
1128
|
+
}, [hasTitle, countTitle]);
|
|
1129
|
+
const Body = frame.inBody ? Fragment : "div";
|
|
1130
|
+
return /* @__PURE__ */ jsxs(Body, {
|
|
1131
|
+
...frame.inBody ? {} : slot("body"),
|
|
1132
|
+
children: [
|
|
1133
|
+
title != null && /* @__PURE__ */ jsx("h1", {
|
|
1134
|
+
id: frame.titleId,
|
|
1135
|
+
...slot("title"),
|
|
1136
|
+
children: title
|
|
1137
|
+
}),
|
|
1138
|
+
message != null && /* @__PURE__ */ jsx("div", {
|
|
1139
|
+
...slot("message"),
|
|
1140
|
+
children: message
|
|
1141
|
+
}),
|
|
1142
|
+
children,
|
|
1143
|
+
actions && actions.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
1144
|
+
...slot("actions"),
|
|
1145
|
+
children: actions.map(({ label, variant = "secondary", onClick, disabled, className, ...rest }, i) => /* @__PURE__ */ jsx("button", {
|
|
1146
|
+
type: "button",
|
|
1147
|
+
...rest,
|
|
1148
|
+
...slot("button", className),
|
|
1149
|
+
"data-variant": variant,
|
|
1150
|
+
"data-busy": busy === i ? "" : void 0,
|
|
1151
|
+
"aria-busy": busy === i || void 0,
|
|
1152
|
+
disabled: disabled || busy !== null,
|
|
1153
|
+
onClick: (event) => {
|
|
1154
|
+
const outcome = onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
|
1155
|
+
if (!(outcome instanceof Promise)) return;
|
|
1156
|
+
setBusy(i);
|
|
1157
|
+
outcome.catch((error) => console.error(error)).finally(() => setBusy(null));
|
|
1158
|
+
},
|
|
1159
|
+
children: label
|
|
1160
|
+
}, i))
|
|
1161
|
+
})
|
|
1162
|
+
]
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
export { ConfirmDialog, Dialog, DialogHost, DialogLayout, alert, closeAll, closeDialog, configureDialogs, confirm, confirmAlert, ReactConfirmAlert as default, openDialog, prompt, useDialog };
|