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/lib/index.js
CHANGED
|
@@ -163,6 +163,7 @@ var slotsFor = (layers) => (slot, extra) => ({
|
|
|
163
163
|
});
|
|
164
164
|
var SlotContext = (0, react.createContext)(slotsFor([]));
|
|
165
165
|
var useSlot = () => (0, react.useContext)(SlotContext);
|
|
166
|
+
var FrameContext = (0, react.createContext)({});
|
|
166
167
|
function configureDialogs(defaults) {
|
|
167
168
|
runtime().defaults = defaults;
|
|
168
169
|
}
|
|
@@ -217,6 +218,7 @@ function EntryView({ entry, depth, topmost }) {
|
|
|
217
218
|
closeOnClickOutside: (_ref2 = (_options$closeOnClick = options.closeOnClickOutside) !== null && _options$closeOnClick !== void 0 ? _options$closeOnClick : defaults.closeOnClickOutside) !== null && _ref2 !== void 0 ? _ref2 : true,
|
|
218
219
|
closeOnEscape: (_ref3 = (_options$closeOnEscap = options.closeOnEscape) !== null && _options$closeOnEscap !== void 0 ? _options$closeOnEscap : defaults.closeOnEscape) !== null && _ref3 !== void 0 ? _ref3 : true,
|
|
219
220
|
legacy: !!options.legacy,
|
|
221
|
+
skin: options.skin,
|
|
220
222
|
onClickOutside: options.onClickOutside,
|
|
221
223
|
onDismiss: dismiss,
|
|
222
224
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Render, {
|
|
@@ -225,6 +227,7 @@ function EntryView({ entry, depth, topmost }) {
|
|
|
225
227
|
descriptionId,
|
|
226
228
|
title: options.title,
|
|
227
229
|
message: options.message,
|
|
230
|
+
content: options.content,
|
|
228
231
|
buttons: (_options$buttons = options.buttons) !== null && _options$buttons !== void 0 ? _options$buttons : [],
|
|
229
232
|
close,
|
|
230
233
|
dismiss,
|
|
@@ -352,7 +355,7 @@ function closeDialog$1(id, { sync = true } = {}) {
|
|
|
352
355
|
commit(() => store.set(remove(store.get(), id)), sync);
|
|
353
356
|
return;
|
|
354
357
|
}
|
|
355
|
-
Promise.all(exits.map((a) => a.finished)).
|
|
358
|
+
Promise.all(exits.map((a) => a.finished.catch(() => {}))).then(() => store.set(remove(store.get(), id)));
|
|
356
359
|
}
|
|
357
360
|
var reopenQueued = false;
|
|
358
361
|
function reopenClosedFrames() {
|
|
@@ -378,12 +381,15 @@ function animationsOf({ frame, panel }) {
|
|
|
378
381
|
// src/DialogFrame.tsx
|
|
379
382
|
var canShowModal = () => typeof HTMLDialogElement !== "undefined" && typeof HTMLDialogElement.prototype.showModal === "function";
|
|
380
383
|
function DialogFrame(props) {
|
|
381
|
-
var _props$tone, _props$depth, _props$topmost;
|
|
384
|
+
var _props$labelledBy, _props$tone, _props$depth, _props$topmost, _props$labelledBy2;
|
|
382
385
|
const frame = (0, react.useRef)(null);
|
|
383
386
|
const panel = (0, react.useRef)(null);
|
|
384
387
|
const pressedOn = (0, react.useRef)(null);
|
|
385
388
|
const stay = (0, react.useRef)(null);
|
|
386
389
|
const native = props.modal && canShowModal();
|
|
390
|
+
const layoutTitleId = (0, react.useId)();
|
|
391
|
+
const [layoutTitles, setLayoutTitles] = (0, react.useState)(0);
|
|
392
|
+
const labelledBy = (_props$labelledBy = props.labelledBy) !== null && _props$labelledBy !== void 0 ? _props$labelledBy : props.label || layoutTitles === 0 ? void 0 : layoutTitleId;
|
|
387
393
|
(0, react.useLayoutEffect)(() => {
|
|
388
394
|
var _panel$current, _panel$current2, _panel$current3;
|
|
389
395
|
const element = frame.current;
|
|
@@ -444,7 +450,10 @@ function DialogFrame(props) {
|
|
|
444
450
|
const isBusy = () => !!props.id && runtime().busy.has(props.id);
|
|
445
451
|
const onKeyDown = (e) => {
|
|
446
452
|
var _props$onKeyDown;
|
|
447
|
-
(_props$onKeyDown = props.onKeyDown) === null || _props$onKeyDown === void 0 || _props$onKeyDown.call(props, e,
|
|
453
|
+
(_props$onKeyDown = props.onKeyDown) === null || _props$onKeyDown === void 0 || _props$onKeyDown.call(props, e, () => {
|
|
454
|
+
e.preventDefault();
|
|
455
|
+
props.onDismiss();
|
|
456
|
+
});
|
|
448
457
|
if (!native && !props.legacy && e.key === "Escape" && props.closeOnEscape && !isBusy()) props.onDismiss();
|
|
449
458
|
};
|
|
450
459
|
const slot = slotsFor(props.layers);
|
|
@@ -452,11 +461,12 @@ function DialogFrame(props) {
|
|
|
452
461
|
...slot("dialog", props.extraClass),
|
|
453
462
|
role: props.role,
|
|
454
463
|
"aria-label": props.label,
|
|
455
|
-
"aria-labelledby":
|
|
464
|
+
"aria-labelledby": labelledBy,
|
|
456
465
|
"aria-describedby": props.describedBy,
|
|
457
466
|
"data-rca": "",
|
|
458
467
|
"data-state": props.state,
|
|
459
468
|
"data-kind": props.kind,
|
|
469
|
+
"data-skin": props.legacy && !props.skin ? void 0 : "",
|
|
460
470
|
"data-tone": (_props$tone = props.tone) !== null && _props$tone !== void 0 ? _props$tone : "default",
|
|
461
471
|
"data-depth": String((_props$depth = props.depth) !== null && _props$depth !== void 0 ? _props$depth : 0),
|
|
462
472
|
"data-topmost": ((_props$topmost = props.topmost) !== null && _props$topmost !== void 0 ? _props$topmost : true) ? "" : void 0,
|
|
@@ -470,7 +480,14 @@ function DialogFrame(props) {
|
|
|
470
480
|
tabIndex: -1,
|
|
471
481
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SlotContext.Provider, {
|
|
472
482
|
value: slot,
|
|
473
|
-
children:
|
|
483
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FrameContext.Provider, {
|
|
484
|
+
value: {
|
|
485
|
+
id: props.id,
|
|
486
|
+
titleId: (_props$labelledBy2 = props.labelledBy) !== null && _props$labelledBy2 !== void 0 ? _props$labelledBy2 : layoutTitleId,
|
|
487
|
+
countTitle: setLayoutTitles
|
|
488
|
+
},
|
|
489
|
+
children: props.children
|
|
490
|
+
})
|
|
474
491
|
})
|
|
475
492
|
});
|
|
476
493
|
return native ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dialog", {
|
|
@@ -500,7 +517,7 @@ var defaultButtons = [{
|
|
|
500
517
|
function CustomUIHost({ render, args }) {
|
|
501
518
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: render(args) });
|
|
502
519
|
}
|
|
503
|
-
function LegacyContent({ props, titleId, close, id }) {
|
|
520
|
+
function LegacyContent({ props, titleId, close, id, skin }) {
|
|
504
521
|
var _props$buttons;
|
|
505
522
|
const latest = (0, react.useRef)({
|
|
506
523
|
props,
|
|
@@ -514,7 +531,12 @@ function LegacyContent({ props, titleId, close, id }) {
|
|
|
514
531
|
const keyboard = (event) => {
|
|
515
532
|
var _topmost, _props$keyCodeForClos, _props$closeOnEscape, _props$onkeyPress;
|
|
516
533
|
if (id && ((_topmost = topmost(store.get())) === null || _topmost === void 0 ? void 0 : _topmost.id) !== id) return;
|
|
517
|
-
|
|
534
|
+
if (id && runtime().busy.has(id)) return;
|
|
535
|
+
const { props } = latest.current;
|
|
536
|
+
const close = () => {
|
|
537
|
+
event.preventDefault();
|
|
538
|
+
latest.current.close();
|
|
539
|
+
};
|
|
518
540
|
const keyCode = event.keyCode;
|
|
519
541
|
if (((_props$keyCodeForClos = props.keyCodeForClose) !== null && _props$keyCodeForClos !== void 0 ? _props$keyCodeForClos : []).includes(keyCode)) close();
|
|
520
542
|
if (((_props$closeOnEscape = props.closeOnEscape) !== null && _props$closeOnEscape !== void 0 ? _props$closeOnEscape : true) && keyCode === 27) {
|
|
@@ -528,17 +550,30 @@ function LegacyContent({ props, titleId, close, id }) {
|
|
|
528
550
|
return () => document.removeEventListener("keydown", keyboard, false);
|
|
529
551
|
}, []);
|
|
530
552
|
const slot = useSlot();
|
|
553
|
+
const frame = (0, react.useContext)(FrameContext);
|
|
531
554
|
const { title, message, customUI, childrenElement } = props;
|
|
532
555
|
const buttons = (_props$buttons = props.buttons) !== null && _props$buttons !== void 0 ? _props$buttons : defaultButtons;
|
|
533
|
-
if (customUI)
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
556
|
+
if (customUI) {
|
|
557
|
+
const ui = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CustomUIHost, {
|
|
558
|
+
render: customUI,
|
|
559
|
+
args: {
|
|
560
|
+
title,
|
|
561
|
+
message,
|
|
562
|
+
buttons,
|
|
563
|
+
onClose: close
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
return skin ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
567
|
+
...slot("body"),
|
|
568
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FrameContext.Provider, {
|
|
569
|
+
value: {
|
|
570
|
+
...frame,
|
|
571
|
+
inBody: true
|
|
572
|
+
},
|
|
573
|
+
children: ui
|
|
574
|
+
})
|
|
575
|
+
}) : ui;
|
|
576
|
+
}
|
|
542
577
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
543
578
|
...slot("body"),
|
|
544
579
|
children: [
|
|
@@ -565,19 +600,21 @@ function LegacyContent({ props, titleId, close, id }) {
|
|
|
565
600
|
});
|
|
566
601
|
}
|
|
567
602
|
function confirmAlert(properties) {
|
|
568
|
-
var _ref, _properties$
|
|
603
|
+
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;
|
|
604
|
+
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;
|
|
569
605
|
function Content({ id, titleId, dismiss }) {
|
|
570
606
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LegacyContent, {
|
|
571
607
|
props: properties,
|
|
572
608
|
titleId,
|
|
573
609
|
close: dismiss,
|
|
574
|
-
id
|
|
610
|
+
id,
|
|
611
|
+
skin
|
|
575
612
|
});
|
|
576
613
|
}
|
|
577
614
|
openEntry({
|
|
578
615
|
kind: "custom",
|
|
579
616
|
title: properties.title,
|
|
580
|
-
modal: (
|
|
617
|
+
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,
|
|
581
618
|
unstyled: properties.unstyled,
|
|
582
619
|
classNames: properties.classNames,
|
|
583
620
|
closeOnClickOutside: (_properties$closeOnCl = properties.closeOnClickOutside) !== null && _properties$closeOnCl !== void 0 ? _properties$closeOnCl : true,
|
|
@@ -585,18 +622,20 @@ function confirmAlert(properties) {
|
|
|
585
622
|
overlayClassName: properties.overlayClassName,
|
|
586
623
|
onClickOutside: properties.onClickOutside,
|
|
587
624
|
legacy: true,
|
|
625
|
+
skin,
|
|
588
626
|
willUnmount: properties.willUnmount,
|
|
589
627
|
afterClose: properties.afterClose,
|
|
590
628
|
render: Content
|
|
591
|
-
}, (_properties$targetId = properties.targetId) !== null && _properties$targetId !== void 0 ? _properties$targetId : null, (
|
|
629
|
+
}, (_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");
|
|
592
630
|
}
|
|
593
631
|
function DeclarativeDialog(props) {
|
|
594
|
-
var _props$modal, _props$closeOnClickOu, _props$closeOnEscape2;
|
|
632
|
+
var _ref4, _props$skin, _runtime$defaults$con4, _props$modal, _props$closeOnClickOu, _props$closeOnEscape2;
|
|
595
633
|
const titleId = (0, react.useId)();
|
|
596
634
|
const close = () => {
|
|
597
635
|
var _props$afterClose;
|
|
598
636
|
return (_props$afterClose = props.afterClose) === null || _props$afterClose === void 0 ? void 0 : _props$afterClose.call(props);
|
|
599
637
|
};
|
|
638
|
+
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;
|
|
600
639
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogFrame, {
|
|
601
640
|
modal: (_props$modal = props.modal) !== null && _props$modal !== void 0 ? _props$modal : false,
|
|
602
641
|
state: "open",
|
|
@@ -610,13 +649,15 @@ function DeclarativeDialog(props) {
|
|
|
610
649
|
closeOnClickOutside: (_props$closeOnClickOu = props.closeOnClickOutside) !== null && _props$closeOnClickOu !== void 0 ? _props$closeOnClickOu : true,
|
|
611
650
|
closeOnEscape: (_props$closeOnEscape2 = props.closeOnEscape) !== null && _props$closeOnEscape2 !== void 0 ? _props$closeOnEscape2 : true,
|
|
612
651
|
legacy: true,
|
|
652
|
+
skin,
|
|
613
653
|
role: "dialog",
|
|
614
654
|
onClickOutside: props.onClickOutside,
|
|
615
655
|
onDismiss: close,
|
|
616
656
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LegacyContent, {
|
|
617
657
|
props,
|
|
618
658
|
titleId,
|
|
619
|
-
close
|
|
659
|
+
close,
|
|
660
|
+
skin
|
|
620
661
|
})
|
|
621
662
|
});
|
|
622
663
|
}
|
|
@@ -667,6 +708,7 @@ function open(options, dismissValue, body) {
|
|
|
667
708
|
}
|
|
668
709
|
function Body({ props, children }) {
|
|
669
710
|
const slot = useSlot();
|
|
711
|
+
const frame = (0, react.useContext)(FrameContext);
|
|
670
712
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
671
713
|
...slot("body"),
|
|
672
714
|
children: [
|
|
@@ -675,22 +717,42 @@ function Body({ props, children }) {
|
|
|
675
717
|
...slot("title"),
|
|
676
718
|
children: props.title
|
|
677
719
|
}),
|
|
678
|
-
props.message != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
720
|
+
props.message != null && (typeof props.message === "object" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
721
|
+
id: props.descriptionId,
|
|
722
|
+
...slot("message"),
|
|
723
|
+
children: props.message
|
|
724
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
679
725
|
id: props.descriptionId,
|
|
680
726
|
...slot("message"),
|
|
681
727
|
children: props.message
|
|
728
|
+
})),
|
|
729
|
+
props.content != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FrameContext.Provider, {
|
|
730
|
+
value: {
|
|
731
|
+
...frame,
|
|
732
|
+
inBody: true
|
|
733
|
+
},
|
|
734
|
+
children: props.content
|
|
682
735
|
}),
|
|
683
736
|
children
|
|
684
737
|
]
|
|
685
738
|
});
|
|
686
739
|
}
|
|
687
|
-
function
|
|
688
|
-
const slot = useSlot();
|
|
740
|
+
function useBusy(id) {
|
|
689
741
|
const [busy, setBusy] = (0, react.useState)(null);
|
|
690
|
-
const
|
|
691
|
-
|
|
692
|
-
|
|
742
|
+
const mark = (index) => {
|
|
743
|
+
if (id) {
|
|
744
|
+
var _runtime$frames$get;
|
|
745
|
+
(_runtime$frames$get = runtime().frames.get(id)) === null || _runtime$frames$get === void 0 || _runtime$frames$get.frame.toggleAttribute("data-busy", index !== null);
|
|
746
|
+
if (index === null) runtime().busy.delete(id);
|
|
747
|
+
else runtime().busy.add(id);
|
|
748
|
+
}
|
|
749
|
+
setBusy(index);
|
|
693
750
|
};
|
|
751
|
+
return [busy, mark];
|
|
752
|
+
}
|
|
753
|
+
function Buttons({ props, signal: getSignal, focus }) {
|
|
754
|
+
const slot = useSlot();
|
|
755
|
+
const [busy, setBusy] = useBusy(props.id);
|
|
694
756
|
const press = async (button, index) => {
|
|
695
757
|
const signal = getSignal();
|
|
696
758
|
let waiting = false;
|
|
@@ -707,16 +769,11 @@ function Buttons({ props, signal: getSignal, focus }) {
|
|
|
707
769
|
}
|
|
708
770
|
waiting = true;
|
|
709
771
|
setBusy(index);
|
|
710
|
-
markBusy(true);
|
|
711
|
-
runtime().busy.add(props.id);
|
|
712
772
|
if (await outcome !== false && !signal.aborted) props.close(button.value);
|
|
713
773
|
} catch (error) {
|
|
714
774
|
console.error(error);
|
|
715
775
|
} finally {
|
|
716
|
-
if (
|
|
717
|
-
runtime().busy.delete(props.id);
|
|
718
|
-
markBusy(false);
|
|
719
|
-
if (!signal.aborted) setBusy(null);
|
|
776
|
+
if (waiting) setBusy(null);
|
|
720
777
|
}
|
|
721
778
|
};
|
|
722
779
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -988,6 +1045,7 @@ function ConfirmDialog(props) {
|
|
|
988
1045
|
descriptionId,
|
|
989
1046
|
title: props.title,
|
|
990
1047
|
message: props.message,
|
|
1048
|
+
content: props.content,
|
|
991
1049
|
dismiss: hide,
|
|
992
1050
|
onClose: hide
|
|
993
1051
|
};
|
|
@@ -1059,9 +1117,59 @@ function ConfirmDialog(props) {
|
|
|
1059
1117
|
children: body
|
|
1060
1118
|
});
|
|
1061
1119
|
}
|
|
1120
|
+
// src/DialogLayout.tsx
|
|
1121
|
+
/** The default dialog layout for your own content: title, message, your children, then the actions. */
|
|
1122
|
+
function DialogLayout({ title, message, actions, children }) {
|
|
1123
|
+
const slot = useSlot();
|
|
1124
|
+
const frame = (0, react.useContext)(FrameContext);
|
|
1125
|
+
const [busy, setBusy] = useBusy(frame.id);
|
|
1126
|
+
const hasTitle = title != null;
|
|
1127
|
+
const { countTitle } = frame;
|
|
1128
|
+
(0, react.useLayoutEffect)(() => {
|
|
1129
|
+
if (!hasTitle || !countTitle) return;
|
|
1130
|
+
countTitle((n) => n + 1);
|
|
1131
|
+
return () => countTitle((n) => n - 1);
|
|
1132
|
+
}, [hasTitle, countTitle]);
|
|
1133
|
+
const Body = frame.inBody ? react.Fragment : "div";
|
|
1134
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Body, {
|
|
1135
|
+
...frame.inBody ? {} : slot("body"),
|
|
1136
|
+
children: [
|
|
1137
|
+
title != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
1138
|
+
id: frame.titleId,
|
|
1139
|
+
...slot("title"),
|
|
1140
|
+
children: title
|
|
1141
|
+
}),
|
|
1142
|
+
message != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1143
|
+
...slot("message"),
|
|
1144
|
+
children: message
|
|
1145
|
+
}),
|
|
1146
|
+
children,
|
|
1147
|
+
actions && actions.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1148
|
+
...slot("actions"),
|
|
1149
|
+
children: actions.map(({ label, variant = "secondary", onClick, disabled, className, ...rest }, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1150
|
+
type: "button",
|
|
1151
|
+
...rest,
|
|
1152
|
+
...slot("button", className),
|
|
1153
|
+
"data-variant": variant,
|
|
1154
|
+
"data-busy": busy === i ? "" : void 0,
|
|
1155
|
+
"aria-busy": busy === i || void 0,
|
|
1156
|
+
disabled: disabled || busy !== null,
|
|
1157
|
+
onClick: (event) => {
|
|
1158
|
+
const outcome = onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
|
1159
|
+
if (!(outcome instanceof Promise)) return;
|
|
1160
|
+
setBusy(i);
|
|
1161
|
+
outcome.catch((error) => console.error(error)).finally(() => setBusy(null));
|
|
1162
|
+
},
|
|
1163
|
+
children: label
|
|
1164
|
+
}, i))
|
|
1165
|
+
})
|
|
1166
|
+
]
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1062
1169
|
exports.ConfirmDialog = ConfirmDialog;
|
|
1063
1170
|
exports.Dialog = Dialog;
|
|
1064
1171
|
exports.DialogHost = DialogHost;
|
|
1172
|
+
exports.DialogLayout = DialogLayout;
|
|
1065
1173
|
exports.alert = alert;
|
|
1066
1174
|
exports.closeAll = closeAll;
|
|
1067
1175
|
exports.closeDialog = closeDialog;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-confirm-alert",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "react component confirm dialog.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"react": "^18.1.0",
|
|
62
62
|
"react-dom": "^18.1.0",
|
|
63
63
|
"size-limit": "^14.3.0",
|
|
64
|
+
"tailwindcss": "^4.3.3",
|
|
64
65
|
"typescript": "^7.0.2",
|
|
65
66
|
"vite": "^8.3.5",
|
|
66
67
|
"vitest": "^5.0.5"
|
|
@@ -32,6 +32,8 @@ body.react-confirm-alert-body-element {
|
|
|
32
32
|
border-radius: var(--rca-radius, 10px);
|
|
33
33
|
box-shadow: var(--rca-shadow, 0 20px 75px rgba(0, 0, 0, 0.13));
|
|
34
34
|
color: var(--rca-fg, #666);
|
|
35
|
+
/* confirmAlert renders message as text right in the body; keep its line breaks (#38). */
|
|
36
|
+
white-space: pre-line;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
.react-confirm-alert-body > h1 {
|
|
@@ -125,3 +127,234 @@ dialog.react-confirm-alert-overlay::backdrop {
|
|
|
125
127
|
opacity: 1;
|
|
126
128
|
}
|
|
127
129
|
}
|
|
130
|
+
|
|
131
|
+
/* The default look of every dialog except confirmAlert, which has no data-skin and keeps the 3.0 look above; unstyled drops the overlay class, so none of this applies.
|
|
132
|
+
--_* are internal defaults: a --rca-* variable set by the app always wins over them. */
|
|
133
|
+
.react-confirm-alert-overlay[data-skin] {
|
|
134
|
+
--_bg: #fff;
|
|
135
|
+
--_fg: #71717a;
|
|
136
|
+
--_title: #09090b;
|
|
137
|
+
--_border: #e4e4e7;
|
|
138
|
+
--_hover: #f4f4f5;
|
|
139
|
+
--_primary: #18181b;
|
|
140
|
+
--_primary-fg: #fff;
|
|
141
|
+
--_ring: #a1a1aa;
|
|
142
|
+
--_danger: #dc2626;
|
|
143
|
+
--_error: #dc2626;
|
|
144
|
+
box-sizing: border-box;
|
|
145
|
+
padding: 16px;
|
|
146
|
+
background: var(--rca-backdrop, rgba(0, 0, 0, 0.5));
|
|
147
|
+
opacity: 1;
|
|
148
|
+
animation: rca-in var(--rca-duration, 200ms) var(--rca-easing, cubic-bezier(0.32, 0.72, 0, 1)) both;
|
|
149
|
+
}
|
|
150
|
+
/* Dark is opt-in: the app's .dark class or data-theme="dark" on an ancestor, usually <html>. */
|
|
151
|
+
:is(.dark, [data-theme=dark]) .react-confirm-alert-overlay[data-skin] {
|
|
152
|
+
--_bg: #18181b;
|
|
153
|
+
--_fg: #a1a1aa;
|
|
154
|
+
--_title: #fafafa;
|
|
155
|
+
--_border: #3f3f46;
|
|
156
|
+
--_hover: #27272a;
|
|
157
|
+
--_primary: #fafafa;
|
|
158
|
+
--_primary-fg: #18181b;
|
|
159
|
+
--_ring: #71717a;
|
|
160
|
+
--_error: #f87171;
|
|
161
|
+
color-scheme: dark;
|
|
162
|
+
background: var(--rca-backdrop, rgba(0, 0, 0, 0.7));
|
|
163
|
+
}
|
|
164
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert {
|
|
165
|
+
max-width: 100%;
|
|
166
|
+
animation: rca-pop var(--rca-duration, 200ms) var(--rca-easing, cubic-bezier(0.32, 0.72, 0, 1)) both;
|
|
167
|
+
}
|
|
168
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-body {
|
|
169
|
+
box-sizing: border-box;
|
|
170
|
+
width: var(--rca-width, 420px);
|
|
171
|
+
max-width: 100%;
|
|
172
|
+
padding: var(--rca-padding, 24px);
|
|
173
|
+
border: 1px solid var(--rca-border, var(--_border));
|
|
174
|
+
border-radius: var(--rca-radius, 10px);
|
|
175
|
+
background: var(--rca-bg, var(--_bg));
|
|
176
|
+
box-shadow: var(--rca-shadow, 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1));
|
|
177
|
+
color: var(--rca-fg, var(--_fg));
|
|
178
|
+
font-family: var(--rca-font, inherit);
|
|
179
|
+
font-size: 14px;
|
|
180
|
+
line-height: 1.5;
|
|
181
|
+
}
|
|
182
|
+
.react-confirm-alert-overlay[data-skin][data-state=closing] {
|
|
183
|
+
animation: rca-out 150ms ease-in both;
|
|
184
|
+
}
|
|
185
|
+
.react-confirm-alert-overlay[data-skin][data-state=closing] .react-confirm-alert {
|
|
186
|
+
animation: rca-pop-out 150ms ease-in both;
|
|
187
|
+
}
|
|
188
|
+
/* Plain elements inside a skinned dialog look like the slots. Their selectors are type selectors under
|
|
189
|
+
:where(), so they beat a CSS reset such as Tailwind preflight and lose to any class you add. */
|
|
190
|
+
.react-confirm-alert-overlay[data-skin] [data-slot=title],
|
|
191
|
+
:where(.react-confirm-alert-overlay[data-skin]) div :is(h1, h2, h3) {
|
|
192
|
+
margin: 0 0 8px;
|
|
193
|
+
font-size: 18px;
|
|
194
|
+
font-weight: 600;
|
|
195
|
+
line-height: 1.3;
|
|
196
|
+
letter-spacing: -0.01em;
|
|
197
|
+
color: var(--rca-title, var(--_title));
|
|
198
|
+
}
|
|
199
|
+
.react-confirm-alert-overlay[data-skin] [data-slot=field] {
|
|
200
|
+
margin-top: 16px;
|
|
201
|
+
}
|
|
202
|
+
.react-confirm-alert-overlay[data-skin] [data-slot=label],
|
|
203
|
+
:where(.react-confirm-alert-overlay[data-skin]) div label {
|
|
204
|
+
display: block;
|
|
205
|
+
margin-bottom: 6px;
|
|
206
|
+
font-size: 13px;
|
|
207
|
+
font-weight: 500;
|
|
208
|
+
color: var(--rca-title, var(--_title));
|
|
209
|
+
}
|
|
210
|
+
.react-confirm-alert-overlay[data-skin] [data-slot=input],
|
|
211
|
+
:where(.react-confirm-alert-overlay[data-skin]) div :is(input:where(:not([type=checkbox], [type=radio], [type=range], [type=file], [type=color], [type=submit], [type=button], [type=reset], [type=image])), textarea, select) {
|
|
212
|
+
display: block;
|
|
213
|
+
box-sizing: border-box;
|
|
214
|
+
width: 100%;
|
|
215
|
+
height: 36px;
|
|
216
|
+
padding: 0 12px;
|
|
217
|
+
border: 1px solid var(--rca-border, var(--_border));
|
|
218
|
+
border-radius: 6px;
|
|
219
|
+
background: transparent;
|
|
220
|
+
color: var(--rca-title, var(--_title));
|
|
221
|
+
font: inherit;
|
|
222
|
+
outline: none;
|
|
223
|
+
transition: border-color 150ms, box-shadow 150ms;
|
|
224
|
+
}
|
|
225
|
+
.react-confirm-alert-overlay[data-skin] textarea[data-slot=input],
|
|
226
|
+
:where(.react-confirm-alert-overlay[data-skin]) div textarea {
|
|
227
|
+
height: auto;
|
|
228
|
+
min-height: 80px;
|
|
229
|
+
padding: 8px 12px;
|
|
230
|
+
resize: vertical;
|
|
231
|
+
}
|
|
232
|
+
.react-confirm-alert-overlay[data-skin] [data-slot=input]:focus,
|
|
233
|
+
:where(.react-confirm-alert-overlay[data-skin]) div :is(input, textarea, select):where(:focus) {
|
|
234
|
+
border-color: var(--rca-ring, var(--_ring));
|
|
235
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--rca-ring, var(--_ring)) 50%, transparent);
|
|
236
|
+
}
|
|
237
|
+
.react-confirm-alert-overlay[data-skin] [data-slot=input][aria-invalid=true],
|
|
238
|
+
:where(.react-confirm-alert-overlay[data-skin]) div :is(input, textarea, select):where([aria-invalid=true]) {
|
|
239
|
+
border-color: var(--rca-danger, var(--_error));
|
|
240
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--rca-danger, var(--_error)) 20%, transparent);
|
|
241
|
+
}
|
|
242
|
+
:where(.react-confirm-alert-overlay[data-skin]) div p {
|
|
243
|
+
margin: 0;
|
|
244
|
+
}
|
|
245
|
+
:where(.react-confirm-alert-overlay[data-skin]) div input:where([type=checkbox], [type=radio]) {
|
|
246
|
+
accent-color: var(--rca-button-bg, var(--_primary));
|
|
247
|
+
}
|
|
248
|
+
:where(.react-confirm-alert-overlay[data-skin]) div * + :is(p, label, input, textarea, select) {
|
|
249
|
+
margin-top: 12px;
|
|
250
|
+
}
|
|
251
|
+
:where(.react-confirm-alert-overlay[data-skin]) div label + :is(input, textarea, select) {
|
|
252
|
+
margin-top: 0;
|
|
253
|
+
}
|
|
254
|
+
.react-confirm-alert-overlay[data-skin] [data-slot=error] {
|
|
255
|
+
margin: 6px 0 0;
|
|
256
|
+
font-size: 13px;
|
|
257
|
+
color: var(--rca-danger, var(--_error));
|
|
258
|
+
}
|
|
259
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group {
|
|
260
|
+
justify-content: flex-end;
|
|
261
|
+
gap: var(--rca-gap, 8px);
|
|
262
|
+
margin-top: 24px;
|
|
263
|
+
}
|
|
264
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > button,
|
|
265
|
+
:where(.react-confirm-alert-overlay[data-skin]) div button {
|
|
266
|
+
display: inline-flex;
|
|
267
|
+
align-items: center;
|
|
268
|
+
justify-content: center;
|
|
269
|
+
gap: 8px;
|
|
270
|
+
height: 36px;
|
|
271
|
+
margin: 0;
|
|
272
|
+
padding: 0 16px;
|
|
273
|
+
border: 1px solid var(--rca-border, var(--_border));
|
|
274
|
+
border-radius: var(--rca-button-radius, 6px);
|
|
275
|
+
background: var(--rca-bg, var(--_bg));
|
|
276
|
+
color: var(--rca-title, var(--_title));
|
|
277
|
+
font-family: inherit;
|
|
278
|
+
font-size: 14px;
|
|
279
|
+
font-weight: 500;
|
|
280
|
+
line-height: 1;
|
|
281
|
+
white-space: nowrap;
|
|
282
|
+
transition: background-color 150ms, transform 150ms;
|
|
283
|
+
}
|
|
284
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > [data-variant=primary],
|
|
285
|
+
:where(.react-confirm-alert-overlay[data-skin]) div button:where([data-variant=primary]) {
|
|
286
|
+
border-color: transparent;
|
|
287
|
+
background: var(--rca-button-bg, var(--_primary));
|
|
288
|
+
color: var(--rca-button-fg, var(--_primary-fg));
|
|
289
|
+
}
|
|
290
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > [data-variant=danger],
|
|
291
|
+
:where(.react-confirm-alert-overlay[data-skin]) div button:where([data-variant=danger]) {
|
|
292
|
+
border-color: transparent;
|
|
293
|
+
background: var(--rca-danger, var(--_danger));
|
|
294
|
+
color: #fff;
|
|
295
|
+
}
|
|
296
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > :not([data-variant=primary],[data-variant=danger]):enabled:hover,
|
|
297
|
+
:where(.react-confirm-alert-overlay[data-skin]) div button:where(:not([data-variant=primary],[data-variant=danger]):enabled:hover) {
|
|
298
|
+
background: var(--_hover);
|
|
299
|
+
}
|
|
300
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > [data-variant=primary]:enabled:hover,
|
|
301
|
+
:where(.react-confirm-alert-overlay[data-skin]) div button:where([data-variant=primary]:enabled:hover) {
|
|
302
|
+
background: var(--rca-button-bg-hover, color-mix(in srgb, var(--rca-button-bg, var(--_primary)) 85%, #000));
|
|
303
|
+
}
|
|
304
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > [data-variant=danger]:enabled:hover,
|
|
305
|
+
:where(.react-confirm-alert-overlay[data-skin]) div button:where([data-variant=danger]:enabled:hover) {
|
|
306
|
+
background: var(--rca-danger-hover, color-mix(in srgb, var(--rca-danger, var(--_danger)) 85%, #000));
|
|
307
|
+
}
|
|
308
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > button:active,
|
|
309
|
+
:where(.react-confirm-alert-overlay[data-skin]) div button:where(:active) {
|
|
310
|
+
transform: scale(0.97);
|
|
311
|
+
}
|
|
312
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > button:focus-visible,
|
|
313
|
+
:where(.react-confirm-alert-overlay[data-skin]) div button:where(:focus-visible) {
|
|
314
|
+
outline: var(--rca-focus-ring, 2px solid var(--_ring));
|
|
315
|
+
outline-offset: 2px;
|
|
316
|
+
}
|
|
317
|
+
/* Not faded: white on a faded red is below 4.5:1. */
|
|
318
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > button:disabled:not([aria-busy=true]),
|
|
319
|
+
:where(.react-confirm-alert-overlay[data-skin]) div button:where(:disabled:not([aria-busy=true])) {
|
|
320
|
+
cursor: default;
|
|
321
|
+
border-color: var(--rca-border, var(--_border));
|
|
322
|
+
background: var(--rca-bg, var(--_bg));
|
|
323
|
+
color: var(--rca-fg, var(--_fg));
|
|
324
|
+
}
|
|
325
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > button[aria-busy=true],
|
|
326
|
+
:where(.react-confirm-alert-overlay[data-skin]) div button:where([aria-busy=true]) {
|
|
327
|
+
cursor: progress;
|
|
328
|
+
}
|
|
329
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > button[aria-busy=true]::before,
|
|
330
|
+
:where(.react-confirm-alert-overlay[data-skin]) div button:where([aria-busy=true])::before {
|
|
331
|
+
content: '';
|
|
332
|
+
width: 12px;
|
|
333
|
+
height: 12px;
|
|
334
|
+
border: 2px solid currentColor;
|
|
335
|
+
border-right-color: transparent;
|
|
336
|
+
border-radius: 50%;
|
|
337
|
+
animation: rca-spin 700ms linear infinite;
|
|
338
|
+
}
|
|
339
|
+
@media (max-width: 480px) {
|
|
340
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group {
|
|
341
|
+
flex-direction: column-reverse;
|
|
342
|
+
}
|
|
343
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > button {
|
|
344
|
+
height: 40px;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
@media (prefers-reduced-motion: reduce) {
|
|
348
|
+
.react-confirm-alert-overlay[data-skin],
|
|
349
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert {
|
|
350
|
+
animation: none;
|
|
351
|
+
}
|
|
352
|
+
.react-confirm-alert-overlay[data-skin] .react-confirm-alert-button-group > button {
|
|
353
|
+
transition: none;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
@keyframes rca-in { from { opacity: 0; } }
|
|
357
|
+
@keyframes rca-out { to { opacity: 0; } }
|
|
358
|
+
@keyframes rca-pop { from { opacity: 0; transform: scale(0.95); } }
|
|
359
|
+
@keyframes rca-pop-out { to { opacity: 0; transform: scale(0.95); } }
|
|
360
|
+
@keyframes rca-spin { to { transform: rotate(360deg); } }
|