dauth-context-react 5.0.0 → 6.0.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/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  // src/index.tsx
2
2
  import {
3
3
  useReducer,
4
- useMemo,
5
- useEffect,
6
- useCallback,
4
+ useMemo as useMemo2,
5
+ useEffect as useEffect2,
6
+ useCallback as useCallback2,
7
7
  createContext,
8
8
  useContext
9
9
  } from "react";
@@ -21,8 +21,6 @@ var initialDauthState = {
21
21
  logout: () => {
22
22
  },
23
23
  updateUser: () => Promise.resolve(false),
24
- updateUserWithRedirect: () => {
25
- },
26
24
  deleteAccount: () => Promise.resolve(false)
27
25
  };
28
26
  var initialDauthState_default = initialDauthState;
@@ -72,7 +70,12 @@ function getCsrfToken() {
72
70
  const match = document.cookie.match(
73
71
  /(?:^|;\s*)(?:__Host-csrf|csrf-token)=([^;]*)/
74
72
  );
75
- return match?.[1] ?? "";
73
+ if (!match?.[1]) return "";
74
+ try {
75
+ return decodeURIComponent(match[1]);
76
+ } catch {
77
+ return match[1];
78
+ }
76
79
  }
77
80
  async function exchangeCodeAPI(basePath, code) {
78
81
  const response = await fetch(`${basePath}/exchange-code`, {
@@ -125,18 +128,6 @@ async function deleteAccountAPI(basePath) {
125
128
  const data = await response.json();
126
129
  return { response, data };
127
130
  }
128
- async function profileRedirectAPI(basePath) {
129
- const response = await fetch(
130
- `${basePath}/profile-redirect`,
131
- {
132
- method: "GET",
133
- headers: { "X-CSRF-Token": getCsrfToken() },
134
- credentials: "include"
135
- }
136
- );
137
- const data = await response.json();
138
- return { response, data };
139
- }
140
131
 
141
132
  // src/reducer/dauth.actions.ts
142
133
  async function exchangeCodeAction(ctx, code) {
@@ -146,11 +137,7 @@ async function exchangeCodeAction(ctx, code) {
146
137
  payload: { isLoading: true }
147
138
  });
148
139
  try {
149
- window.history.replaceState(
150
- {},
151
- document.title,
152
- window.location.pathname
153
- );
140
+ window.history.replaceState({}, document.title, window.location.pathname);
154
141
  const result = await exchangeCodeAPI(authProxyPath, code);
155
142
  if (result.response.status === 200) {
156
143
  dispatch({
@@ -165,9 +152,7 @@ async function exchangeCodeAction(ctx, code) {
165
152
  }
166
153
  resetUser(dispatch);
167
154
  } catch (error) {
168
- onError(
169
- error instanceof Error ? error : new Error(String(error))
170
- );
155
+ onError(error instanceof Error ? error : new Error(String(error)));
171
156
  resetUser(dispatch);
172
157
  } finally {
173
158
  dispatch({
@@ -197,9 +182,7 @@ async function autoLoginAction(ctx) {
197
182
  }
198
183
  resetUser(dispatch);
199
184
  } catch (error) {
200
- onError(
201
- error instanceof Error ? error : new Error(String(error))
202
- );
185
+ onError(error instanceof Error ? error : new Error(String(error)));
203
186
  resetUser(dispatch);
204
187
  } finally {
205
188
  dispatch({
@@ -236,10 +219,7 @@ async function logoutAction(ctx) {
236
219
  async function updateUserAction(ctx, user) {
237
220
  const { dispatch, authProxyPath, onError } = ctx;
238
221
  if (user.language) {
239
- window.document.documentElement.setAttribute(
240
- "lang",
241
- user.language
242
- );
222
+ window.document.documentElement.setAttribute("lang", user.language);
243
223
  }
244
224
  try {
245
225
  const result = await updateUserAPI(authProxyPath, user);
@@ -250,34 +230,13 @@ async function updateUserAction(ctx, user) {
250
230
  });
251
231
  return true;
252
232
  }
253
- onError(
254
- new Error("Update user error: " + result.data.message)
255
- );
233
+ onError(new Error("Update user error: " + result.data.message));
256
234
  return false;
257
235
  } catch (error) {
258
- onError(
259
- error instanceof Error ? error : new Error("Update user error")
260
- );
236
+ onError(error instanceof Error ? error : new Error("Update user error"));
261
237
  return false;
262
238
  }
263
239
  }
264
- async function updateUserWithRedirectAction(ctx) {
265
- const { authProxyPath, onError } = ctx;
266
- try {
267
- const result = await profileRedirectAPI(authProxyPath);
268
- if (result.response.status === 200 && result.data.redirectUrl) {
269
- window.location.replace(result.data.redirectUrl);
270
- return;
271
- }
272
- onError(
273
- new Error("Could not generate profile redirect")
274
- );
275
- } catch (error) {
276
- onError(
277
- error instanceof Error ? error : new Error("Profile redirect error")
278
- );
279
- }
280
- }
281
240
  async function deleteAccountAction(ctx) {
282
241
  const { dispatch, authProxyPath, onError } = ctx;
283
242
  try {
@@ -288,9 +247,7 @@ async function deleteAccountAction(ctx) {
288
247
  }
289
248
  return false;
290
249
  } catch (error) {
291
- onError(
292
- error instanceof Error ? error : new Error("Delete account error")
293
- );
250
+ onError(error instanceof Error ? error : new Error("Delete account error"));
294
251
  return false;
295
252
  }
296
253
  }
@@ -314,12 +271,12 @@ function setDauthUrl(url) {
314
271
  function checkIsLocalhost() {
315
272
  if (typeof window === "undefined") return false;
316
273
  const hostname = window.location.hostname;
317
- return Boolean(
318
- hostname === "localhost" || hostname === "[::1]" || hostname.match(
319
- /(192)\.(168)\.(1)\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/gm
320
- ) || hostname.match(
321
- /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
322
- )
274
+ return hostname === "localhost" || hostname === "[::1]" || /^127(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/.test(
275
+ hostname
276
+ ) || /^192\.168(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){2}$/.test(
277
+ hostname
278
+ ) || /^10(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/.test(
279
+ hostname
323
280
  );
324
281
  }
325
282
  function getClientBasePath() {
@@ -339,8 +296,766 @@ var routes = {
339
296
  signin: "signin"
340
297
  };
341
298
 
299
+ // src/DauthProfileModal.tsx
300
+ import {
301
+ useCallback,
302
+ useEffect,
303
+ useMemo,
304
+ useRef,
305
+ useState
306
+ } from "react";
307
+ import { createPortal } from "react-dom";
308
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
309
+ var TRANSITION_MS = 200;
310
+ var MOBILE_TRANSITION_MS = 300;
311
+ var SUCCESS_TIMEOUT_MS = 4e3;
312
+ var CONFIRM_WORD = "DELETE";
313
+ function IconClose() {
314
+ return /* @__PURE__ */ jsxs(
315
+ "svg",
316
+ {
317
+ width: "20",
318
+ height: "20",
319
+ viewBox: "0 0 24 24",
320
+ fill: "none",
321
+ stroke: "currentColor",
322
+ strokeWidth: "2",
323
+ strokeLinecap: "round",
324
+ strokeLinejoin: "round",
325
+ children: [
326
+ /* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
327
+ /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
328
+ ]
329
+ }
330
+ );
331
+ }
332
+ function IconBack() {
333
+ return /* @__PURE__ */ jsxs(
334
+ "svg",
335
+ {
336
+ width: "20",
337
+ height: "20",
338
+ viewBox: "0 0 24 24",
339
+ fill: "none",
340
+ stroke: "currentColor",
341
+ strokeWidth: "2",
342
+ strokeLinecap: "round",
343
+ strokeLinejoin: "round",
344
+ children: [
345
+ /* @__PURE__ */ jsx("line", { x1: "19", y1: "12", x2: "5", y2: "12" }),
346
+ /* @__PURE__ */ jsx("polyline", { points: "12 19 5 12 12 5" })
347
+ ]
348
+ }
349
+ );
350
+ }
351
+ function Spinner() {
352
+ return /* @__PURE__ */ jsx("span", { style: spinnerStyle, "aria-hidden": "true" });
353
+ }
354
+ function useMediaQuery(query) {
355
+ const [matches, setMatches] = useState(
356
+ () => typeof window !== "undefined" && window.matchMedia(query).matches
357
+ );
358
+ useEffect(() => {
359
+ const mq = window.matchMedia(query);
360
+ const handler = (e) => setMatches(e.matches);
361
+ mq.addEventListener("change", handler);
362
+ return () => mq.removeEventListener("change", handler);
363
+ }, [query]);
364
+ return matches;
365
+ }
366
+ function useModalAnimation(open) {
367
+ const [phase, setPhase] = useState("exited");
368
+ useEffect(() => {
369
+ if (open) {
370
+ setPhase("entering");
371
+ const raf = requestAnimationFrame(() => {
372
+ requestAnimationFrame(() => setPhase("entered"));
373
+ });
374
+ return () => cancelAnimationFrame(raf);
375
+ }
376
+ if (phase === "entered" || phase === "entering") {
377
+ setPhase("exiting");
378
+ const timer = setTimeout(() => setPhase("exited"), MOBILE_TRANSITION_MS);
379
+ return () => clearTimeout(timer);
380
+ }
381
+ return void 0;
382
+ }, [open]);
383
+ return phase;
384
+ }
385
+ function useFocusTrap(containerRef, active, onEscape) {
386
+ const previousFocus = useRef(null);
387
+ useEffect(() => {
388
+ if (!active) return;
389
+ previousFocus.current = document.activeElement;
390
+ const container = containerRef.current;
391
+ if (!container) return;
392
+ const focusFirst = () => {
393
+ const firstInput = container.querySelector(
394
+ "input:not([disabled])"
395
+ );
396
+ (firstInput ?? container).focus();
397
+ };
398
+ const raf = requestAnimationFrame(focusFirst);
399
+ const handleKeyDown = (e) => {
400
+ if (e.key === "Escape") {
401
+ e.preventDefault();
402
+ onEscape();
403
+ return;
404
+ }
405
+ if (e.key !== "Tab") return;
406
+ const focusable = container.querySelectorAll(
407
+ 'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])'
408
+ );
409
+ if (focusable.length === 0) return;
410
+ const first = focusable[0];
411
+ const last = focusable[focusable.length - 1];
412
+ if (e.shiftKey && document.activeElement === first) {
413
+ e.preventDefault();
414
+ last.focus();
415
+ } else if (!e.shiftKey && document.activeElement === last) {
416
+ e.preventDefault();
417
+ first.focus();
418
+ }
419
+ };
420
+ document.addEventListener("keydown", handleKeyDown);
421
+ return () => {
422
+ cancelAnimationFrame(raf);
423
+ document.removeEventListener("keydown", handleKeyDown);
424
+ if (previousFocus.current instanceof HTMLElement) {
425
+ previousFocus.current.focus();
426
+ }
427
+ };
428
+ }, [active, containerRef, onEscape]);
429
+ }
430
+ function useScrollLock(active) {
431
+ useEffect(() => {
432
+ if (!active) return;
433
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
434
+ const prevOverflow = document.body.style.overflow;
435
+ const prevPaddingRight = document.body.style.paddingRight;
436
+ document.body.style.overflow = "hidden";
437
+ if (scrollbarWidth > 0) {
438
+ document.body.style.paddingRight = `${scrollbarWidth}px`;
439
+ }
440
+ return () => {
441
+ document.body.style.overflow = prevOverflow;
442
+ document.body.style.paddingRight = prevPaddingRight;
443
+ };
444
+ }, [active]);
445
+ }
446
+ function DauthProfileModal({ open, onClose }) {
447
+ const { user, domain, updateUser, deleteAccount } = useDauth();
448
+ const isDesktop = useMediaQuery("(min-width: 641px)");
449
+ const phase = useModalAnimation(open);
450
+ const modalRef = useRef(null);
451
+ const [name, setName] = useState("");
452
+ const [lastname, setLastname] = useState("");
453
+ const [nickname, setNickname] = useState("");
454
+ const [country, setCountry] = useState("");
455
+ const [populated, setPopulated] = useState(false);
456
+ const [saving, setSaving] = useState(false);
457
+ const [status, setStatus] = useState(null);
458
+ const [showDelete, setShowDelete] = useState(false);
459
+ const [deleteText, setDeleteText] = useState("");
460
+ const [deleting, setDeleting] = useState(false);
461
+ useEffect(() => {
462
+ if (open && user?._id && !populated) {
463
+ setName(user.name || "");
464
+ setLastname(user.lastname || "");
465
+ setNickname(user.nickname || "");
466
+ setCountry(user.country || "");
467
+ setPopulated(true);
468
+ }
469
+ if (!open) {
470
+ setPopulated(false);
471
+ setStatus(null);
472
+ setShowDelete(false);
473
+ setDeleteText("");
474
+ }
475
+ }, [open, user, populated]);
476
+ useEffect(() => {
477
+ if (status?.type !== "success") return;
478
+ const timer = setTimeout(() => setStatus(null), SUCCESS_TIMEOUT_MS);
479
+ return () => clearTimeout(timer);
480
+ }, [status]);
481
+ useFocusTrap(modalRef, phase === "entered", onClose);
482
+ useScrollLock(phase !== "exited");
483
+ const hasField = useCallback(
484
+ (field) => domain.formFields?.some((f) => f.field === field) ?? false,
485
+ [domain.formFields]
486
+ );
487
+ const isRequired = useCallback(
488
+ (field) => domain.formFields?.find((f) => f.field === field)?.required ?? false,
489
+ [domain.formFields]
490
+ );
491
+ const hasChanges = useMemo(() => {
492
+ if (!user?._id) return false;
493
+ return name !== (user.name || "") || lastname !== (user.lastname || "") || nickname !== (user.nickname || "") || country !== (user.country || "");
494
+ }, [name, lastname, nickname, country, user]);
495
+ const canSave = name.trim().length > 0 && hasChanges && !saving;
496
+ const handleSave = useCallback(async () => {
497
+ setSaving(true);
498
+ setStatus(null);
499
+ const fields = { name };
500
+ if (hasField("lastname")) fields.lastname = lastname;
501
+ if (hasField("nickname")) fields.nickname = nickname;
502
+ if (hasField("country")) fields.country = country;
503
+ const ok = await updateUser(fields);
504
+ setSaving(false);
505
+ if (ok) {
506
+ setStatus({
507
+ type: "success",
508
+ message: "Profile updated successfully"
509
+ });
510
+ } else {
511
+ setStatus({
512
+ type: "error",
513
+ message: "Something went wrong. Please try again."
514
+ });
515
+ }
516
+ }, [name, lastname, nickname, country, hasField, updateUser]);
517
+ const handleDelete = useCallback(async () => {
518
+ setDeleting(true);
519
+ const ok = await deleteAccount();
520
+ setDeleting(false);
521
+ if (ok) {
522
+ onClose();
523
+ } else {
524
+ setStatus({
525
+ type: "error",
526
+ message: "Could not delete account. Please try again."
527
+ });
528
+ setShowDelete(false);
529
+ setDeleteText("");
530
+ }
531
+ }, [deleteAccount, onClose]);
532
+ if (phase === "exited") return null;
533
+ const dur = isDesktop ? TRANSITION_MS : MOBILE_TRANSITION_MS;
534
+ const easing = "cubic-bezier(0.16, 1, 0.3, 1)";
535
+ const backdrop = {
536
+ position: "fixed",
537
+ inset: 0,
538
+ zIndex: 2147483647,
539
+ backgroundColor: "var(--dauth-backdrop, rgba(0, 0, 0, 0.6))",
540
+ backdropFilter: "blur(4px)",
541
+ WebkitBackdropFilter: "blur(4px)",
542
+ display: "flex",
543
+ alignItems: "center",
544
+ justifyContent: "center",
545
+ opacity: phase === "entered" ? 1 : 0,
546
+ transition: `opacity ${dur}ms ease-out`
547
+ };
548
+ const modalDesktop = {
549
+ position: "relative",
550
+ width: "100%",
551
+ maxWidth: 480,
552
+ maxHeight: "90vh",
553
+ margin: 16,
554
+ backgroundColor: "var(--dauth-surface, #1a1a2e)",
555
+ borderRadius: "var(--dauth-radius, 12px)",
556
+ boxShadow: "var(--dauth-shadow, 0 25px 50px -12px rgba(0, 0, 0, 0.5))",
557
+ border: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
558
+ display: "flex",
559
+ flexDirection: "column",
560
+ overflow: "hidden",
561
+ fontFamily: "var(--dauth-font-family, system-ui, -apple-system, sans-serif)",
562
+ color: "var(--dauth-text-primary, #e4e4e7)",
563
+ opacity: phase === "entered" ? 1 : 0,
564
+ transform: phase === "entered" ? "translateY(0)" : "translateY(16px)",
565
+ transition: `opacity ${dur}ms ${easing}, transform ${dur}ms ${easing}`
566
+ };
567
+ const modalMobile = {
568
+ position: "fixed",
569
+ inset: 0,
570
+ backgroundColor: "var(--dauth-surface, #1a1a2e)",
571
+ display: "flex",
572
+ flexDirection: "column",
573
+ fontFamily: "var(--dauth-font-family, system-ui, -apple-system, sans-serif)",
574
+ color: "var(--dauth-text-primary, #e4e4e7)",
575
+ transform: phase === "entered" ? "translateY(0)" : "translateY(100%)",
576
+ transition: `transform ${dur}ms ${easing}`
577
+ };
578
+ const avatarInitial = (user.name || user.email || "?").charAt(0).toUpperCase();
579
+ return createPortal(
580
+ /* @__PURE__ */ jsxs(Fragment, { children: [
581
+ /* @__PURE__ */ jsx(
582
+ "style",
583
+ {
584
+ dangerouslySetInnerHTML: {
585
+ __html: "@keyframes dauth-spin{to{transform:rotate(360deg)}}"
586
+ }
587
+ }
588
+ ),
589
+ /* @__PURE__ */ jsx(
590
+ "div",
591
+ {
592
+ style: backdrop,
593
+ onClick: isDesktop ? onClose : void 0,
594
+ "data-testid": "dauth-profile-backdrop",
595
+ children: /* @__PURE__ */ jsxs(
596
+ "div",
597
+ {
598
+ ref: modalRef,
599
+ role: "dialog",
600
+ "aria-modal": "true",
601
+ "aria-labelledby": "dauth-profile-title",
602
+ style: isDesktop ? modalDesktop : modalMobile,
603
+ onClick: (e) => e.stopPropagation(),
604
+ tabIndex: -1,
605
+ children: [
606
+ /* @__PURE__ */ jsxs("div", { style: headerStyle(isDesktop), children: [
607
+ /* @__PURE__ */ jsx(
608
+ "button",
609
+ {
610
+ type: "button",
611
+ onClick: onClose,
612
+ style: closeBtn,
613
+ "aria-label": "Close",
614
+ onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-surface-hover, #232340)",
615
+ onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "transparent",
616
+ children: isDesktop ? /* @__PURE__ */ jsx(IconClose, {}) : /* @__PURE__ */ jsx(IconBack, {})
617
+ }
618
+ ),
619
+ /* @__PURE__ */ jsx("h2", { id: "dauth-profile-title", style: titleStyle, children: "Your Profile" }),
620
+ /* @__PURE__ */ jsx("div", { style: { width: 36 } })
621
+ ] }),
622
+ /* @__PURE__ */ jsxs("div", { style: bodyStyle, children: [
623
+ /* @__PURE__ */ jsxs("div", { style: avatarSection, children: [
624
+ /* @__PURE__ */ jsx("div", { style: avatarCircle, children: user.avatar?.url ? /* @__PURE__ */ jsx(
625
+ "img",
626
+ {
627
+ src: user.avatar.url,
628
+ alt: "",
629
+ style: {
630
+ width: "100%",
631
+ height: "100%",
632
+ objectFit: "cover"
633
+ }
634
+ }
635
+ ) : avatarInitial }),
636
+ /* @__PURE__ */ jsx("div", { style: emailText, children: user.email })
637
+ ] }),
638
+ status && /* @__PURE__ */ jsx(
639
+ "div",
640
+ {
641
+ role: "status",
642
+ "aria-live": "polite",
643
+ style: statusMsg(status.type),
644
+ children: status.message
645
+ }
646
+ ),
647
+ /* @__PURE__ */ jsxs("div", { children: [
648
+ /* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
649
+ /* @__PURE__ */ jsx("label", { htmlFor: "dauth-name", style: label, children: "Name *" }),
650
+ /* @__PURE__ */ jsx(
651
+ "input",
652
+ {
653
+ id: "dauth-name",
654
+ type: "text",
655
+ value: name,
656
+ onChange: (e) => setName(e.target.value),
657
+ placeholder: "Your name",
658
+ disabled: saving,
659
+ style: input,
660
+ onFocus: inputFocusHandler,
661
+ onBlur: inputBlurHandler
662
+ }
663
+ )
664
+ ] }),
665
+ hasField("lastname") && /* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
666
+ /* @__PURE__ */ jsxs("label", { htmlFor: "dauth-lastname", style: label, children: [
667
+ "Last name",
668
+ isRequired("lastname") ? " *" : ""
669
+ ] }),
670
+ /* @__PURE__ */ jsx(
671
+ "input",
672
+ {
673
+ id: "dauth-lastname",
674
+ type: "text",
675
+ value: lastname,
676
+ onChange: (e) => setLastname(e.target.value),
677
+ placeholder: "Your last name",
678
+ disabled: saving,
679
+ style: input,
680
+ onFocus: inputFocusHandler,
681
+ onBlur: inputBlurHandler
682
+ }
683
+ )
684
+ ] }),
685
+ hasField("nickname") && /* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
686
+ /* @__PURE__ */ jsxs("label", { htmlFor: "dauth-nickname", style: label, children: [
687
+ "Nickname",
688
+ isRequired("nickname") ? " *" : ""
689
+ ] }),
690
+ /* @__PURE__ */ jsx(
691
+ "input",
692
+ {
693
+ id: "dauth-nickname",
694
+ type: "text",
695
+ value: nickname,
696
+ onChange: (e) => setNickname(e.target.value),
697
+ placeholder: "Choose a nickname",
698
+ disabled: saving,
699
+ style: input,
700
+ onFocus: inputFocusHandler,
701
+ onBlur: inputBlurHandler
702
+ }
703
+ )
704
+ ] }),
705
+ hasField("country") && /* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
706
+ /* @__PURE__ */ jsxs("label", { htmlFor: "dauth-country", style: label, children: [
707
+ "Country",
708
+ isRequired("country") ? " *" : ""
709
+ ] }),
710
+ /* @__PURE__ */ jsx(
711
+ "input",
712
+ {
713
+ id: "dauth-country",
714
+ type: "text",
715
+ value: country,
716
+ onChange: (e) => setCountry(e.target.value),
717
+ placeholder: "Your country",
718
+ disabled: saving,
719
+ style: input,
720
+ onFocus: inputFocusHandler,
721
+ onBlur: inputBlurHandler
722
+ }
723
+ )
724
+ ] })
725
+ ] }),
726
+ /* @__PURE__ */ jsx("hr", { style: separator }),
727
+ /* @__PURE__ */ jsxs("div", { children: [
728
+ /* @__PURE__ */ jsx("div", { style: dangerTitle, children: "Delete account" }),
729
+ /* @__PURE__ */ jsx("div", { style: dangerDesc, children: "Permanently delete your account and all associated data." }),
730
+ !showDelete ? /* @__PURE__ */ jsx(
731
+ "button",
732
+ {
733
+ type: "button",
734
+ style: deleteBtn,
735
+ onClick: () => setShowDelete(true),
736
+ onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "rgba(239, 68, 68, 0.2)",
737
+ onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))",
738
+ children: "Delete account"
739
+ }
740
+ ) : /* @__PURE__ */ jsxs("div", { style: deletePanel, children: [
741
+ /* @__PURE__ */ jsxs("div", { style: deletePanelText, children: [
742
+ "This action is permanent and cannot be undone. Type",
743
+ " ",
744
+ /* @__PURE__ */ jsx("strong", { children: CONFIRM_WORD }),
745
+ " to confirm."
746
+ ] }),
747
+ /* @__PURE__ */ jsx(
748
+ "input",
749
+ {
750
+ type: "text",
751
+ value: deleteText,
752
+ onChange: (e) => setDeleteText(e.target.value),
753
+ placeholder: `Type ${CONFIRM_WORD}`,
754
+ style: input,
755
+ onFocus: inputFocusHandler,
756
+ onBlur: inputBlurHandler,
757
+ disabled: deleting
758
+ }
759
+ ),
760
+ /* @__PURE__ */ jsxs(
761
+ "div",
762
+ {
763
+ style: {
764
+ display: "flex",
765
+ gap: 8,
766
+ marginTop: 12
767
+ },
768
+ children: [
769
+ /* @__PURE__ */ jsx(
770
+ "button",
771
+ {
772
+ type: "button",
773
+ style: cancelBtn,
774
+ onClick: () => {
775
+ setShowDelete(false);
776
+ setDeleteText("");
777
+ },
778
+ onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-surface-hover, #232340)",
779
+ onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "transparent",
780
+ children: "Cancel"
781
+ }
782
+ ),
783
+ /* @__PURE__ */ jsxs(
784
+ "button",
785
+ {
786
+ type: "button",
787
+ style: {
788
+ ...deleteConfirmBtn,
789
+ opacity: deleteText !== CONFIRM_WORD || deleting ? 0.5 : 1,
790
+ cursor: deleteText !== CONFIRM_WORD || deleting ? "not-allowed" : "pointer"
791
+ },
792
+ disabled: deleteText !== CONFIRM_WORD || deleting,
793
+ onClick: handleDelete,
794
+ children: [
795
+ deleting && /* @__PURE__ */ jsx(Spinner, {}),
796
+ "Delete my account"
797
+ ]
798
+ }
799
+ )
800
+ ]
801
+ }
802
+ )
803
+ ] })
804
+ ] })
805
+ ] }),
806
+ /* @__PURE__ */ jsx("div", { style: footerStyle(isDesktop), children: /* @__PURE__ */ jsxs(
807
+ "button",
808
+ {
809
+ type: "button",
810
+ style: {
811
+ ...saveBtn,
812
+ opacity: canSave ? 1 : 0.5,
813
+ cursor: canSave ? "pointer" : "not-allowed"
814
+ },
815
+ disabled: !canSave,
816
+ onClick: handleSave,
817
+ "aria-busy": saving,
818
+ onMouseEnter: (e) => {
819
+ if (canSave)
820
+ e.currentTarget.style.backgroundColor = "var(--dauth-accent-hover, #818cf8)";
821
+ },
822
+ onMouseLeave: (e) => {
823
+ e.currentTarget.style.backgroundColor = "var(--dauth-accent, #6366f1)";
824
+ },
825
+ children: [
826
+ saving && /* @__PURE__ */ jsx(Spinner, {}),
827
+ saving ? "Saving..." : "Save changes"
828
+ ]
829
+ }
830
+ ) })
831
+ ]
832
+ }
833
+ )
834
+ }
835
+ )
836
+ ] }),
837
+ document.body
838
+ );
839
+ }
840
+ var headerStyle = (isDesktop) => ({
841
+ display: "flex",
842
+ alignItems: "center",
843
+ justifyContent: "space-between",
844
+ padding: "16px 24px",
845
+ borderBottom: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
846
+ flexShrink: 0,
847
+ ...!isDesktop ? {
848
+ position: "sticky",
849
+ top: 0,
850
+ zIndex: 1,
851
+ backgroundColor: "var(--dauth-surface, #1a1a2e)"
852
+ } : {}
853
+ });
854
+ var titleStyle = {
855
+ fontSize: "var(--dauth-font-size-lg, 1.25rem)",
856
+ fontWeight: 600,
857
+ margin: 0,
858
+ lineHeight: 1.4,
859
+ textAlign: "center",
860
+ flex: 1
861
+ };
862
+ var closeBtn = {
863
+ display: "flex",
864
+ alignItems: "center",
865
+ justifyContent: "center",
866
+ width: 36,
867
+ height: 36,
868
+ borderRadius: "var(--dauth-radius-sm, 8px)",
869
+ border: "none",
870
+ backgroundColor: "transparent",
871
+ color: "var(--dauth-text-secondary, #a1a1aa)",
872
+ cursor: "pointer",
873
+ transition: "background-color 150ms, color 150ms",
874
+ padding: 0
875
+ };
876
+ var bodyStyle = {
877
+ flex: 1,
878
+ overflowY: "auto",
879
+ padding: 24,
880
+ WebkitOverflowScrolling: "touch"
881
+ };
882
+ var avatarSection = {
883
+ display: "flex",
884
+ flexDirection: "column",
885
+ alignItems: "center",
886
+ marginBottom: 24,
887
+ gap: 8
888
+ };
889
+ var avatarCircle = {
890
+ width: 64,
891
+ height: 64,
892
+ borderRadius: "50%",
893
+ backgroundColor: "var(--dauth-accent, #6366f1)",
894
+ display: "flex",
895
+ alignItems: "center",
896
+ justifyContent: "center",
897
+ overflow: "hidden",
898
+ color: "#ffffff",
899
+ fontSize: "1.5rem",
900
+ fontWeight: 600
901
+ };
902
+ var emailText = {
903
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
904
+ color: "var(--dauth-text-secondary, #a1a1aa)"
905
+ };
906
+ var statusMsg = (type) => ({
907
+ padding: "10px 14px",
908
+ borderRadius: "var(--dauth-radius-sm, 8px)",
909
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
910
+ marginBottom: 16,
911
+ backgroundColor: type === "success" ? "var(--dauth-success-bg, rgba(34, 197, 94, 0.1))" : "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))",
912
+ color: type === "success" ? "var(--dauth-success, #22c55e)" : "var(--dauth-error, #ef4444)",
913
+ textAlign: "center",
914
+ lineHeight: 1.5
915
+ });
916
+ var fieldGroup = { marginBottom: 16 };
917
+ var label = {
918
+ display: "block",
919
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
920
+ fontWeight: 500,
921
+ color: "var(--dauth-text-primary, #e4e4e7)",
922
+ marginBottom: 6
923
+ };
924
+ var input = {
925
+ width: "100%",
926
+ padding: "10px 14px",
927
+ fontSize: "var(--dauth-font-size-base, 1rem)",
928
+ lineHeight: 1.5,
929
+ color: "var(--dauth-text-primary, #e4e4e7)",
930
+ backgroundColor: "var(--dauth-surface-secondary, rgba(255, 255, 255, 0.04))",
931
+ border: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
932
+ borderRadius: "var(--dauth-radius-input, 8px)",
933
+ outline: "none",
934
+ transition: "border-color 150ms, box-shadow 150ms",
935
+ boxSizing: "border-box",
936
+ fontFamily: "inherit"
937
+ };
938
+ var inputFocusHandler = (e) => {
939
+ e.currentTarget.style.borderColor = "var(--dauth-border-focus, rgba(99, 102, 241, 0.5))";
940
+ e.currentTarget.style.boxShadow = "0 0 0 3px rgba(99, 102, 241, 0.15)";
941
+ };
942
+ var inputBlurHandler = (e) => {
943
+ e.currentTarget.style.borderColor = "var(--dauth-border, rgba(255, 255, 255, 0.08))";
944
+ e.currentTarget.style.boxShadow = "none";
945
+ };
946
+ var separator = {
947
+ height: 1,
948
+ backgroundColor: "var(--dauth-border, rgba(255, 255, 255, 0.08))",
949
+ margin: "24px 0",
950
+ border: "none"
951
+ };
952
+ var dangerTitle = {
953
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
954
+ fontWeight: 600,
955
+ color: "var(--dauth-error, #ef4444)",
956
+ marginBottom: 4
957
+ };
958
+ var dangerDesc = {
959
+ fontSize: "var(--dauth-font-size-xs, 0.75rem)",
960
+ color: "var(--dauth-text-muted, #71717a)",
961
+ marginBottom: 12,
962
+ lineHeight: 1.5
963
+ };
964
+ var deleteBtn = {
965
+ padding: "8px 16px",
966
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
967
+ fontWeight: 500,
968
+ color: "var(--dauth-error, #ef4444)",
969
+ backgroundColor: "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))",
970
+ border: "1px solid rgba(239, 68, 68, 0.2)",
971
+ borderRadius: "var(--dauth-radius-sm, 8px)",
972
+ cursor: "pointer",
973
+ transition: "background-color 150ms, border-color 150ms",
974
+ fontFamily: "inherit"
975
+ };
976
+ var deletePanel = {
977
+ marginTop: 12,
978
+ padding: 16,
979
+ borderRadius: "var(--dauth-radius-sm, 8px)",
980
+ border: "1px solid rgba(239, 68, 68, 0.3)",
981
+ backgroundColor: "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))"
982
+ };
983
+ var deletePanelText = {
984
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
985
+ color: "var(--dauth-text-primary, #e4e4e7)",
986
+ marginBottom: 12,
987
+ lineHeight: 1.5
988
+ };
989
+ var cancelBtn = {
990
+ flex: 1,
991
+ padding: "8px 16px",
992
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
993
+ fontWeight: 500,
994
+ color: "var(--dauth-text-secondary, #a1a1aa)",
995
+ backgroundColor: "transparent",
996
+ border: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
997
+ borderRadius: "var(--dauth-radius-sm, 8px)",
998
+ cursor: "pointer",
999
+ transition: "background-color 150ms",
1000
+ fontFamily: "inherit"
1001
+ };
1002
+ var deleteConfirmBtn = {
1003
+ flex: 1,
1004
+ padding: "8px 16px",
1005
+ fontSize: "var(--dauth-font-size-sm, 0.875rem)",
1006
+ fontWeight: 500,
1007
+ color: "#ffffff",
1008
+ backgroundColor: "var(--dauth-error, #ef4444)",
1009
+ border: "none",
1010
+ borderRadius: "var(--dauth-radius-sm, 8px)",
1011
+ cursor: "pointer",
1012
+ transition: "opacity 150ms",
1013
+ fontFamily: "inherit",
1014
+ display: "flex",
1015
+ alignItems: "center",
1016
+ justifyContent: "center",
1017
+ gap: 8
1018
+ };
1019
+ var footerStyle = (isDesktop) => ({
1020
+ padding: "16px 24px",
1021
+ borderTop: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
1022
+ flexShrink: 0,
1023
+ ...!isDesktop ? {
1024
+ position: "sticky",
1025
+ bottom: 0,
1026
+ zIndex: 1,
1027
+ backgroundColor: "var(--dauth-surface, #1a1a2e)",
1028
+ paddingBottom: "max(16px, env(safe-area-inset-bottom))"
1029
+ } : {}
1030
+ });
1031
+ var saveBtn = {
1032
+ width: "100%",
1033
+ padding: "12px 24px",
1034
+ fontSize: "var(--dauth-font-size-base, 1rem)",
1035
+ fontWeight: 600,
1036
+ color: "#ffffff",
1037
+ backgroundColor: "var(--dauth-accent, #6366f1)",
1038
+ border: "none",
1039
+ borderRadius: "var(--dauth-radius-sm, 8px)",
1040
+ transition: "opacity 150ms, background-color 150ms",
1041
+ display: "flex",
1042
+ alignItems: "center",
1043
+ justifyContent: "center",
1044
+ gap: 8,
1045
+ fontFamily: "inherit"
1046
+ };
1047
+ var spinnerStyle = {
1048
+ display: "inline-block",
1049
+ width: 16,
1050
+ height: 16,
1051
+ border: "2px solid rgba(255, 255, 255, 0.3)",
1052
+ borderTopColor: "#ffffff",
1053
+ borderRadius: "50%",
1054
+ animation: "dauth-spin 0.6s linear infinite"
1055
+ };
1056
+
342
1057
  // src/index.tsx
343
- import { jsx } from "react/jsx-runtime";
1058
+ import { jsx as jsx2 } from "react/jsx-runtime";
344
1059
  var defaultOnError = (error) => console.error(error);
345
1060
  var DauthProvider = (props) => {
346
1061
  const {
@@ -351,22 +1066,19 @@ var DauthProvider = (props) => {
351
1066
  env,
352
1067
  dauthUrl
353
1068
  } = props;
354
- const [dauthState, dispatch] = useReducer(
355
- userReducer,
356
- initialDauthState_default
357
- );
358
- useEffect(() => {
1069
+ const [dauthState, dispatch] = useReducer(userReducer, initialDauthState_default);
1070
+ useEffect2(() => {
359
1071
  setDauthUrl(dauthUrl);
360
1072
  }, [dauthUrl]);
361
- const handleError = useCallback(
1073
+ const handleError = useCallback2(
362
1074
  (error) => (onError ?? defaultOnError)(error),
363
1075
  [onError]
364
1076
  );
365
- const ctx = useMemo(
1077
+ const ctx = useMemo2(
366
1078
  () => ({ dispatch, authProxyPath, onError: handleError }),
367
1079
  [authProxyPath, handleError]
368
1080
  );
369
- useEffect(() => {
1081
+ useEffect2(() => {
370
1082
  const params = new URLSearchParams(window.location.search);
371
1083
  const code = params.get(AUTH_CODE_PARAM);
372
1084
  if (code) {
@@ -375,16 +1087,13 @@ var DauthProvider = (props) => {
375
1087
  autoLoginAction(ctx);
376
1088
  }
377
1089
  }, []);
378
- const loginWithRedirect = useCallback(() => {
1090
+ const loginWithRedirect = useCallback2(() => {
379
1091
  const base = `${getClientBasePath()}/${domainName}/${routes.signin}`;
380
1092
  const url = env ? `${base}?env=${encodeURIComponent(env)}` : base;
381
1093
  return window.location.replace(url);
382
1094
  }, [domainName, env]);
383
- const logout = useCallback(
384
- () => logoutAction(ctx),
385
- [ctx]
386
- );
387
- const updateUser = useCallback(
1095
+ const logout = useCallback2(() => logoutAction(ctx), [ctx]);
1096
+ const updateUser = useCallback2(
388
1097
  async (fields) => {
389
1098
  const {
390
1099
  name,
@@ -414,33 +1123,21 @@ var DauthProvider = (props) => {
414
1123
  },
415
1124
  [ctx]
416
1125
  );
417
- const updateUserWithRedirect = useCallback(
418
- () => updateUserWithRedirectAction(ctx),
419
- [ctx]
420
- );
421
- const deleteAccount = useCallback(
1126
+ const deleteAccount = useCallback2(
422
1127
  () => deleteAccountAction(ctx),
423
1128
  [ctx]
424
1129
  );
425
- const memoProvider = useMemo(
1130
+ const memoProvider = useMemo2(
426
1131
  () => ({
427
1132
  ...dauthState,
428
1133
  loginWithRedirect,
429
1134
  logout,
430
1135
  updateUser,
431
- updateUserWithRedirect,
432
1136
  deleteAccount
433
1137
  }),
434
- [
435
- dauthState,
436
- loginWithRedirect,
437
- logout,
438
- updateUser,
439
- updateUserWithRedirect,
440
- deleteAccount
441
- ]
1138
+ [dauthState, loginWithRedirect, logout, updateUser, deleteAccount]
442
1139
  );
443
- return /* @__PURE__ */ jsx(DauthContext.Provider, { value: memoProvider, children });
1140
+ return /* @__PURE__ */ jsx2(DauthContext.Provider, { value: memoProvider, children });
444
1141
  };
445
1142
  var DauthContext = createContext(initialDauthState_default);
446
1143
  var useDauth = () => {
@@ -451,6 +1148,7 @@ var useDauth = () => {
451
1148
  return context;
452
1149
  };
453
1150
  export {
1151
+ DauthProfileModal,
454
1152
  DauthProvider,
455
1153
  useDauth
456
1154
  };