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/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)).finally(() => store.set(remove(store.get(), id)));
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, props.onDismiss);
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": props.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: props.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
- const { props, close } = latest.current;
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) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CustomUIHost, {
534
- render: customUI,
535
- args: {
536
- title,
537
- message,
538
- buttons,
539
- onClose: close
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$modal, _runtime$defaults$con, _properties$closeOnCl, _properties$closeOnEs, _properties$targetId, _ref2, _properties$strategy, _runtime$defaults$con2;
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: (_ref = (_properties$modal = properties.modal) !== null && _properties$modal !== void 0 ? _properties$modal : (_runtime$defaults$con = runtime().defaults.confirmAlert) === null || _runtime$defaults$con === void 0 ? void 0 : _runtime$defaults$con.modal) !== null && _ref !== void 0 ? _ref : false,
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, (_ref2 = (_properties$strategy = properties.strategy) !== null && _properties$strategy !== void 0 ? _properties$strategy : (_runtime$defaults$con2 = runtime().defaults.confirmAlert) === null || _runtime$defaults$con2 === void 0 ? void 0 : _runtime$defaults$con2.strategy) !== null && _ref2 !== void 0 ? _ref2 : "replace");
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)("p", {
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 Buttons({ props, signal: getSignal, focus }) {
688
- const slot = useSlot();
740
+ function useBusy(id) {
689
741
  const [busy, setBusy] = (0, react.useState)(null);
690
- const markBusy = (on) => {
691
- var _runtime$frames$get;
692
- return (_runtime$frames$get = runtime().frames.get(props.id)) === null || _runtime$frames$get === void 0 ? void 0 : _runtime$frames$get.frame.toggleAttribute("data-busy", on);
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 (!waiting) return;
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.1.1",
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); } }