@nobertdev/react-confirm-dialog 1.0.0 → 1.1.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 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
@@ -49,34 +49,54 @@ var import_react_dom = require("react-dom");
49
49
  // src/components/BuildinDialog.tsx
50
50
  var import_react = require("react");
51
51
  var import_jsx_runtime = require("react/jsx-runtime");
52
+ function usePrefersDark() {
53
+ const [dark, setDark] = (0, import_react.useState)(
54
+ () => typeof window !== "undefined" ? window.matchMedia("(prefers-color-scheme: dark)").matches : false
55
+ );
56
+ (0, import_react.useEffect)(() => {
57
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
58
+ const handler = (e) => setDark(e.matches);
59
+ mq.addEventListener("change", handler);
60
+ return () => mq.removeEventListener("change", handler);
61
+ }, []);
62
+ return dark;
63
+ }
52
64
  var VARIANT_STYLES = {
53
65
  default: {
54
66
  confirmBg: "#111",
55
67
  confirmColor: "#fff",
56
68
  confirmHover: "#333",
57
69
  accentColor: "#111",
58
- iconBg: "#f4f4f4"
70
+ accentColorDark: "#e5e5e5",
71
+ iconBg: "#f4f4f4",
72
+ iconBgDark: "#2c2c2e"
59
73
  },
60
74
  danger: {
61
75
  confirmBg: "#dc2626",
62
76
  confirmColor: "#fff",
63
77
  confirmHover: "#b91c1c",
64
78
  accentColor: "#dc2626",
65
- iconBg: "#fef2f2"
79
+ accentColorDark: "#f87171",
80
+ iconBg: "#fef2f2",
81
+ iconBgDark: "#3b1114"
66
82
  },
67
83
  warning: {
68
84
  confirmBg: "#d97706",
69
85
  confirmColor: "#fff",
70
86
  confirmHover: "#b45309",
71
87
  accentColor: "#d97706",
72
- iconBg: "#fffbeb"
88
+ accentColorDark: "#fbbf24",
89
+ iconBg: "#fffbeb",
90
+ iconBgDark: "#3b2a0a"
73
91
  },
74
92
  success: {
75
93
  confirmBg: "#16a34a",
76
94
  confirmColor: "#fff",
77
95
  confirmHover: "#15803d",
78
96
  accentColor: "#16a34a",
79
- iconBg: "#f0fdf4"
97
+ accentColorDark: "#4ade80",
98
+ iconBg: "#f0fdf4",
99
+ iconBgDark: "#0a2e1a"
80
100
  }
81
101
  };
82
102
  var DEFAULT_ICONS = {
@@ -179,6 +199,7 @@ function BuiltInDialog({
179
199
  }) {
180
200
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
181
201
  const confirmRef = (0, import_react.useRef)(null);
202
+ const isDark = usePrefersDark();
182
203
  const variant = (_a = state.variant) != null ? _a : "default";
183
204
  const v = VARIANT_STYLES[variant];
184
205
  (0, import_react.useEffect)(() => {
@@ -202,7 +223,7 @@ function BuiltInDialog({
202
223
  const overlayStyle = __spreadValues({
203
224
  position: "fixed",
204
225
  inset: 0,
205
- background: "rgba(0,0,0,0.45)",
226
+ background: isDark ? "rgba(0,0,0,0.6)" : "rgba(0,0,0,0.45)",
206
227
  backdropFilter: "blur(4px)",
207
228
  WebkitBackdropFilter: "blur(4px)",
208
229
  display: "flex",
@@ -213,12 +234,13 @@ function BuiltInDialog({
213
234
  animation: `rcd-overlay-${animationState} 200ms ease forwards`
214
235
  }, (_b = providerProps.styles) == null ? void 0 : _b.overlay);
215
236
  const dialogStyle = __spreadValues({
216
- background: "#fff",
237
+ background: isDark ? "#1c1c1e" : "#fff",
217
238
  borderRadius: "16px",
218
239
  padding: "28px",
219
240
  maxWidth: "420px",
220
241
  width: "100%",
221
- boxShadow: "0 24px 64px rgba(0,0,0,0.18), 0 4px 12px rgba(0,0,0,0.08)",
242
+ 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)",
243
+ border: isDark ? "1px solid rgba(255,255,255,0.08)" : "none",
222
244
  position: "relative",
223
245
  animation: `rcd-dialog-${animationState} 220ms cubic-bezier(0.34,1.56,0.64,1) forwards`
224
246
  }, (_c = providerProps.styles) == null ? void 0 : _c.dialog);
@@ -226,8 +248,8 @@ function BuiltInDialog({
226
248
  width: 48,
227
249
  height: 48,
228
250
  borderRadius: "12px",
229
- background: v.iconBg,
230
- color: v.accentColor,
251
+ background: isDark ? v.iconBgDark : v.iconBg,
252
+ color: isDark ? v.accentColorDark : v.accentColor,
231
253
  display: "flex",
232
254
  alignItems: "center",
233
255
  justifyContent: "center",
@@ -238,7 +260,7 @@ function BuiltInDialog({
238
260
  margin: "0 0 6px 0",
239
261
  fontSize: "17px",
240
262
  fontWeight: 700,
241
- color: "#0f0f0f",
263
+ color: isDark ? "#f5f5f5" : "#0f0f0f",
242
264
  lineHeight: 1.3,
243
265
  letterSpacing: "-0.02em",
244
266
  fontFamily: "inherit"
@@ -246,7 +268,7 @@ function BuiltInDialog({
246
268
  const messageStyle = __spreadValues({
247
269
  margin: "0 0 24px 0",
248
270
  fontSize: "14px",
249
- color: "#6b7280",
271
+ color: isDark ? "#a1a1aa" : "#6b7280",
250
272
  lineHeight: 1.6,
251
273
  fontFamily: "inherit"
252
274
  }, (_e = providerProps.styles) == null ? void 0 : _e.message);
@@ -255,12 +277,13 @@ function BuiltInDialog({
255
277
  gap: "10px",
256
278
  justifyContent: "flex-end"
257
279
  }, (_f = providerProps.styles) == null ? void 0 : _f.actions);
280
+ const cancelBg = isDark ? "#2c2c2e" : "#fff";
258
281
  const cancelStyle = __spreadValues({
259
282
  padding: "9px 18px",
260
283
  borderRadius: "9px",
261
- border: "1.5px solid #e5e7eb",
262
- background: "#fff",
263
- color: "#374151",
284
+ border: isDark ? "1.5px solid #3a3a3c" : "1.5px solid #e5e7eb",
285
+ background: cancelBg,
286
+ color: isDark ? "#e5e5e5" : "#374151",
264
287
  fontSize: "14px",
265
288
  fontWeight: 500,
266
289
  cursor: "pointer",
@@ -325,11 +348,11 @@ function BuiltInDialog({
325
348
  className: (_p = providerProps.classNames) == null ? void 0 : _p.cancelButton,
326
349
  onClick: onCancel,
327
350
  onMouseEnter: (e) => {
328
- e.target.style.background = "#f9fafb";
351
+ e.target.style.background = isDark ? "#3a3a3c" : "#f9fafb";
329
352
  },
330
353
  onMouseLeave: (e) => {
331
354
  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";
355
+ 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
356
  },
334
357
  children: (_q = state.cancelText) != null ? _q : "Cancel"
335
358
  }
package/dist/index.mjs CHANGED
@@ -19,40 +19,60 @@ 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 } 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
+ function usePrefersDark() {
29
+ const [dark, setDark] = useState(
30
+ () => typeof window !== "undefined" ? window.matchMedia("(prefers-color-scheme: dark)").matches : false
31
+ );
32
+ useEffect(() => {
33
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
34
+ const handler = (e) => setDark(e.matches);
35
+ mq.addEventListener("change", handler);
36
+ return () => mq.removeEventListener("change", handler);
37
+ }, []);
38
+ return dark;
39
+ }
28
40
  var VARIANT_STYLES = {
29
41
  default: {
30
42
  confirmBg: "#111",
31
43
  confirmColor: "#fff",
32
44
  confirmHover: "#333",
33
45
  accentColor: "#111",
34
- iconBg: "#f4f4f4"
46
+ accentColorDark: "#e5e5e5",
47
+ iconBg: "#f4f4f4",
48
+ iconBgDark: "#2c2c2e"
35
49
  },
36
50
  danger: {
37
51
  confirmBg: "#dc2626",
38
52
  confirmColor: "#fff",
39
53
  confirmHover: "#b91c1c",
40
54
  accentColor: "#dc2626",
41
- iconBg: "#fef2f2"
55
+ accentColorDark: "#f87171",
56
+ iconBg: "#fef2f2",
57
+ iconBgDark: "#3b1114"
42
58
  },
43
59
  warning: {
44
60
  confirmBg: "#d97706",
45
61
  confirmColor: "#fff",
46
62
  confirmHover: "#b45309",
47
63
  accentColor: "#d97706",
48
- iconBg: "#fffbeb"
64
+ accentColorDark: "#fbbf24",
65
+ iconBg: "#fffbeb",
66
+ iconBgDark: "#3b2a0a"
49
67
  },
50
68
  success: {
51
69
  confirmBg: "#16a34a",
52
70
  confirmColor: "#fff",
53
71
  confirmHover: "#15803d",
54
72
  accentColor: "#16a34a",
55
- iconBg: "#f0fdf4"
73
+ accentColorDark: "#4ade80",
74
+ iconBg: "#f0fdf4",
75
+ iconBgDark: "#0a2e1a"
56
76
  }
57
77
  };
58
78
  var DEFAULT_ICONS = {
@@ -155,6 +175,7 @@ function BuiltInDialog({
155
175
  }) {
156
176
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
157
177
  const confirmRef = useRef(null);
178
+ const isDark = usePrefersDark();
158
179
  const variant = (_a = state.variant) != null ? _a : "default";
159
180
  const v = VARIANT_STYLES[variant];
160
181
  useEffect(() => {
@@ -178,7 +199,7 @@ function BuiltInDialog({
178
199
  const overlayStyle = __spreadValues({
179
200
  position: "fixed",
180
201
  inset: 0,
181
- background: "rgba(0,0,0,0.45)",
202
+ background: isDark ? "rgba(0,0,0,0.6)" : "rgba(0,0,0,0.45)",
182
203
  backdropFilter: "blur(4px)",
183
204
  WebkitBackdropFilter: "blur(4px)",
184
205
  display: "flex",
@@ -189,12 +210,13 @@ function BuiltInDialog({
189
210
  animation: `rcd-overlay-${animationState} 200ms ease forwards`
190
211
  }, (_b = providerProps.styles) == null ? void 0 : _b.overlay);
191
212
  const dialogStyle = __spreadValues({
192
- background: "#fff",
213
+ background: isDark ? "#1c1c1e" : "#fff",
193
214
  borderRadius: "16px",
194
215
  padding: "28px",
195
216
  maxWidth: "420px",
196
217
  width: "100%",
197
- boxShadow: "0 24px 64px rgba(0,0,0,0.18), 0 4px 12px rgba(0,0,0,0.08)",
218
+ 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)",
219
+ border: isDark ? "1px solid rgba(255,255,255,0.08)" : "none",
198
220
  position: "relative",
199
221
  animation: `rcd-dialog-${animationState} 220ms cubic-bezier(0.34,1.56,0.64,1) forwards`
200
222
  }, (_c = providerProps.styles) == null ? void 0 : _c.dialog);
@@ -202,8 +224,8 @@ function BuiltInDialog({
202
224
  width: 48,
203
225
  height: 48,
204
226
  borderRadius: "12px",
205
- background: v.iconBg,
206
- color: v.accentColor,
227
+ background: isDark ? v.iconBgDark : v.iconBg,
228
+ color: isDark ? v.accentColorDark : v.accentColor,
207
229
  display: "flex",
208
230
  alignItems: "center",
209
231
  justifyContent: "center",
@@ -214,7 +236,7 @@ function BuiltInDialog({
214
236
  margin: "0 0 6px 0",
215
237
  fontSize: "17px",
216
238
  fontWeight: 700,
217
- color: "#0f0f0f",
239
+ color: isDark ? "#f5f5f5" : "#0f0f0f",
218
240
  lineHeight: 1.3,
219
241
  letterSpacing: "-0.02em",
220
242
  fontFamily: "inherit"
@@ -222,7 +244,7 @@ function BuiltInDialog({
222
244
  const messageStyle = __spreadValues({
223
245
  margin: "0 0 24px 0",
224
246
  fontSize: "14px",
225
- color: "#6b7280",
247
+ color: isDark ? "#a1a1aa" : "#6b7280",
226
248
  lineHeight: 1.6,
227
249
  fontFamily: "inherit"
228
250
  }, (_e = providerProps.styles) == null ? void 0 : _e.message);
@@ -231,12 +253,13 @@ function BuiltInDialog({
231
253
  gap: "10px",
232
254
  justifyContent: "flex-end"
233
255
  }, (_f = providerProps.styles) == null ? void 0 : _f.actions);
256
+ const cancelBg = isDark ? "#2c2c2e" : "#fff";
234
257
  const cancelStyle = __spreadValues({
235
258
  padding: "9px 18px",
236
259
  borderRadius: "9px",
237
- border: "1.5px solid #e5e7eb",
238
- background: "#fff",
239
- color: "#374151",
260
+ border: isDark ? "1.5px solid #3a3a3c" : "1.5px solid #e5e7eb",
261
+ background: cancelBg,
262
+ color: isDark ? "#e5e5e5" : "#374151",
240
263
  fontSize: "14px",
241
264
  fontWeight: 500,
242
265
  cursor: "pointer",
@@ -301,11 +324,11 @@ function BuiltInDialog({
301
324
  className: (_p = providerProps.classNames) == null ? void 0 : _p.cancelButton,
302
325
  onClick: onCancel,
303
326
  onMouseEnter: (e) => {
304
- e.target.style.background = "#f9fafb";
327
+ e.target.style.background = isDark ? "#3a3a3c" : "#f9fafb";
305
328
  },
306
329
  onMouseLeave: (e) => {
307
330
  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";
331
+ 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
332
  },
310
333
  children: (_q = state.cancelText) != null ? _q : "Cancel"
311
334
  }
@@ -369,8 +392,8 @@ 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);
375
398
  const close = useCallback((result) => {
376
399
  setIsClosing(true);
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.0",
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
  }