@nobertdev/react-confirm-dialog 1.0.0 → 1.1.1

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 CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  A lightweight, fully customizable confirmation dialog hook — `useConfirm()` — that replaces `window.confirm()` with beautiful async modals.
4
4
 
5
- **Zero runtime dependencies. ~2KB gzipped. Full TypeScript support.**
5
+ **Zero runtime dependencies. ~2KB gzipped. Full TypeScript support. Auto dark mode.**
6
+
7
+ 📺 **[Live Demo](https://react-confirm-dialog.vercel.app/)** · 📖 **[Documentation](https://react-confirm-dialog.vercel.app/docs)** · 💻 **[GitHub](https://github.com/NOBERT167/react-confirm-dialog)**
6
8
 
7
9
  ---
8
10
 
@@ -10,6 +12,7 @@ A lightweight, fully customizable confirmation dialog hook — `useConfirm()`
10
12
 
11
13
  - ✅ Drop-in async replacement for `window.confirm()`
12
14
  - 🎨 Four built-in variants: `default`, `danger`, `warning`, `success`
15
+ - 🌗 Auto dark mode — adapts to `prefers-color-scheme` automatically
13
16
  - 🧩 Fully customizable via props, classNames, styles, or `renderDialog`
14
17
  - ⌨️ Keyboard accessible (Escape to cancel, auto-focus confirm)
15
18
  - 🖱️ Click outside to dismiss
@@ -201,6 +204,17 @@ await confirm({ title: "Publish post?", variant: "success" });
201
204
 
202
205
  ---
203
206
 
207
+ ## Dark Mode
208
+
209
+ The built-in dialog **automatically adapts** to the user's system color scheme via `prefers-color-scheme: dark`. No configuration needed — it just works.
210
+
211
+ - Light mode: White dialog, light icon backgrounds, subtle shadows
212
+ - Dark mode: Dark gray dialog, muted icon backgrounds, deeper shadows
213
+
214
+ If you use `renderDialog` or custom `styles`, you have full control over theming.
215
+
216
+ ---
217
+
204
218
  ## SSR / Next.js
205
219
 
206
220
  Works with SSR out of the box. The portal is only created on the client.
package/dist/index.js CHANGED
@@ -55,28 +55,36 @@ var VARIANT_STYLES = {
55
55
  confirmColor: "#fff",
56
56
  confirmHover: "#333",
57
57
  accentColor: "#111",
58
- iconBg: "#f4f4f4"
58
+ accentColorDark: "#e5e5e5",
59
+ iconBg: "#f4f4f4",
60
+ iconBgDark: "#2c2c2e"
59
61
  },
60
62
  danger: {
61
63
  confirmBg: "#dc2626",
62
64
  confirmColor: "#fff",
63
65
  confirmHover: "#b91c1c",
64
66
  accentColor: "#dc2626",
65
- iconBg: "#fef2f2"
67
+ accentColorDark: "#f87171",
68
+ iconBg: "#fef2f2",
69
+ iconBgDark: "#3b1114"
66
70
  },
67
71
  warning: {
68
72
  confirmBg: "#d97706",
69
73
  confirmColor: "#fff",
70
74
  confirmHover: "#b45309",
71
75
  accentColor: "#d97706",
72
- iconBg: "#fffbeb"
76
+ accentColorDark: "#fbbf24",
77
+ iconBg: "#fffbeb",
78
+ iconBgDark: "#3b2a0a"
73
79
  },
74
80
  success: {
75
81
  confirmBg: "#16a34a",
76
82
  confirmColor: "#fff",
77
83
  confirmHover: "#15803d",
78
84
  accentColor: "#16a34a",
79
- iconBg: "#f0fdf4"
85
+ accentColorDark: "#4ade80",
86
+ iconBg: "#f0fdf4",
87
+ iconBgDark: "#0a2e1a"
80
88
  }
81
89
  };
82
90
  var DEFAULT_ICONS = {
@@ -175,7 +183,8 @@ function BuiltInDialog({
175
183
  providerProps,
176
184
  onConfirm,
177
185
  onCancel,
178
- isClosing
186
+ isClosing,
187
+ isDark
179
188
  }) {
180
189
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
181
190
  const confirmRef = (0, import_react.useRef)(null);
@@ -202,7 +211,7 @@ function BuiltInDialog({
202
211
  const overlayStyle = __spreadValues({
203
212
  position: "fixed",
204
213
  inset: 0,
205
- background: "rgba(0,0,0,0.45)",
214
+ background: isDark ? "rgba(0,0,0,0.6)" : "rgba(0,0,0,0.45)",
206
215
  backdropFilter: "blur(4px)",
207
216
  WebkitBackdropFilter: "blur(4px)",
208
217
  display: "flex",
@@ -213,12 +222,13 @@ function BuiltInDialog({
213
222
  animation: `rcd-overlay-${animationState} 200ms ease forwards`
214
223
  }, (_b = providerProps.styles) == null ? void 0 : _b.overlay);
215
224
  const dialogStyle = __spreadValues({
216
- background: "#fff",
225
+ background: isDark ? "#1c1c1e" : "#fff",
217
226
  borderRadius: "16px",
218
227
  padding: "28px",
219
228
  maxWidth: "420px",
220
229
  width: "100%",
221
- boxShadow: "0 24px 64px rgba(0,0,0,0.18), 0 4px 12px rgba(0,0,0,0.08)",
230
+ boxShadow: isDark ? "0 24px 64px rgba(0,0,0,0.4), 0 4px 12px rgba(0,0,0,0.3)" : "0 24px 64px rgba(0,0,0,0.18), 0 4px 12px rgba(0,0,0,0.08)",
231
+ border: isDark ? "1px solid rgba(255,255,255,0.08)" : "none",
222
232
  position: "relative",
223
233
  animation: `rcd-dialog-${animationState} 220ms cubic-bezier(0.34,1.56,0.64,1) forwards`
224
234
  }, (_c = providerProps.styles) == null ? void 0 : _c.dialog);
@@ -226,8 +236,8 @@ function BuiltInDialog({
226
236
  width: 48,
227
237
  height: 48,
228
238
  borderRadius: "12px",
229
- background: v.iconBg,
230
- color: v.accentColor,
239
+ background: isDark ? v.iconBgDark : v.iconBg,
240
+ color: isDark ? v.accentColorDark : v.accentColor,
231
241
  display: "flex",
232
242
  alignItems: "center",
233
243
  justifyContent: "center",
@@ -238,7 +248,7 @@ function BuiltInDialog({
238
248
  margin: "0 0 6px 0",
239
249
  fontSize: "17px",
240
250
  fontWeight: 700,
241
- color: "#0f0f0f",
251
+ color: isDark ? "#f5f5f5" : "#0f0f0f",
242
252
  lineHeight: 1.3,
243
253
  letterSpacing: "-0.02em",
244
254
  fontFamily: "inherit"
@@ -246,7 +256,7 @@ function BuiltInDialog({
246
256
  const messageStyle = __spreadValues({
247
257
  margin: "0 0 24px 0",
248
258
  fontSize: "14px",
249
- color: "#6b7280",
259
+ color: isDark ? "#a1a1aa" : "#6b7280",
250
260
  lineHeight: 1.6,
251
261
  fontFamily: "inherit"
252
262
  }, (_e = providerProps.styles) == null ? void 0 : _e.message);
@@ -255,12 +265,13 @@ function BuiltInDialog({
255
265
  gap: "10px",
256
266
  justifyContent: "flex-end"
257
267
  }, (_f = providerProps.styles) == null ? void 0 : _f.actions);
268
+ const cancelBg = isDark ? "#2c2c2e" : "#fff";
258
269
  const cancelStyle = __spreadValues({
259
270
  padding: "9px 18px",
260
271
  borderRadius: "9px",
261
- border: "1.5px solid #e5e7eb",
262
- background: "#fff",
263
- color: "#374151",
272
+ border: isDark ? "1.5px solid #3a3a3c" : "1.5px solid #e5e7eb",
273
+ background: cancelBg,
274
+ color: isDark ? "#e5e5e5" : "#374151",
264
275
  fontSize: "14px",
265
276
  fontWeight: 500,
266
277
  cursor: "pointer",
@@ -325,11 +336,11 @@ function BuiltInDialog({
325
336
  className: (_p = providerProps.classNames) == null ? void 0 : _p.cancelButton,
326
337
  onClick: onCancel,
327
338
  onMouseEnter: (e) => {
328
- e.target.style.background = "#f9fafb";
339
+ e.target.style.background = isDark ? "#3a3a3c" : "#f9fafb";
329
340
  },
330
341
  onMouseLeave: (e) => {
331
342
  var _a2, _b2, _c2, _d2;
332
- e.target.style.background = (_d2 = (_c2 = (_b2 = (_a2 = providerProps.styles) == null ? void 0 : _a2.cancelButton) == null ? void 0 : _b2.background) == null ? void 0 : _c2.toString()) != null ? _d2 : "#fff";
343
+ e.target.style.background = (_d2 = (_c2 = (_b2 = (_a2 = providerProps.styles) == null ? void 0 : _a2.cancelButton) == null ? void 0 : _b2.background) == null ? void 0 : _c2.toString()) != null ? _d2 : cancelBg;
333
344
  },
334
345
  children: (_q = state.cancelText) != null ? _q : "Cancel"
335
346
  }
@@ -386,6 +397,18 @@ var DEFAULT_STATE = {
386
397
  variant: "default",
387
398
  icon: void 0
388
399
  };
400
+ function usePrefersDark() {
401
+ const [dark, setDark] = (0, import_react3.useState)(
402
+ () => typeof window !== "undefined" ? window.matchMedia("(prefers-color-scheme: dark)").matches : false
403
+ );
404
+ (0, import_react3.useEffect)(() => {
405
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
406
+ const handler = (e) => setDark(e.matches);
407
+ mq.addEventListener("change", handler);
408
+ return () => mq.removeEventListener("change", handler);
409
+ }, []);
410
+ return dark;
411
+ }
389
412
  function ConfirmDialogProvider({
390
413
  children,
391
414
  defaultOptions,
@@ -396,6 +419,7 @@ function ConfirmDialogProvider({
396
419
  const [state, setState] = (0, import_react3.useState)(DEFAULT_STATE);
397
420
  const [isClosing, setIsClosing] = (0, import_react3.useState)(false);
398
421
  const resolveRef = (0, import_react3.useRef)(null);
422
+ const isDark = usePrefersDark();
399
423
  const close = (0, import_react3.useCallback)((result) => {
400
424
  setIsClosing(true);
401
425
  setTimeout(() => {
@@ -434,7 +458,8 @@ function ConfirmDialogProvider({
434
458
  providerProps: { classNames, styles, defaultOptions },
435
459
  onConfirm,
436
460
  onCancel,
437
- isClosing
461
+ isClosing,
462
+ isDark
438
463
  }
439
464
  );
440
465
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(ConfirmDialogContext.Provider, { value: contextValue, children: [
package/dist/index.mjs CHANGED
@@ -19,11 +19,11 @@ var __spreadValues = (a, b) => {
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
20
 
21
21
  // src/components/ConfirmDialogProvider.tsx
22
- import { useState, useCallback, useRef as useRef2, useMemo } from "react";
22
+ import { useState as useState2, useCallback, useRef as useRef2, useMemo, useEffect as useEffect2 } from "react";
23
23
  import { createPortal } from "react-dom";
24
24
 
25
25
  // src/components/BuildinDialog.tsx
26
- import { useEffect, useRef } from "react";
26
+ import { useEffect, useRef, useState } from "react";
27
27
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
28
28
  var VARIANT_STYLES = {
29
29
  default: {
@@ -31,28 +31,36 @@ var VARIANT_STYLES = {
31
31
  confirmColor: "#fff",
32
32
  confirmHover: "#333",
33
33
  accentColor: "#111",
34
- iconBg: "#f4f4f4"
34
+ accentColorDark: "#e5e5e5",
35
+ iconBg: "#f4f4f4",
36
+ iconBgDark: "#2c2c2e"
35
37
  },
36
38
  danger: {
37
39
  confirmBg: "#dc2626",
38
40
  confirmColor: "#fff",
39
41
  confirmHover: "#b91c1c",
40
42
  accentColor: "#dc2626",
41
- iconBg: "#fef2f2"
43
+ accentColorDark: "#f87171",
44
+ iconBg: "#fef2f2",
45
+ iconBgDark: "#3b1114"
42
46
  },
43
47
  warning: {
44
48
  confirmBg: "#d97706",
45
49
  confirmColor: "#fff",
46
50
  confirmHover: "#b45309",
47
51
  accentColor: "#d97706",
48
- iconBg: "#fffbeb"
52
+ accentColorDark: "#fbbf24",
53
+ iconBg: "#fffbeb",
54
+ iconBgDark: "#3b2a0a"
49
55
  },
50
56
  success: {
51
57
  confirmBg: "#16a34a",
52
58
  confirmColor: "#fff",
53
59
  confirmHover: "#15803d",
54
60
  accentColor: "#16a34a",
55
- iconBg: "#f0fdf4"
61
+ accentColorDark: "#4ade80",
62
+ iconBg: "#f0fdf4",
63
+ iconBgDark: "#0a2e1a"
56
64
  }
57
65
  };
58
66
  var DEFAULT_ICONS = {
@@ -151,7 +159,8 @@ function BuiltInDialog({
151
159
  providerProps,
152
160
  onConfirm,
153
161
  onCancel,
154
- isClosing
162
+ isClosing,
163
+ isDark
155
164
  }) {
156
165
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
157
166
  const confirmRef = useRef(null);
@@ -178,7 +187,7 @@ function BuiltInDialog({
178
187
  const overlayStyle = __spreadValues({
179
188
  position: "fixed",
180
189
  inset: 0,
181
- background: "rgba(0,0,0,0.45)",
190
+ background: isDark ? "rgba(0,0,0,0.6)" : "rgba(0,0,0,0.45)",
182
191
  backdropFilter: "blur(4px)",
183
192
  WebkitBackdropFilter: "blur(4px)",
184
193
  display: "flex",
@@ -189,12 +198,13 @@ function BuiltInDialog({
189
198
  animation: `rcd-overlay-${animationState} 200ms ease forwards`
190
199
  }, (_b = providerProps.styles) == null ? void 0 : _b.overlay);
191
200
  const dialogStyle = __spreadValues({
192
- background: "#fff",
201
+ background: isDark ? "#1c1c1e" : "#fff",
193
202
  borderRadius: "16px",
194
203
  padding: "28px",
195
204
  maxWidth: "420px",
196
205
  width: "100%",
197
- boxShadow: "0 24px 64px rgba(0,0,0,0.18), 0 4px 12px rgba(0,0,0,0.08)",
206
+ boxShadow: isDark ? "0 24px 64px rgba(0,0,0,0.4), 0 4px 12px rgba(0,0,0,0.3)" : "0 24px 64px rgba(0,0,0,0.18), 0 4px 12px rgba(0,0,0,0.08)",
207
+ border: isDark ? "1px solid rgba(255,255,255,0.08)" : "none",
198
208
  position: "relative",
199
209
  animation: `rcd-dialog-${animationState} 220ms cubic-bezier(0.34,1.56,0.64,1) forwards`
200
210
  }, (_c = providerProps.styles) == null ? void 0 : _c.dialog);
@@ -202,8 +212,8 @@ function BuiltInDialog({
202
212
  width: 48,
203
213
  height: 48,
204
214
  borderRadius: "12px",
205
- background: v.iconBg,
206
- color: v.accentColor,
215
+ background: isDark ? v.iconBgDark : v.iconBg,
216
+ color: isDark ? v.accentColorDark : v.accentColor,
207
217
  display: "flex",
208
218
  alignItems: "center",
209
219
  justifyContent: "center",
@@ -214,7 +224,7 @@ function BuiltInDialog({
214
224
  margin: "0 0 6px 0",
215
225
  fontSize: "17px",
216
226
  fontWeight: 700,
217
- color: "#0f0f0f",
227
+ color: isDark ? "#f5f5f5" : "#0f0f0f",
218
228
  lineHeight: 1.3,
219
229
  letterSpacing: "-0.02em",
220
230
  fontFamily: "inherit"
@@ -222,7 +232,7 @@ function BuiltInDialog({
222
232
  const messageStyle = __spreadValues({
223
233
  margin: "0 0 24px 0",
224
234
  fontSize: "14px",
225
- color: "#6b7280",
235
+ color: isDark ? "#a1a1aa" : "#6b7280",
226
236
  lineHeight: 1.6,
227
237
  fontFamily: "inherit"
228
238
  }, (_e = providerProps.styles) == null ? void 0 : _e.message);
@@ -231,12 +241,13 @@ function BuiltInDialog({
231
241
  gap: "10px",
232
242
  justifyContent: "flex-end"
233
243
  }, (_f = providerProps.styles) == null ? void 0 : _f.actions);
244
+ const cancelBg = isDark ? "#2c2c2e" : "#fff";
234
245
  const cancelStyle = __spreadValues({
235
246
  padding: "9px 18px",
236
247
  borderRadius: "9px",
237
- border: "1.5px solid #e5e7eb",
238
- background: "#fff",
239
- color: "#374151",
248
+ border: isDark ? "1.5px solid #3a3a3c" : "1.5px solid #e5e7eb",
249
+ background: cancelBg,
250
+ color: isDark ? "#e5e5e5" : "#374151",
240
251
  fontSize: "14px",
241
252
  fontWeight: 500,
242
253
  cursor: "pointer",
@@ -301,11 +312,11 @@ function BuiltInDialog({
301
312
  className: (_p = providerProps.classNames) == null ? void 0 : _p.cancelButton,
302
313
  onClick: onCancel,
303
314
  onMouseEnter: (e) => {
304
- e.target.style.background = "#f9fafb";
315
+ e.target.style.background = isDark ? "#3a3a3c" : "#f9fafb";
305
316
  },
306
317
  onMouseLeave: (e) => {
307
318
  var _a2, _b2, _c2, _d2;
308
- e.target.style.background = (_d2 = (_c2 = (_b2 = (_a2 = providerProps.styles) == null ? void 0 : _a2.cancelButton) == null ? void 0 : _b2.background) == null ? void 0 : _c2.toString()) != null ? _d2 : "#fff";
319
+ e.target.style.background = (_d2 = (_c2 = (_b2 = (_a2 = providerProps.styles) == null ? void 0 : _a2.cancelButton) == null ? void 0 : _b2.background) == null ? void 0 : _c2.toString()) != null ? _d2 : cancelBg;
309
320
  },
310
321
  children: (_q = state.cancelText) != null ? _q : "Cancel"
311
322
  }
@@ -362,6 +373,18 @@ var DEFAULT_STATE = {
362
373
  variant: "default",
363
374
  icon: void 0
364
375
  };
376
+ function usePrefersDark() {
377
+ const [dark, setDark] = useState2(
378
+ () => typeof window !== "undefined" ? window.matchMedia("(prefers-color-scheme: dark)").matches : false
379
+ );
380
+ useEffect2(() => {
381
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
382
+ const handler = (e) => setDark(e.matches);
383
+ mq.addEventListener("change", handler);
384
+ return () => mq.removeEventListener("change", handler);
385
+ }, []);
386
+ return dark;
387
+ }
365
388
  function ConfirmDialogProvider({
366
389
  children,
367
390
  defaultOptions,
@@ -369,9 +392,10 @@ function ConfirmDialogProvider({
369
392
  styles,
370
393
  renderDialog
371
394
  }) {
372
- const [state, setState] = useState(DEFAULT_STATE);
373
- const [isClosing, setIsClosing] = useState(false);
395
+ const [state, setState] = useState2(DEFAULT_STATE);
396
+ const [isClosing, setIsClosing] = useState2(false);
374
397
  const resolveRef = useRef2(null);
398
+ const isDark = usePrefersDark();
375
399
  const close = useCallback((result) => {
376
400
  setIsClosing(true);
377
401
  setTimeout(() => {
@@ -410,7 +434,8 @@ function ConfirmDialogProvider({
410
434
  providerProps: { classNames, styles, defaultOptions },
411
435
  onConfirm,
412
436
  onCancel,
413
- isClosing
437
+ isClosing,
438
+ isDark
414
439
  }
415
440
  );
416
441
  return /* @__PURE__ */ jsxs2(ConfirmDialogContext.Provider, { value: contextValue, children: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nobertdev/react-confirm-dialog",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "A lightweight, fully customizable confirmation dialog hook (useConfirm()) that replaces window.confirm() with beautiful async modals. Zero dependencies.",
5
5
  "keywords": [
6
6
  "react",
@@ -39,10 +39,10 @@
39
39
  },
40
40
  "repository": {
41
41
  "type": "git",
42
- "url": "https://github.com/NOBERT167/@nobertdev/react-confirm-dialog.git"
42
+ "url": "https://github.com/NOBERT167/react-confirm-dialog.git"
43
43
  },
44
44
  "bugs": {
45
- "url": "https://github.com/NOBERT167/@nobertdev/react-confirm-dialog/issues"
45
+ "url": "https://github.com/NOBERT167/react-confirm-dialog/issues"
46
46
  },
47
- "homepage": "https://github.com/NOBERT167/@nobertdev/react-confirm-dialog#readme"
47
+ "homepage": "https://github.com/NOBERT167/react-confirm-dialog#readme"
48
48
  }