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