@better-auth-ui/heroui 1.6.27 → 1.6.28

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.
@@ -0,0 +1,126 @@
1
+ import { authMutationKeys as e, getEmailProviderLink as t, getProviderName as n } from "@better-auth-ui/core";
2
+ import { providerIcons as r, useAuth as i, useSession as a, useSignInSocial as o } from "@better-auth-ui/react";
3
+ import { ArrowUpRightFromSquare as s, Person as c } from "@gravity-ui/icons";
4
+ import { Avatar as l, Button as u, Link as d, Separator as f, Skeleton as p, Spinner as m, cn as h } from "@heroui/react";
5
+ import { useMemo as g } from "react";
6
+ import { jsx as _, jsxs as v } from "react/jsx-runtime";
7
+ import { buttonVariants as y } from "@heroui/styles";
8
+ import { useIsMutating as b } from "@tanstack/react-query";
9
+ //#region src/components/auth/open-email-button.tsx
10
+ function x({ email: e, className: n }) {
11
+ let { localization: r } = i(), a = t(e);
12
+ return a ? /* @__PURE__ */ v(d, {
13
+ href: a.loginUrl,
14
+ target: "_blank",
15
+ rel: "noopener noreferrer",
16
+ className: h(y({ variant: "primary" }), "w-full gap-2", n),
17
+ children: [r.auth.openEmailProvider.replace("{{provider}}", a.companyProvider), /* @__PURE__ */ _(s, { className: "size-3" })]
18
+ }) : null;
19
+ }
20
+ //#endregion
21
+ //#region src/components/auth/field-separator.tsx
22
+ function S({ children: e }) {
23
+ return /* @__PURE__ */ v("div", {
24
+ className: "flex items-center gap-4",
25
+ children: [
26
+ /* @__PURE__ */ _(f, { className: "flex-1" }),
27
+ /* @__PURE__ */ _("p", {
28
+ className: "text-xs text-muted shrink-0",
29
+ children: e
30
+ }),
31
+ /* @__PURE__ */ _(f, { className: "flex-1" })
32
+ ]
33
+ });
34
+ }
35
+ //#endregion
36
+ //#region src/components/auth/provider-button.tsx
37
+ function C({ provider: t, display: a = "full", variant: s = "tertiary", ...c }) {
38
+ let { authClient: l, baseURL: d, localization: f, redirectTo: p } = i(), h = `${d}${p}`, { mutate: g, isPending: y } = o(l), x = r[t];
39
+ return /* @__PURE__ */ v(u, {
40
+ variant: s,
41
+ isPending: b({ mutationKey: e.signIn.all }) + b({ mutationKey: e.signUp.all }) > 0,
42
+ onPress: () => g({
43
+ provider: t,
44
+ callbackURL: h
45
+ }),
46
+ ...c,
47
+ "aria-label": n(t),
48
+ children: [y ? /* @__PURE__ */ _(m, {
49
+ color: "current",
50
+ size: "sm"
51
+ }) : /* @__PURE__ */ _(x, {}), a === "full" ? f.auth.continueWith.replace("{{provider}}", n(t)) : a === "name" ? n(t) : null]
52
+ });
53
+ }
54
+ //#endregion
55
+ //#region src/components/auth/provider-buttons.tsx
56
+ function w({ socialLayout: e = "auto" }) {
57
+ let { socialProviders: t } = i(), n = g(() => e === "auto" ? t?.length && t.length >= 4 ? "horizontal" : "vertical" : e, [e, t?.length]);
58
+ return /* @__PURE__ */ _("div", {
59
+ className: h("gap-3", n === "grid" && "grid grid-cols-2", n === "vertical" && "flex flex-col", n === "horizontal" && "flex flex-wrap"),
60
+ children: t?.map((e) => /* @__PURE__ */ _(C, {
61
+ provider: e,
62
+ display: n === "vertical" ? "full" : n === "grid" ? "name" : "icon",
63
+ className: h("w-full", n === "horizontal" && "flex-1")
64
+ }, e))
65
+ });
66
+ }
67
+ //#endregion
68
+ //#region src/components/auth/user/user-avatar.tsx
69
+ function T({ className: e, fallback: t, isPending: n, user: r, size: o = "sm", style: s, ...u }) {
70
+ let { authClient: d } = i(), { data: f, isPending: m } = a(d, { enabled: !r && !n });
71
+ if ((n || m) && !r) return /* @__PURE__ */ _(p, {
72
+ className: h("rounded-full", o === "sm" ? "size-8" : o === "md" ? "size-10" : "size-12", e),
73
+ style: s
74
+ });
75
+ let g = r ?? f?.user, y = (g?.username || g?.name || g?.email)?.slice(0, 2).toUpperCase();
76
+ return /* @__PURE__ */ v(l, {
77
+ size: o,
78
+ className: h("rounded-full", e),
79
+ style: s,
80
+ ...u,
81
+ children: [/* @__PURE__ */ _(l.Image, {
82
+ alt: g?.displayUsername || g?.name || g?.email,
83
+ src: g?.image ?? void 0
84
+ }), /* @__PURE__ */ _(l.Fallback, {
85
+ className: h(o === "lg" ? "text-xl" : o === "md" ? "text-base" : "text-sm"),
86
+ delayMs: g?.image ? 600 : void 0,
87
+ children: t || y || /* @__PURE__ */ _(c, { className: "size-4" })
88
+ })]
89
+ });
90
+ }
91
+ //#endregion
92
+ //#region src/components/auth/user/user-view.tsx
93
+ function E({ className: e, isPending: t, size: n = "md", hideSubtitle: r = !1, user: o, ...s }) {
94
+ let { authClient: c } = i(), { data: l, isPending: u } = a(c, { enabled: !o && !t }), d = o ?? l?.user;
95
+ return (t || u) && !o ? /* @__PURE__ */ v("div", {
96
+ className: h("flex items-center gap-2 min-w-0", e),
97
+ ...s,
98
+ children: [/* @__PURE__ */ _(T, {
99
+ isPending: !0,
100
+ className: n === "sm" ? "size-5 [&>span]:text-xs" : void 0,
101
+ size: n === "lg" ? "md" : "sm"
102
+ }), /* @__PURE__ */ v("div", {
103
+ className: "flex flex-col gap-1 min-w-0",
104
+ children: [/* @__PURE__ */ _(p, { className: "h-3.5 w-24 rounded-lg" }), r ? null : /* @__PURE__ */ _(p, { className: "h-3 w-32 rounded-lg" })]
105
+ })]
106
+ }) : /* @__PURE__ */ v("div", {
107
+ className: h("flex items-center gap-2 min-w-0", e),
108
+ ...s,
109
+ children: [/* @__PURE__ */ _(T, {
110
+ className: n === "sm" ? "size-5 [&>span]:text-xs" : void 0,
111
+ user: d,
112
+ size: n === "lg" ? "md" : "sm"
113
+ }), /* @__PURE__ */ v("div", {
114
+ className: "flex flex-col min-w-0",
115
+ children: [/* @__PURE__ */ _("p", {
116
+ className: "text-foreground text-sm font-medium leading-tight truncate",
117
+ children: d?.displayUsername || d?.name || d?.email
118
+ }), !r && (d?.displayUsername || d?.name) ? /* @__PURE__ */ _("p", {
119
+ className: "text-muted text-xs leading-tight truncate overflow-x-hidden",
120
+ children: d?.email
121
+ }) : null]
122
+ })]
123
+ });
124
+ }
125
+ //#endregion
126
+ export { S as a, C as i, T as n, x as o, w as r, E as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth-ui/heroui",
3
- "version": "1.6.27",
3
+ "version": "1.6.28",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "vite build",
@@ -4,6 +4,7 @@ import type { CardProps } from "@heroui/react"
4
4
  import { type ComponentType, useEffect } from "react"
5
5
  import { ForgotPassword } from "./forgot-password"
6
6
  import type { SocialLayout } from "./provider-buttons"
7
+ import { ResetLinkSent } from "./reset-link-sent"
7
8
  import { ResetPassword } from "./reset-password"
8
9
  import { SignIn } from "./sign-in"
9
10
  import { SignOut } from "./sign-out"
@@ -25,7 +26,12 @@ export type AuthProps = {
25
26
  * When it's disabled, the `<Auth>` router redirects these to `signIn` so a
26
27
  * plugin's `fallbackViews.auth.signIn` (e.g. magic link) takes over.
27
28
  */
28
- const PASSWORD_ONLY_VIEWS = ["signUp", "forgotPassword", "resetPassword"]
29
+ const PASSWORD_ONLY_VIEWS = [
30
+ "signUp",
31
+ "forgotPassword",
32
+ "resetPassword",
33
+ "resetLinkSent"
34
+ ]
29
35
 
30
36
  const AUTH_VIEWS: Partial<Record<AuthView, ComponentType<AuthProps>>> = {
31
37
  signIn: SignIn,
@@ -33,6 +39,7 @@ const AUTH_VIEWS: Partial<Record<AuthView, ComponentType<AuthProps>>> = {
33
39
  signUp: SignUp,
34
40
  forgotPassword: ForgotPassword,
35
41
  resetPassword: ResetPassword,
42
+ resetLinkSent: ResetLinkSent,
36
43
  verifyEmail: VerifyEmail
37
44
  }
38
45
 
@@ -15,11 +15,12 @@ import {
15
15
  Label,
16
16
  Link,
17
17
  Spinner,
18
- TextField,
19
- toast
18
+ TextField
20
19
  } from "@heroui/react"
21
20
  import type { SyntheticEvent } from "react"
22
21
 
22
+ import { RESET_LINK_SENT_STORAGE_KEY } from "./reset-link-sent"
23
+
23
24
  export type ForgotPasswordProps = {
24
25
  className?: string
25
26
  variant?: CardProps["variant"]
@@ -29,7 +30,9 @@ export type ForgotPasswordProps = {
29
30
  * Render a card-based "Forgot Password" form that sends a password-reset email.
30
31
  *
31
32
  * The form displays an email input, submit button, and a link back to sign-in.
32
- * Success toasts are shown via `useRequestPasswordReset`; errors are handled globally by `ErrorToaster`.
33
+ * After a successful request the submitted email is stored in `sessionStorage`
34
+ * and the user is redirected to the reset-link-sent view, which offers to open
35
+ * their email provider. Errors are handled globally by `ErrorToaster`.
33
36
  *
34
37
  * @param className - Optional additional CSS class names applied to the card
35
38
  * @returns The forgot-password form UI as a JSX element
@@ -53,9 +56,9 @@ export function ForgotPassword({ className, variant }: ForgotPasswordProps) {
53
56
  onError: () => {
54
57
  resetFetchOptions()
55
58
  },
56
- onSuccess: () => {
57
- toast.success(localization.auth.passwordResetEmailSent)
58
- navigate({ to: `${basePaths.auth}/${viewPaths.auth.signIn}` })
59
+ onSuccess: (_data, { email }) => {
60
+ sessionStorage.setItem(RESET_LINK_SENT_STORAGE_KEY, email)
61
+ navigate({ to: `${basePaths.auth}/${viewPaths.auth.resetLinkSent}` })
59
62
  }
60
63
  }
61
64
  )
@@ -0,0 +1,84 @@
1
+ import { useAuth, useAuthPlugin } from "@better-auth-ui/react"
2
+ import {
3
+ Card,
4
+ type CardProps,
5
+ cn,
6
+ Description,
7
+ Link,
8
+ useIsHydrated
9
+ } from "@heroui/react"
10
+ import { useEffect, useState } from "react"
11
+
12
+ import { magicLinkPlugin } from "../../../lib/auth/magic-link-plugin"
13
+ import { OpenEmailButton } from "../open-email-button"
14
+
15
+ /** `sessionStorage` key the magic-link form stores the submitted email under. */
16
+ export const MAGIC_LINK_SENT_STORAGE_KEY = "better-auth-ui.magic-link-sent"
17
+
18
+ export type MagicLinkSentProps = {
19
+ className?: string
20
+ variant?: CardProps["variant"]
21
+ }
22
+
23
+ /**
24
+ * Render a card confirming that a magic-link email was sent, with a button
25
+ * to open the user's email provider.
26
+ *
27
+ * The target email is read from `sessionStorage` (set when the magic-link
28
+ * form redirects here); the OpenEmail button is only shown when an email is
29
+ * stored and resolves to a known provider.
30
+ *
31
+ * @param className - Additional CSS classes applied to the outer card container
32
+ * @param variant - Variant to apply to the card
33
+ * @returns The magic-link-sent card React element
34
+ */
35
+ export function MagicLinkSent({ className, variant }: MagicLinkSentProps) {
36
+ const { basePaths, emailAndPassword, localization, viewPaths } = useAuth()
37
+ const { localization: magicLinkLocalization } = useAuthPlugin(magicLinkPlugin)
38
+
39
+ const isHydrated = useIsHydrated()
40
+ const [email, setEmail] = useState(
41
+ (isHydrated && sessionStorage.getItem(MAGIC_LINK_SENT_STORAGE_KEY)) || ""
42
+ )
43
+
44
+ useEffect(() => {
45
+ setEmail(sessionStorage.getItem(MAGIC_LINK_SENT_STORAGE_KEY) ?? "")
46
+ }, [])
47
+
48
+ return (
49
+ <Card
50
+ className={cn("w-full max-w-sm gap-4 md:p-6", className)}
51
+ variant={variant}
52
+ >
53
+ <Card.Header>
54
+ <Card.Title className="text-xl font-semibold mb-1">
55
+ {localization.auth.checkYourEmailTitle}
56
+ </Card.Title>
57
+ </Card.Header>
58
+
59
+ <Card.Content className="gap-4">
60
+ <Description className="text-sm">
61
+ {email
62
+ ? magicLinkLocalization.magicLinkSentTo.replace("{{email}}", email)
63
+ : magicLinkLocalization.magicLinkSent}
64
+ </Description>
65
+
66
+ {email && <OpenEmailButton email={email} />}
67
+ </Card.Content>
68
+
69
+ {emailAndPassword?.enabled && (
70
+ <Card.Footer className="flex-col gap-3">
71
+ <Description className="text-sm">
72
+ {localization.auth.needToCreateAnAccount}{" "}
73
+ <Link
74
+ href={`${basePaths.auth}/${viewPaths.auth.signUp}`}
75
+ className="text-accent no-underline hover:underline decoration-accent-hover"
76
+ >
77
+ {localization.auth.signUp}
78
+ </Link>
79
+ </Description>
80
+ </Card.Footer>
81
+ )}
82
+ </Card>
83
+ )
84
+ }
@@ -17,8 +17,7 @@ import {
17
17
  Label,
18
18
  Link,
19
19
  Spinner,
20
- TextField,
21
- toast
20
+ TextField
22
21
  } from "@heroui/react"
23
22
  import { useIsMutating } from "@tanstack/react-query"
24
23
  import { type SyntheticEvent, useState } from "react"
@@ -26,6 +25,7 @@ import { type SyntheticEvent, useState } from "react"
26
25
  import { magicLinkPlugin } from "../../../lib/auth/magic-link-plugin"
27
26
  import { FieldSeparator } from "../field-separator"
28
27
  import { ProviderButtons, type SocialLayout } from "../provider-buttons"
28
+ import { MAGIC_LINK_SENT_STORAGE_KEY } from "./magic-link-sent"
29
29
 
30
30
  export type MagicLinkProps = {
31
31
  className?: string
@@ -53,20 +53,24 @@ export function MagicLink({
53
53
  baseURL,
54
54
  emailAndPassword,
55
55
  localization,
56
+ navigate,
56
57
  plugins,
57
58
  redirectTo,
58
59
  socialProviders,
59
60
  viewPaths
60
61
  } = useAuth()
61
- const { localization: magicLinkLocalization } = useAuthPlugin(magicLinkPlugin)
62
+ const { localization: magicLinkLocalization, viewPaths: magicLinkViewPaths } =
63
+ useAuthPlugin(magicLinkPlugin)
62
64
 
63
65
  const [email, setEmail] = useState("")
64
66
 
65
67
  const { mutate: signInMagicLink, isPending: signInMagicLinkPending } =
66
68
  useSignInMagicLink(authClient as MagicLinkAuthClient, {
67
- onSuccess: () => {
68
- setEmail("")
69
- toast.success(magicLinkLocalization.magicLinkSent)
69
+ onSuccess: (_data, variables) => {
70
+ sessionStorage.setItem(MAGIC_LINK_SENT_STORAGE_KEY, variables.email)
71
+ navigate({
72
+ to: `${basePaths.auth}/${magicLinkViewPaths.auth.magicLinkSent}`
73
+ })
70
74
  }
71
75
  })
72
76
 
@@ -0,0 +1,80 @@
1
+ import { useAuth } from "@better-auth-ui/react"
2
+ import {
3
+ Card,
4
+ type CardProps,
5
+ cn,
6
+ Description,
7
+ Link,
8
+ useIsHydrated
9
+ } from "@heroui/react"
10
+ import { useEffect, useState } from "react"
11
+
12
+ import { OpenEmailButton } from "./open-email-button"
13
+
14
+ /** `sessionStorage` key the forgot-password form stores the submitted email under. */
15
+ export const RESET_LINK_SENT_STORAGE_KEY = "better-auth-ui.reset-link-sent"
16
+
17
+ export type ResetLinkSentProps = {
18
+ className?: string
19
+ variant?: CardProps["variant"]
20
+ }
21
+
22
+ /**
23
+ * Render a card confirming that a password-reset email was sent, with a
24
+ * button to open the user's email provider.
25
+ *
26
+ * The target email is read from `sessionStorage` (set when the forgot-password
27
+ * form redirects here); the OpenEmail button is only shown when an email is
28
+ * stored and resolves to a known provider.
29
+ *
30
+ * @param className - Additional CSS classes applied to the outer card container
31
+ * @param variant - Variant to apply to the card
32
+ * @returns The reset-link-sent card React element
33
+ */
34
+ export function ResetLinkSent({ className, variant }: ResetLinkSentProps) {
35
+ const { basePaths, localization, viewPaths } = useAuth()
36
+
37
+ const isHydrated = useIsHydrated()
38
+ const [email, setEmail] = useState(
39
+ (isHydrated && sessionStorage.getItem(RESET_LINK_SENT_STORAGE_KEY)) || ""
40
+ )
41
+
42
+ useEffect(() => {
43
+ setEmail(sessionStorage.getItem(RESET_LINK_SENT_STORAGE_KEY) ?? "")
44
+ }, [])
45
+
46
+ return (
47
+ <Card
48
+ className={cn("w-full max-w-sm gap-4 md:p-6", className)}
49
+ variant={variant}
50
+ >
51
+ <Card.Header>
52
+ <Card.Title className="text-xl font-semibold mb-1">
53
+ {localization.auth.checkYourEmailTitle}
54
+ </Card.Title>
55
+ </Card.Header>
56
+
57
+ <Card.Content className="gap-4">
58
+ <Description className="text-sm">
59
+ {email
60
+ ? localization.auth.resetLinkSentTo.replace("{{email}}", email)
61
+ : localization.auth.passwordResetEmailSent}
62
+ </Description>
63
+
64
+ {email && <OpenEmailButton email={email} />}
65
+ </Card.Content>
66
+
67
+ <Card.Footer className="flex-col gap-3">
68
+ <Description className="text-sm">
69
+ {localization.auth.rememberYourPassword}{" "}
70
+ <Link
71
+ href={`${basePaths.auth}/${viewPaths.auth.signIn}`}
72
+ className="text-accent no-underline hover:underline decoration-accent-hover"
73
+ >
74
+ {localization.auth.signIn}
75
+ </Link>
76
+ </Description>
77
+ </Card.Footer>
78
+ </Card>
79
+ )
80
+ }
@@ -25,6 +25,8 @@ import {
25
25
  } from "@heroui/react"
26
26
  import { type SyntheticEvent, useState } from "react"
27
27
 
28
+ import { OpenEmailButton } from "../../open-email-button"
29
+
28
30
  export type ChangePasswordProps = {
29
31
  className?: string
30
32
  variant?: CardProps["variant"]
@@ -77,6 +79,7 @@ function SetPassword({
77
79
  const { authClient, localization, plugins } = useAuth()
78
80
  const { data: session } = useSession(authClient)
79
81
  const { fetchOptions, resetFetchOptions } = useFetchOptions()
82
+ const [sentEmail, setSentEmail] = useState("")
80
83
 
81
84
  const { mutate: requestPasswordReset, isPending } = useRequestPasswordReset(
82
85
  authClient,
@@ -84,7 +87,9 @@ function SetPassword({
84
87
  onError: () => {
85
88
  resetFetchOptions()
86
89
  },
87
- onSuccess: () => toast.success(localization.auth.passwordResetEmailSent)
90
+ onSuccess: (_data, { email }) => {
91
+ setSentEmail(email)
92
+ }
88
93
  }
89
94
  )
90
95
 
@@ -115,19 +120,32 @@ function SetPassword({
115
120
  </p>
116
121
  </div>
117
122
 
118
- <div className="flex flex-col gap-3 items-start sm:items-end">
119
- {Captcha && <div>{Captcha}</div>}
120
-
121
- <Button
122
- size="sm"
123
- isPending={isPending}
124
- isDisabled={!session?.user.email}
125
- onPress={handleSetPassword}
126
- >
127
- {isPending && <Spinner color="current" size="sm" />}
128
- {localization.auth.sendResetLink}
129
- </Button>
130
- </div>
123
+ {sentEmail ? (
124
+ <div className="flex flex-col gap-3 items-start sm:items-end">
125
+ <p className="text-sm" role="status">
126
+ {localization.auth.resetLinkSentTo.replace(
127
+ "{{email}}",
128
+ sentEmail
129
+ )}
130
+ </p>
131
+
132
+ <OpenEmailButton email={sentEmail} className="w-auto" />
133
+ </div>
134
+ ) : (
135
+ <div className="flex flex-col gap-3 items-start sm:items-end">
136
+ {Captcha && <div>{Captcha}</div>}
137
+
138
+ <Button
139
+ size="sm"
140
+ isPending={isPending}
141
+ isDisabled={!session?.user.email}
142
+ onPress={handleSetPassword}
143
+ >
144
+ {isPending && <Spinner color="current" size="sm" />}
145
+ {localization.auth.sendResetLink}
146
+ </Button>
147
+ </div>
148
+ )}
131
149
  </Card.Content>
132
150
  </Card>
133
151
  </div>
package/src/index.tsx CHANGED
@@ -7,6 +7,7 @@ export * from "./components/auth/forgot-password"
7
7
  export * from "./components/auth/open-email-button"
8
8
  export * from "./components/auth/provider-button"
9
9
  export * from "./components/auth/provider-buttons"
10
+ export * from "./components/auth/reset-link-sent"
10
11
  export * from "./components/auth/reset-password"
11
12
  export * from "./components/auth/settings/account/account-settings"
12
13
  export * from "./components/auth/settings/account/change-email"
@@ -6,6 +6,7 @@ import {
6
6
 
7
7
  import { MagicLink } from "../../components/auth/magic-link/magic-link"
8
8
  import { MagicLinkButton } from "../../components/auth/magic-link/magic-link-button"
9
+ import { MagicLinkSent } from "../../components/auth/magic-link/magic-link-sent"
9
10
 
10
11
  export const magicLinkPlugin = createAuthPlugin(
11
12
  coreMagicLinkPlugin.id,
@@ -13,7 +14,7 @@ export const magicLinkPlugin = createAuthPlugin(
13
14
  ...coreMagicLinkPlugin(options),
14
15
  authButtons: [MagicLinkButton],
15
16
  views: {
16
- auth: { magicLink: MagicLink }
17
+ auth: { magicLink: MagicLink, magicLinkSent: MagicLinkSent }
17
18
  },
18
19
  // Conditional, not an override: when `emailAndPassword.enabled === false`
19
20
  // the `<Auth>` router renders this at `/auth/sign-in` instead of the
package/src/plugins.ts CHANGED
@@ -6,6 +6,7 @@ export * from "./components/auth/delete-user/danger-zone"
6
6
  export * from "./components/auth/delete-user/delete-account"
7
7
  // Plugin-contributed components that may be used standalone
8
8
  export * from "./components/auth/magic-link/magic-link"
9
+ export * from "./components/auth/magic-link/magic-link-sent"
9
10
  export * from "./components/auth/multi-session/manage-account"
10
11
  export * from "./components/auth/multi-session/manage-accounts"
11
12
  export * from "./components/auth/multi-session/switch-account-submenu"
@@ -1,113 +0,0 @@
1
- import { authMutationKeys as e, getProviderName as t } from "@better-auth-ui/core";
2
- import { providerIcons as n, useAuth as r, useSession as i, useSignInSocial as a } from "@better-auth-ui/react";
3
- import { Person as o } from "@gravity-ui/icons";
4
- import { Avatar as s, Button as c, Separator as l, Skeleton as u, Spinner as d, cn as f } from "@heroui/react";
5
- import { useMemo as p } from "react";
6
- import { jsx as m, jsxs as h } from "react/jsx-runtime";
7
- import { useIsMutating as g } from "@tanstack/react-query";
8
- //#region src/components/auth/field-separator.tsx
9
- function _({ children: e }) {
10
- return /* @__PURE__ */ h("div", {
11
- className: "flex items-center gap-4",
12
- children: [
13
- /* @__PURE__ */ m(l, { className: "flex-1" }),
14
- /* @__PURE__ */ m("p", {
15
- className: "text-xs text-muted shrink-0",
16
- children: e
17
- }),
18
- /* @__PURE__ */ m(l, { className: "flex-1" })
19
- ]
20
- });
21
- }
22
- //#endregion
23
- //#region src/components/auth/provider-button.tsx
24
- function v({ provider: i, display: o = "full", variant: s = "tertiary", ...l }) {
25
- let { authClient: u, baseURL: f, localization: p, redirectTo: _ } = r(), v = `${f}${_}`, { mutate: y, isPending: b } = a(u), x = n[i];
26
- return /* @__PURE__ */ h(c, {
27
- variant: s,
28
- isPending: g({ mutationKey: e.signIn.all }) + g({ mutationKey: e.signUp.all }) > 0,
29
- onPress: () => y({
30
- provider: i,
31
- callbackURL: v
32
- }),
33
- ...l,
34
- "aria-label": t(i),
35
- children: [b ? /* @__PURE__ */ m(d, {
36
- color: "current",
37
- size: "sm"
38
- }) : /* @__PURE__ */ m(x, {}), o === "full" ? p.auth.continueWith.replace("{{provider}}", t(i)) : o === "name" ? t(i) : null]
39
- });
40
- }
41
- //#endregion
42
- //#region src/components/auth/provider-buttons.tsx
43
- function y({ socialLayout: e = "auto" }) {
44
- let { socialProviders: t } = r(), n = p(() => e === "auto" ? t?.length && t.length >= 4 ? "horizontal" : "vertical" : e, [e, t?.length]);
45
- return /* @__PURE__ */ m("div", {
46
- className: f("gap-3", n === "grid" && "grid grid-cols-2", n === "vertical" && "flex flex-col", n === "horizontal" && "flex flex-wrap"),
47
- children: t?.map((e) => /* @__PURE__ */ m(v, {
48
- provider: e,
49
- display: n === "vertical" ? "full" : n === "grid" ? "name" : "icon",
50
- className: f("w-full", n === "horizontal" && "flex-1")
51
- }, e))
52
- });
53
- }
54
- //#endregion
55
- //#region src/components/auth/user/user-avatar.tsx
56
- function b({ className: e, fallback: t, isPending: n, user: a, size: c = "sm", style: l, ...d }) {
57
- let { authClient: p } = r(), { data: g, isPending: _ } = i(p, { enabled: !a && !n });
58
- if ((n || _) && !a) return /* @__PURE__ */ m(u, {
59
- className: f("rounded-full", c === "sm" ? "size-8" : c === "md" ? "size-10" : "size-12", e),
60
- style: l
61
- });
62
- let v = a ?? g?.user, y = (v?.username || v?.name || v?.email)?.slice(0, 2).toUpperCase();
63
- return /* @__PURE__ */ h(s, {
64
- size: c,
65
- className: f("rounded-full", e),
66
- style: l,
67
- ...d,
68
- children: [/* @__PURE__ */ m(s.Image, {
69
- alt: v?.displayUsername || v?.name || v?.email,
70
- src: v?.image ?? void 0
71
- }), /* @__PURE__ */ m(s.Fallback, {
72
- className: f(c === "lg" ? "text-xl" : c === "md" ? "text-base" : "text-sm"),
73
- delayMs: v?.image ? 600 : void 0,
74
- children: t || y || /* @__PURE__ */ m(o, { className: "size-4" })
75
- })]
76
- });
77
- }
78
- //#endregion
79
- //#region src/components/auth/user/user-view.tsx
80
- function x({ className: e, isPending: t, size: n = "md", hideSubtitle: a = !1, user: o, ...s }) {
81
- let { authClient: c } = r(), { data: l, isPending: d } = i(c, { enabled: !o && !t }), p = o ?? l?.user;
82
- return (t || d) && !o ? /* @__PURE__ */ h("div", {
83
- className: f("flex items-center gap-2 min-w-0", e),
84
- ...s,
85
- children: [/* @__PURE__ */ m(b, {
86
- isPending: !0,
87
- className: n === "sm" ? "size-5 [&>span]:text-xs" : void 0,
88
- size: n === "lg" ? "md" : "sm"
89
- }), /* @__PURE__ */ h("div", {
90
- className: "flex flex-col gap-1 min-w-0",
91
- children: [/* @__PURE__ */ m(u, { className: "h-3.5 w-24 rounded-lg" }), a ? null : /* @__PURE__ */ m(u, { className: "h-3 w-32 rounded-lg" })]
92
- })]
93
- }) : /* @__PURE__ */ h("div", {
94
- className: f("flex items-center gap-2 min-w-0", e),
95
- ...s,
96
- children: [/* @__PURE__ */ m(b, {
97
- className: n === "sm" ? "size-5 [&>span]:text-xs" : void 0,
98
- user: p,
99
- size: n === "lg" ? "md" : "sm"
100
- }), /* @__PURE__ */ h("div", {
101
- className: "flex flex-col min-w-0",
102
- children: [/* @__PURE__ */ m("p", {
103
- className: "text-foreground text-sm font-medium leading-tight truncate",
104
- children: p?.displayUsername || p?.name || p?.email
105
- }), !a && (p?.displayUsername || p?.name) ? /* @__PURE__ */ m("p", {
106
- className: "text-muted text-xs leading-tight truncate overflow-x-hidden",
107
- children: p?.email
108
- }) : null]
109
- })]
110
- });
111
- }
112
- //#endregion
113
- export { _ as a, v as i, b as n, y as r, x as t };