@better-auth-ui/heroui 1.6.1 → 1.6.3

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.
Files changed (117) hide show
  1. package/dist/components/auth/auth-provider.d.ts +1 -1
  2. package/dist/components/auth/auth-provider.js +16 -11
  3. package/dist/components/auth/auth.d.ts +4 -4
  4. package/dist/components/auth/auth.js +36 -41
  5. package/dist/components/auth/error-toaster.d.ts +1 -0
  6. package/dist/components/auth/error-toaster.js +17 -0
  7. package/dist/components/auth/field-separator.d.ts +1 -1
  8. package/dist/components/auth/field-separator.js +17 -4
  9. package/dist/components/auth/forgot-password.d.ts +2 -2
  10. package/dist/components/auth/forgot-password.js +66 -27
  11. package/dist/components/auth/magic-link-button.d.ts +1 -1
  12. package/dist/components/auth/magic-link-button.js +15 -18
  13. package/dist/components/auth/magic-link.d.ts +3 -3
  14. package/dist/components/auth/magic-link.js +98 -43
  15. package/dist/components/auth/passkey-button.js +20 -12
  16. package/dist/components/auth/provider-button.d.ts +15 -0
  17. package/dist/components/auth/provider-button.js +29 -0
  18. package/dist/components/auth/provider-buttons.d.ts +4 -10
  19. package/dist/components/auth/provider-buttons.js +19 -33
  20. package/dist/components/auth/reset-password.d.ts +2 -2
  21. package/dist/components/auth/reset-password.js +143 -57
  22. package/dist/components/auth/sign-in.d.ts +3 -3
  23. package/dist/components/auth/sign-in.js +151 -64
  24. package/dist/components/auth/sign-out.js +26 -32
  25. package/dist/components/auth/sign-up.d.ts +3 -3
  26. package/dist/components/auth/sign-up.js +231 -70
  27. package/dist/components/email/email-changed-email.d.ts +2 -2
  28. package/dist/components/email/email-changed-email.js +29 -22
  29. package/dist/components/email/email-verification-email.d.ts +2 -2
  30. package/dist/components/email/email-verification-email.js +29 -22
  31. package/dist/components/email/magic-link-email.d.ts +2 -2
  32. package/dist/components/email/magic-link-email.js +29 -22
  33. package/dist/components/email/new-device-email.d.ts +2 -2
  34. package/dist/components/email/new-device-email.js +29 -22
  35. package/dist/components/email/otp-email.d.ts +2 -2
  36. package/dist/components/email/otp-email.js +28 -21
  37. package/dist/components/email/password-changed-email.d.ts +2 -2
  38. package/dist/components/email/password-changed-email.js +29 -22
  39. package/dist/components/email/reset-password-email.d.ts +2 -2
  40. package/dist/components/email/reset-password-email.js +29 -22
  41. package/dist/components/settings/account/account-settings.d.ts +2 -2
  42. package/dist/components/settings/account/account-settings.js +22 -19
  43. package/dist/components/settings/account/appearance.d.ts +2 -2
  44. package/dist/components/settings/account/appearance.js +70 -27
  45. package/dist/components/settings/account/change-avatar.js +88 -55
  46. package/dist/components/settings/account/change-email.d.ts +2 -2
  47. package/dist/components/settings/account/change-email.js +53 -28
  48. package/dist/components/settings/account/manage-account.d.ts +1 -1
  49. package/dist/components/settings/account/manage-account.js +47 -31
  50. package/dist/components/settings/account/manage-accounts.d.ts +2 -2
  51. package/dist/components/settings/account/manage-accounts.js +32 -36
  52. package/dist/components/settings/account/user-profile.d.ts +4 -4
  53. package/dist/components/settings/account/user-profile.js +102 -22
  54. package/dist/components/settings/security/active-session.d.ts +1 -1
  55. package/dist/components/settings/security/active-session.js +57 -51
  56. package/dist/components/settings/security/active-sessions.d.ts +2 -2
  57. package/dist/components/settings/security/active-sessions.js +32 -26
  58. package/dist/components/settings/security/change-password.d.ts +2 -2
  59. package/dist/components/settings/security/change-password.js +186 -76
  60. package/dist/components/settings/security/danger-zone.d.ts +2 -2
  61. package/dist/components/settings/security/danger-zone.js +17 -11
  62. package/dist/components/settings/security/delete-user.d.ts +2 -2
  63. package/dist/components/settings/security/delete-user.js +91 -46
  64. package/dist/components/settings/security/linked-account.d.ts +1 -1
  65. package/dist/components/settings/security/linked-account.js +55 -47
  66. package/dist/components/settings/security/linked-accounts.d.ts +2 -2
  67. package/dist/components/settings/security/linked-accounts.js +43 -40
  68. package/dist/components/settings/security/passkey.js +42 -13
  69. package/dist/components/settings/security/passkeys.d.ts +2 -2
  70. package/dist/components/settings/security/passkeys.js +51 -19
  71. package/dist/components/settings/security/security-settings.d.ts +2 -2
  72. package/dist/components/settings/security/security-settings.js +24 -21
  73. package/dist/components/settings/settings.d.ts +3 -3
  74. package/dist/components/settings/settings.js +44 -27
  75. package/dist/components/user/switch-account-item.d.ts +1 -1
  76. package/dist/components/user/switch-account-item.js +19 -15
  77. package/dist/components/user/switch-account-menu.js +27 -28
  78. package/dist/components/user/user-avatar.d.ts +3 -3
  79. package/dist/components/user/user-avatar.js +28 -30
  80. package/dist/components/user/user-button.d.ts +1 -1
  81. package/dist/components/user/user-button.js +90 -23
  82. package/dist/components/user/user-view.d.ts +3 -3
  83. package/dist/components/user/user-view.js +36 -23
  84. package/dist/core.d.ts +1 -1
  85. package/dist/index.d.ts +36 -35
  86. package/dist/index.js +37 -35
  87. package/dist/react-exports.d.ts +1 -1
  88. package/package.json +15 -11
  89. package/src/components/auth/auth-provider.tsx +4 -0
  90. package/src/components/auth/auth.tsx +2 -2
  91. package/src/components/auth/error-toaster.tsx +25 -0
  92. package/src/components/auth/forgot-password.tsx +1 -2
  93. package/src/components/auth/magic-link.tsx +3 -23
  94. package/src/components/auth/passkey-button.tsx +1 -2
  95. package/src/components/auth/provider-button.tsx +67 -0
  96. package/src/components/auth/provider-buttons.tsx +26 -43
  97. package/src/components/auth/reset-password.tsx +1 -2
  98. package/src/components/auth/sign-in.tsx +63 -48
  99. package/src/components/auth/sign-up.tsx +99 -20
  100. package/src/components/settings/account/appearance.tsx +1 -1
  101. package/src/components/settings/account/change-avatar.tsx +1 -3
  102. package/src/components/settings/account/change-email.tsx +2 -3
  103. package/src/components/settings/account/manage-account.tsx +1 -4
  104. package/src/components/settings/account/manage-accounts.tsx +3 -8
  105. package/src/components/settings/account/user-profile.tsx +122 -8
  106. package/src/components/settings/security/active-session.tsx +0 -1
  107. package/src/components/settings/security/active-sessions.tsx +3 -8
  108. package/src/components/settings/security/change-password.tsx +7 -4
  109. package/src/components/settings/security/delete-user.tsx +1 -4
  110. package/src/components/settings/security/linked-account.tsx +4 -14
  111. package/src/components/settings/security/linked-accounts.tsx +3 -8
  112. package/src/components/settings/security/passkey.tsx +2 -4
  113. package/src/components/settings/security/passkeys.tsx +4 -12
  114. package/src/components/settings/settings.tsx +1 -1
  115. package/src/components/user/switch-account-item.tsx +2 -4
  116. package/src/components/user/switch-account-menu.tsx +2 -7
  117. package/src/index.tsx +1 -0
@@ -1,4 +1,4 @@
1
- import { type AuthProviderProps as AuthProviderPropsPrimitive } from "@better-auth-ui/react";
1
+ import { AuthProviderProps as AuthProviderPropsPrimitive } from '@better-auth-ui/react';
2
2
  export type AuthProviderProps = Omit<AuthProviderPropsPrimitive, "Link">;
3
3
  /**
4
4
  * Provides an authentication context by rendering an auth provider with the sonner toast handler injected, forwarding remaining configuration and rendering `children` inside it.
@@ -1,12 +1,17 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { AuthProvider as AuthProviderPrimitive } from "@better-auth-ui/react";
3
- import { RouterProvider } from "@heroui/react";
4
- /**
5
- * Provides an authentication context by rendering an auth provider with the sonner toast handler injected, forwarding remaining configuration and rendering `children` inside it.
6
- *
7
- * @param children - React nodes to render inside the authentication provider
8
- * @returns A React element that renders an authentication provider configured with the provided props and toast handler
9
- */
10
- export function AuthProvider({ children, navigate, ...config }) {
11
- return (_jsx(AuthProviderPrimitive, { navigate: navigate, ...config, children: _jsx(RouterProvider, { navigate: (path) => navigate({ to: path }), children: children }) }));
1
+ import { ErrorToaster as e } from "./error-toaster.js";
2
+ import { AuthProvider as t } from "@better-auth-ui/react";
3
+ import { RouterProvider as n } from "@heroui/react";
4
+ import { jsx as r, jsxs as i } from "react/jsx-runtime";
5
+ //#region src/components/auth/auth-provider.tsx
6
+ function a({ children: a, navigate: o, ...s }) {
7
+ return /* @__PURE__ */ r(t, {
8
+ navigate: o,
9
+ ...s,
10
+ children: /* @__PURE__ */ i(n, {
11
+ navigate: (e) => o({ to: e }),
12
+ children: [a, /* @__PURE__ */ r(e, {})]
13
+ })
14
+ });
12
15
  }
16
+ //#endregion
17
+ export { a as AuthProvider };
@@ -1,6 +1,6 @@
1
- import type { AuthView } from "@better-auth-ui/react/core";
2
- import type { CardProps } from "@heroui/react";
3
- import type { SocialLayout } from "./provider-buttons";
1
+ import { AuthView } from '@better-auth-ui/core';
2
+ import { CardProps } from '@heroui/react';
3
+ import { SocialLayout } from './provider-buttons';
4
4
  export type AuthProps = {
5
5
  className?: string;
6
6
  path?: string;
@@ -20,4 +20,4 @@ export type AuthProps = {
20
20
  * @param view - Explicit auth view to render (e.g., "signIn", "signUp")
21
21
  * @returns The React element for the resolved authentication view
22
22
  */
23
- export declare function Auth({ path, socialLayout, socialPosition, view, ...props }: AuthProps & CardProps): import("react/jsx-runtime").JSX.Element;
23
+ export declare function Auth({ path, socialLayout, socialPosition, view, ...props }: AuthProps & Omit<CardProps, "children">): import("react/jsx-runtime").JSX.Element;
@@ -1,42 +1,37 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useAuth } from "@better-auth-ui/react";
3
- import { ForgotPassword } from "./forgot-password";
4
- import { MagicLink } from "./magic-link";
5
- import { ResetPassword } from "./reset-password";
6
- import { SignIn } from "./sign-in";
7
- import { SignOut } from "./sign-out";
8
- import { SignUp } from "./sign-up";
9
- /**
10
- * Render the appropriate authentication view based on the provided `view` or `path`.
11
- *
12
- * @param path - Route path used to resolve an auth view when `view` is not provided
13
- * @param socialLayout - Social layout to apply to sign-in/sign-up/magic-link views
14
- * @param socialPosition - Position for social buttons ("top" or "bottom")
15
- * @param variant - Variant to apply to the card
16
- * @param view - Explicit auth view to render (e.g., "signIn", "signUp")
17
- * @returns The React element for the resolved authentication view
18
- */
19
- export function Auth({ path, socialLayout, socialPosition, view, ...props }) {
20
- const { viewPaths } = useAuth();
21
- if (!view && !path) {
22
- throw new Error("[Better Auth UI] Either `view` or `path` must be provided");
23
- }
24
- const authPathViews = Object.fromEntries(Object.entries(viewPaths.auth).map(([k, v]) => [v, k]));
25
- const currentView = view || (path ? authPathViews[path] : undefined);
26
- switch (currentView) {
27
- case "signIn":
28
- return (_jsx(SignIn, { socialLayout: socialLayout, socialPosition: socialPosition, ...props }));
29
- case "signUp":
30
- return (_jsx(SignUp, { socialLayout: socialLayout, socialPosition: socialPosition, ...props }));
31
- case "magicLink":
32
- return (_jsx(MagicLink, { socialLayout: socialLayout, socialPosition: socialPosition, ...props }));
33
- case "forgotPassword":
34
- return _jsx(ForgotPassword, { ...props });
35
- case "resetPassword":
36
- return _jsx(ResetPassword, { ...props });
37
- case "signOut":
38
- return _jsx(SignOut, { ...props });
39
- default:
40
- throw new Error(`[Better Auth UI] Valid views are: ${Object.keys(viewPaths.auth).join(", ")}`);
41
- }
1
+ import { ForgotPassword as e } from "./forgot-password.js";
2
+ import { MagicLink as t } from "./magic-link.js";
3
+ import { ResetPassword as n } from "./reset-password.js";
4
+ import { SignIn as r } from "./sign-in.js";
5
+ import { SignOut as i } from "./sign-out.js";
6
+ import { SignUp as a } from "./sign-up.js";
7
+ import { useAuth as o } from "@better-auth-ui/react";
8
+ import { jsx as s } from "react/jsx-runtime";
9
+ //#region src/components/auth/auth.tsx
10
+ function c({ path: c, socialLayout: l, socialPosition: u, view: d, ...f }) {
11
+ let { viewPaths: p } = o();
12
+ if (!d && !c) throw Error("[Better Auth UI] Either `view` or `path` must be provided");
13
+ let m = Object.fromEntries(Object.entries(p.auth).map(([e, t]) => [t, e]));
14
+ switch (d || (c ? m[c] : void 0)) {
15
+ case "signIn": return /* @__PURE__ */ s(r, {
16
+ socialLayout: l,
17
+ socialPosition: u,
18
+ ...f
19
+ });
20
+ case "signUp": return /* @__PURE__ */ s(a, {
21
+ socialLayout: l,
22
+ socialPosition: u,
23
+ ...f
24
+ });
25
+ case "magicLink": return /* @__PURE__ */ s(t, {
26
+ socialLayout: l,
27
+ socialPosition: u,
28
+ ...f
29
+ });
30
+ case "forgotPassword": return /* @__PURE__ */ s(e, { ...f });
31
+ case "resetPassword": return /* @__PURE__ */ s(n, { ...f });
32
+ case "signOut": return /* @__PURE__ */ s(i, { ...f });
33
+ default: throw Error(`[Better Auth UI] Valid views are: ${Object.keys(p.auth).join(", ")}`);
34
+ }
42
35
  }
36
+ //#endregion
37
+ export { c as Auth };
@@ -0,0 +1 @@
1
+ export declare function ErrorToaster(): null;
@@ -0,0 +1,17 @@
1
+ import { toast as e } from "@heroui/react";
2
+ import { useEffect as t } from "react";
3
+ import { useQueryClient as n } from "@tanstack/react-query";
4
+ //#region src/components/auth/error-toaster.tsx
5
+ function r() {
6
+ let r = n();
7
+ return t(() => {
8
+ r.getQueryCache().config.onError = (t) => {
9
+ let n = t;
10
+ n?.error && e.danger(n.error.message);
11
+ }, r.setMutationDefaults([], { onError: (t) => {
12
+ e.danger(t?.error?.message || t.message);
13
+ } });
14
+ }, [r]), null;
15
+ }
16
+ //#endregion
17
+ export { r as ErrorToaster };
@@ -1,4 +1,4 @@
1
- import type { ReactNode } from "react";
1
+ import { ReactNode } from 'react';
2
2
  export declare function FieldSeparator({ children }: {
3
3
  children: ReactNode;
4
4
  }): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,18 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Separator } from "@heroui/react";
3
- export function FieldSeparator({ children }) {
4
- return (_jsxs("div", { className: "flex items-center gap-4", children: [_jsx(Separator, { className: "flex-1" }), _jsx("p", { className: "text-xs text-muted shrink-0", children: children }), _jsx(Separator, { className: "flex-1" })] }));
1
+ import { Separator as e } from "@heroui/react";
2
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
+ //#region src/components/auth/field-separator.tsx
4
+ function r({ children: r }) {
5
+ return /* @__PURE__ */ n("div", {
6
+ className: "flex items-center gap-4",
7
+ children: [
8
+ /* @__PURE__ */ t(e, { className: "flex-1" }),
9
+ /* @__PURE__ */ t("p", {
10
+ className: "text-xs text-muted shrink-0",
11
+ children: r
12
+ }),
13
+ /* @__PURE__ */ t(e, { className: "flex-1" })
14
+ ]
15
+ });
5
16
  }
17
+ //#endregion
18
+ export { r as FieldSeparator };
@@ -1,4 +1,4 @@
1
- import { type CardProps } from "@heroui/react";
1
+ import { CardProps } from '@heroui/react';
2
2
  export type ForgotPasswordProps = {
3
3
  className?: string;
4
4
  variant?: CardProps["variant"];
@@ -12,4 +12,4 @@ export type ForgotPasswordProps = {
12
12
  * @param className - Optional additional CSS class names applied to the card
13
13
  * @returns The forgot-password form UI as a JSX element
14
14
  */
15
- export declare function ForgotPassword({ className, variant, ...props }: ForgotPasswordProps & CardProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function ForgotPassword({ className, variant, ...props }: ForgotPasswordProps & Omit<CardProps, "children">): import("react/jsx-runtime").JSX.Element;
@@ -1,28 +1,67 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useAuth, useRequestPasswordReset } from "@better-auth-ui/react";
3
- import { Button, Card, cn, Description, FieldError, Form, Input, Label, Link, Spinner, TextField, toast } from "@heroui/react";
4
- /**
5
- * Render a card-based "Forgot Password" form that sends a password-reset email.
6
- *
7
- * The form displays an email input, submit button, and a link back to sign-in.
8
- * Toasts are displayed on success or error via the `useForgotPassword` hook.
9
- *
10
- * @param className - Optional additional CSS class names applied to the card
11
- * @returns The forgot-password form UI as a JSX element
12
- */
13
- export function ForgotPassword({ className, variant, ...props }) {
14
- const { basePaths, localization, viewPaths, navigate } = useAuth();
15
- const { mutate: requestPasswordReset, isPending } = useRequestPasswordReset({
16
- onError: (error) => toast.danger(error.error?.message || error.message),
17
- onSuccess: () => {
18
- toast.success(localization.auth.passwordResetEmailSent);
19
- navigate({ to: `${basePaths.auth}/${viewPaths.auth.signIn}` });
20
- }
21
- });
22
- function handleSubmit(e) {
23
- e.preventDefault();
24
- const formData = new FormData(e.currentTarget);
25
- requestPasswordReset({ email: formData.get("email") });
26
- }
27
- return (_jsxs(Card, { className: cn("w-full max-w-sm p-4 md:p-6", className), variant: variant, ...props, children: [_jsx(Card.Header, { children: _jsx(Card.Title, { className: "text-xl font-semibold mb-1", children: localization.auth.forgotPassword }) }), _jsx(Card.Content, { children: _jsxs(Form, { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs(TextField, { name: "email", type: "email", autoComplete: "email", isDisabled: isPending, children: [_jsx(Label, { children: localization.auth.email }), _jsx(Input, { placeholder: localization.auth.emailPlaceholder, required: true, variant: variant === "transparent" ? "primary" : "secondary" }), _jsx(FieldError, {})] }), _jsxs(Button, { type: "submit", className: "w-full", isPending: isPending, children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), localization.auth.sendResetLink] })] }) }), _jsx(Card.Footer, { className: "flex-col", children: _jsxs(Description, { className: "text-sm", children: [localization.auth.rememberYourPassword, " ", _jsx(Link, { href: `${basePaths.auth}/${viewPaths.auth.signIn}`, className: "text-accent decoration-accent no-underline hover:underline", children: localization.auth.signIn })] }) })] }));
1
+ import { useAuth as e, useRequestPasswordReset as t } from "@better-auth-ui/react";
2
+ import { Button as n, Card as r, Description as i, FieldError as a, Form as o, Input as s, Label as c, Link as l, Spinner as u, TextField as d, cn as f, toast as p } from "@heroui/react";
3
+ import { jsx as m, jsxs as h } from "react/jsx-runtime";
4
+ //#region src/components/auth/forgot-password.tsx
5
+ function g({ className: g, variant: _, ...v }) {
6
+ let { basePaths: y, localization: b, viewPaths: x, navigate: S } = e(), { mutate: C, isPending: w } = t({ onSuccess: () => {
7
+ p.success(b.auth.passwordResetEmailSent), S({ to: `${y.auth}/${x.auth.signIn}` });
8
+ } });
9
+ function T(e) {
10
+ e.preventDefault(), C({ email: new FormData(e.currentTarget).get("email") });
11
+ }
12
+ return /* @__PURE__ */ h(r, {
13
+ className: f("w-full max-w-sm p-4 md:p-6", g),
14
+ variant: _,
15
+ ...v,
16
+ children: [
17
+ /* @__PURE__ */ m(r.Header, { children: /* @__PURE__ */ m(r.Title, {
18
+ className: "text-xl font-semibold mb-1",
19
+ children: b.auth.forgotPassword
20
+ }) }),
21
+ /* @__PURE__ */ m(r.Content, { children: /* @__PURE__ */ h(o, {
22
+ onSubmit: T,
23
+ className: "flex flex-col gap-4",
24
+ children: [/* @__PURE__ */ h(d, {
25
+ name: "email",
26
+ type: "email",
27
+ autoComplete: "email",
28
+ isDisabled: w,
29
+ children: [
30
+ /* @__PURE__ */ m(c, { children: b.auth.email }),
31
+ /* @__PURE__ */ m(s, {
32
+ placeholder: b.auth.emailPlaceholder,
33
+ required: !0,
34
+ variant: _ === "transparent" ? "primary" : "secondary"
35
+ }),
36
+ /* @__PURE__ */ m(a, {})
37
+ ]
38
+ }), /* @__PURE__ */ h(n, {
39
+ type: "submit",
40
+ className: "w-full",
41
+ isPending: w,
42
+ children: [w && /* @__PURE__ */ m(u, {
43
+ color: "current",
44
+ size: "sm"
45
+ }), b.auth.sendResetLink]
46
+ })]
47
+ }) }),
48
+ /* @__PURE__ */ m(r.Footer, {
49
+ className: "flex-col",
50
+ children: /* @__PURE__ */ h(i, {
51
+ className: "text-sm",
52
+ children: [
53
+ b.auth.rememberYourPassword,
54
+ " ",
55
+ /* @__PURE__ */ m(l, {
56
+ href: `${y.auth}/${x.auth.signIn}`,
57
+ className: "text-accent decoration-accent no-underline hover:underline",
58
+ children: b.auth.signIn
59
+ })
60
+ ]
61
+ })
62
+ })
63
+ ]
64
+ });
28
65
  }
66
+ //#endregion
67
+ export { g as ForgotPassword };
@@ -1,4 +1,4 @@
1
- import type { AuthView } from "@better-auth-ui/core";
1
+ import { AuthView } from '@better-auth-ui/core';
2
2
  export type MagicLinkButtonProps = {
3
3
  isPending: boolean;
4
4
  view?: AuthView;
@@ -1,19 +1,16 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useAuth } from "@better-auth-ui/react";
3
- import { Envelope, Lock } from "@gravity-ui/icons";
4
- import { cn, Link } from "@heroui/react";
5
- import { buttonVariants } from "@heroui/styles";
6
- /**
7
- * Renders a full-width tertiary link-style button that navigates to either the magic-link or sign-in route.
8
- *
9
- * @param isPending - If true, applies disabled styling and prevents interaction
10
- * @param view - Current auth view; when `"magicLink"`, the button targets the sign-in/password variant
11
- * @returns The rendered Link element with the appropriate href, icon, and label
12
- */
13
- export function MagicLinkButton({ isPending, view }) {
14
- const { basePaths, viewPaths, localization } = useAuth();
15
- const isMagicLinkView = view === "magicLink";
16
- return (_jsxs(Link, { href: `${basePaths.auth}/${isMagicLinkView ? viewPaths.auth.signIn : viewPaths.auth.magicLink}`, className: cn(buttonVariants({ variant: "tertiary" }), "w-full gap-2", isPending && "status-disabled pointer-events-none"), children: [isMagicLinkView ? _jsx(Lock, {}) : _jsx(Envelope, {}), localization.auth.continueWith.replace("{{provider}}", isMagicLinkView
17
- ? localization.auth.password
18
- : localization.auth.magicLink)] }));
1
+ import { useAuth as e } from "@better-auth-ui/react";
2
+ import { Link as t, cn as n } from "@heroui/react";
3
+ import { jsx as r, jsxs as i } from "react/jsx-runtime";
4
+ import { Envelope as a, Lock as o } from "@gravity-ui/icons";
5
+ import { buttonVariants as s } from "@heroui/styles";
6
+ //#region src/components/auth/magic-link-button.tsx
7
+ function c({ isPending: c, view: l }) {
8
+ let { basePaths: u, viewPaths: d, localization: f } = e(), p = l === "magicLink";
9
+ return /* @__PURE__ */ i(t, {
10
+ href: `${u.auth}/${p ? d.auth.signIn : d.auth.magicLink}`,
11
+ className: n(s({ variant: "tertiary" }), "w-full gap-2", c && "status-disabled pointer-events-none"),
12
+ children: [r(p ? o : a, {}), f.auth.continueWith.replace("{{provider}}", p ? f.auth.password : f.auth.magicLink)]
13
+ });
19
14
  }
15
+ //#endregion
16
+ export { c as MagicLinkButton };
@@ -1,5 +1,5 @@
1
- import { type CardProps } from "@heroui/react";
2
- import { type SocialLayout } from "./provider-buttons";
1
+ import { CardProps } from '@heroui/react';
2
+ import { SocialLayout } from './provider-buttons';
3
3
  export type MagicLinkProps = {
4
4
  className?: string;
5
5
  socialLayout?: SocialLayout;
@@ -14,4 +14,4 @@ export type MagicLinkProps = {
14
14
  * @param socialPosition - Position of social provider buttons; `"top"` or `"bottom"`. Defaults to `"bottom"`.
15
15
  * @returns The magic-link sign-in UI as a JSX element
16
16
  */
17
- export declare function MagicLink({ className, socialLayout, socialPosition, variant, ...props }: MagicLinkProps & CardProps): import("react/jsx-runtime").JSX.Element;
17
+ export declare function MagicLink({ className, socialLayout, socialPosition, variant, ...props }: MagicLinkProps & Omit<CardProps, "children">): import("react/jsx-runtime").JSX.Element;
@@ -1,44 +1,99 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useAuth, useSignInMagicLink, useSignInSocial } from "@better-auth-ui/react";
3
- import { Button, Card, cn, Description, FieldError, Form, Input, Label, Link, Spinner, TextField, toast } from "@heroui/react";
4
- import { useState } from "react";
5
- import { FieldSeparator } from "./field-separator";
6
- import { MagicLinkButton } from "./magic-link-button";
7
- import { PasskeyButton } from "./passkey-button";
8
- import { ProviderButtons } from "./provider-buttons";
9
- /**
10
- * Render a card-based sign-in form that sends an email magic link and optionally shows social provider buttons.
11
- *
12
- * @param className - Additional CSS class names applied to the card container
13
- * @param socialLayout - Layout style for social provider buttons
14
- * @param socialPosition - Position of social provider buttons; `"top"` or `"bottom"`. Defaults to `"bottom"`.
15
- * @returns The magic-link sign-in UI as a JSX element
16
- */
17
- export function MagicLink({ className, socialLayout, socialPosition = "bottom", variant, ...props }) {
18
- const { basePaths, baseURL, localization, passkey, redirectTo, socialProviders, viewPaths } = useAuth();
19
- const [email, setEmail] = useState("");
20
- const { mutate: signInMagicLink, isPending: magicLinkPending } = useSignInMagicLink({
21
- onError: (error) => toast.danger(error.error?.message || error.message),
22
- onSuccess: () => {
23
- setEmail("");
24
- toast.success(localization.auth.magicLinkSent);
25
- }
26
- });
27
- const [socialRedirecting, setSocialRedirecting] = useState(false);
28
- const { mutate: signInSocial, isPending: socialPending } = useSignInSocial({
29
- onError: (error) => toast.danger(error.error?.message || error.message),
30
- onSuccess: () => {
31
- setSocialRedirecting(true);
32
- setTimeout(() => {
33
- setSocialRedirecting(false);
34
- }, 5000);
35
- }
36
- });
37
- const isPending = magicLinkPending || socialPending || socialRedirecting;
38
- const handleSubmit = (e) => {
39
- e.preventDefault();
40
- signInMagicLink({ email, callbackURL: `${baseURL}${redirectTo}` });
41
- };
42
- const showSeparator = !!socialProviders?.length;
43
- return (_jsxs(Card, { className: cn("w-full max-w-sm p-4 md:p-6", className), variant: variant, ...props, children: [_jsx(Card.Header, { children: _jsx(Card.Title, { className: "text-xl font-semibold mb-1", children: localization.auth.signIn }) }), _jsxs(Card.Content, { className: "gap-4", children: [socialPosition === "top" && (_jsxs(_Fragment, { children: [!!socialProviders?.length && (_jsx(ProviderButtons, { socialLayout: socialLayout, signInSocial: signInSocial, isPending: isPending })), showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or }))] })), _jsxs(Form, { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs(TextField, { name: "email", type: "email", autoComplete: "email", isDisabled: isPending, value: email, onChange: setEmail, children: [_jsx(Label, { children: localization.auth.email }), _jsx(Input, { placeholder: localization.auth.emailPlaceholder, required: true, variant: variant === "transparent" ? "primary" : "secondary" }), _jsx(FieldError, {})] }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs(Button, { type: "submit", className: "w-full", isPending: isPending, children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), localization.auth.sendMagicLink] }), _jsx(MagicLinkButton, { view: "magicLink", isPending: isPending }), passkey && _jsx(PasskeyButton, { isPending: isPending })] })] }), socialPosition === "bottom" && (_jsxs(_Fragment, { children: [showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or })), !!socialProviders?.length && (_jsx(ProviderButtons, { socialLayout: socialLayout, signInSocial: signInSocial, isPending: isPending }))] }))] }), _jsx(Card.Footer, { className: "flex-col", children: _jsxs(Description, { className: "text-sm", children: [localization.auth.needToCreateAnAccount, " ", _jsx(Link, { href: `${basePaths.auth}/${viewPaths.auth.signUp}`, className: "text-accent decoration-accent no-underline hover:underline", children: localization.auth.signUp })] }) })] }));
1
+ import { FieldSeparator as e } from "./field-separator.js";
2
+ import { MagicLinkButton as t } from "./magic-link-button.js";
3
+ import { PasskeyButton as n } from "./passkey-button.js";
4
+ import { ProviderButtons as r } from "./provider-buttons.js";
5
+ import { useAuth as i, useSignInMagicLink as a } from "@better-auth-ui/react";
6
+ import { Button as o, Card as s, Description as c, FieldError as l, Form as u, Input as d, Label as f, Link as p, Spinner as m, TextField as h, cn as g, toast as _ } from "@heroui/react";
7
+ import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
8
+ import { useState as x } from "react";
9
+ //#region src/components/auth/magic-link.tsx
10
+ function S({ className: S, socialLayout: C, socialPosition: w = "bottom", variant: T, ...E }) {
11
+ let { basePaths: D, baseURL: O, localization: k, passkey: A, redirectTo: j, socialProviders: M, viewPaths: N } = i(), [P, F] = x(""), { mutate: I, isPending: L } = a({ onSuccess: () => {
12
+ F(""), _.success(k.auth.magicLinkSent);
13
+ } }), R = L, z = (e) => {
14
+ e.preventDefault(), I({
15
+ email: P,
16
+ callbackURL: `${O}${j}`
17
+ });
18
+ }, B = !!M?.length;
19
+ return /* @__PURE__ */ b(s, {
20
+ className: g("w-full max-w-sm p-4 md:p-6", S),
21
+ variant: T,
22
+ ...E,
23
+ children: [
24
+ /* @__PURE__ */ y(s.Header, { children: /* @__PURE__ */ y(s.Title, {
25
+ className: "text-xl font-semibold mb-1",
26
+ children: k.auth.signIn
27
+ }) }),
28
+ /* @__PURE__ */ b(s.Content, {
29
+ className: "gap-4",
30
+ children: [
31
+ w === "top" && /* @__PURE__ */ b(v, { children: [!!M?.length && /* @__PURE__ */ y(r, {
32
+ socialLayout: C,
33
+ isPending: R
34
+ }), B && /* @__PURE__ */ y(e, { children: k.auth.or })] }),
35
+ /* @__PURE__ */ b(u, {
36
+ onSubmit: z,
37
+ className: "flex flex-col gap-4",
38
+ children: [/* @__PURE__ */ b(h, {
39
+ name: "email",
40
+ type: "email",
41
+ autoComplete: "email",
42
+ isDisabled: R,
43
+ value: P,
44
+ onChange: F,
45
+ children: [
46
+ /* @__PURE__ */ y(f, { children: k.auth.email }),
47
+ /* @__PURE__ */ y(d, {
48
+ placeholder: k.auth.emailPlaceholder,
49
+ required: !0,
50
+ variant: T === "transparent" ? "primary" : "secondary"
51
+ }),
52
+ /* @__PURE__ */ y(l, {})
53
+ ]
54
+ }), /* @__PURE__ */ b("div", {
55
+ className: "flex flex-col gap-3",
56
+ children: [
57
+ /* @__PURE__ */ b(o, {
58
+ type: "submit",
59
+ className: "w-full",
60
+ isPending: R,
61
+ children: [R && /* @__PURE__ */ y(m, {
62
+ color: "current",
63
+ size: "sm"
64
+ }), k.auth.sendMagicLink]
65
+ }),
66
+ /* @__PURE__ */ y(t, {
67
+ view: "magicLink",
68
+ isPending: R
69
+ }),
70
+ A && /* @__PURE__ */ y(n, { isPending: R })
71
+ ]
72
+ })]
73
+ }),
74
+ w === "bottom" && /* @__PURE__ */ b(v, { children: [B && /* @__PURE__ */ y(e, { children: k.auth.or }), !!M?.length && /* @__PURE__ */ y(r, {
75
+ socialLayout: C,
76
+ isPending: R
77
+ })] })
78
+ ]
79
+ }),
80
+ /* @__PURE__ */ y(s.Footer, {
81
+ className: "flex-col",
82
+ children: /* @__PURE__ */ b(c, {
83
+ className: "text-sm",
84
+ children: [
85
+ k.auth.needToCreateAnAccount,
86
+ " ",
87
+ /* @__PURE__ */ y(p, {
88
+ href: `${D.auth}/${N.auth.signUp}`,
89
+ className: "text-accent decoration-accent no-underline hover:underline",
90
+ children: k.auth.signUp
91
+ })
92
+ ]
93
+ })
94
+ })
95
+ ]
96
+ });
44
97
  }
98
+ //#endregion
99
+ export { S as MagicLink };
@@ -1,13 +1,21 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useAuth, useSignInPasskey } from "@better-auth-ui/react";
3
- import { Fingerprint } from "@gravity-ui/icons";
4
- import { Button, Spinner, toast } from "@heroui/react";
5
- export function PasskeyButton({ isPending }) {
6
- const { localization, redirectTo, navigate } = useAuth();
7
- const { mutate: signInPasskey, isPending: passkeyPending } = useSignInPasskey({
8
- onError: (error) => toast.danger(error.error?.message || error.message),
9
- onSuccess: () => navigate({ to: redirectTo })
10
- });
11
- const isDisabled = isPending || passkeyPending;
12
- return (_jsxs(Button, { className: "w-full", variant: "tertiary", isDisabled: isDisabled, isPending: passkeyPending, onPress: () => signInPasskey(), children: [passkeyPending ? _jsx(Spinner, { color: "current", size: "sm" }) : _jsx(Fingerprint, {}), localization.auth.continueWith.replace("{{provider}}", localization.auth.passkey)] }));
1
+ import { useAuth as e, useSignInPasskey as t } from "@better-auth-ui/react";
2
+ import { Button as n, Spinner as r } from "@heroui/react";
3
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
4
+ import { Fingerprint as o } from "@gravity-ui/icons";
5
+ //#region src/components/auth/passkey-button.tsx
6
+ function s({ isPending: s }) {
7
+ let { localization: c, redirectTo: l, navigate: u } = e(), { mutate: d, isPending: f } = t({ onSuccess: () => u({ to: l }) });
8
+ return /* @__PURE__ */ a(n, {
9
+ className: "w-full",
10
+ variant: "tertiary",
11
+ isDisabled: s || f,
12
+ isPending: f,
13
+ onPress: () => d(),
14
+ children: [f ? /* @__PURE__ */ i(r, {
15
+ color: "current",
16
+ size: "sm"
17
+ }) : /* @__PURE__ */ i(o, {}), c.auth.continueWith.replace("{{provider}}", c.auth.passkey)]
18
+ });
13
19
  }
20
+ //#endregion
21
+ export { s as PasskeyButton };
@@ -0,0 +1,15 @@
1
+ import { ButtonProps } from '@heroui/react';
2
+ import { SocialProvider } from 'better-auth/social-providers';
3
+ export type ProviderButtonProps = {
4
+ provider: SocialProvider;
5
+ label?: "continueWith" | "providerName" | "none";
6
+ isDisabled?: boolean;
7
+ } & Omit<ButtonProps, "children" | "onPress" | "isPending">;
8
+ /**
9
+ * Render a single social provider sign-in button with its own mutation and pending state.
10
+ *
11
+ * @param provider - The social provider this button signs in with.
12
+ * @param label - Label style: `"continueWith"` (e.g. "Continue with Google"), `"providerName"` (e.g. "Google"), or `"none"` (icon only).
13
+ * @param isDisabled - External disabled state (e.g. a sibling provider is mid-redirect).
14
+ */
15
+ export declare function ProviderButton({ provider, label, isDisabled, variant, ...props }: ProviderButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,29 @@
1
+ import { providerIcons as e, useAuth as t, useSignInSocial as n } from "@better-auth-ui/react";
2
+ import { Button as r, Spinner as i } from "@heroui/react";
3
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
4
+ import { useState as s } from "react";
5
+ import { getProviderName as c } from "@better-auth-ui/core";
6
+ //#region src/components/auth/provider-button.tsx
7
+ function l({ provider: l, label: u = "continueWith", isDisabled: d, variant: f = "tertiary", ...p }) {
8
+ let { baseURL: m, localization: h, redirectTo: g } = t(), _ = `${m}${g}`, [v, y] = s(!1), { mutate: b, isPending: x } = n({ onSuccess: () => {
9
+ y(!0), setTimeout(() => {
10
+ y(!1);
11
+ }, 5e3);
12
+ } }), S = e[l], C = x || v;
13
+ return /* @__PURE__ */ o(r, {
14
+ variant: f,
15
+ isDisabled: d,
16
+ isPending: C,
17
+ onPress: () => b({
18
+ provider: l,
19
+ callbackURL: _
20
+ }),
21
+ ...p,
22
+ children: [C ? /* @__PURE__ */ a(i, {
23
+ color: "current",
24
+ size: "sm"
25
+ }) : /* @__PURE__ */ a(S, {}), u === "continueWith" ? h.auth.continueWith.replace("{{provider}}", c(l)) : u === "providerName" ? c(l) : null]
26
+ });
27
+ }
28
+ //#endregion
29
+ export { l as ProviderButton };
@@ -1,19 +1,13 @@
1
- import type { SocialProvider } from "better-auth/social-providers";
2
1
  export type ProviderButtonsProps = {
3
- isPending: boolean;
2
+ isPending?: boolean;
4
3
  socialLayout?: SocialLayout;
5
- signInSocial: (params: {
6
- provider: SocialProvider;
7
- callbackURL: string;
8
- }) => void;
9
4
  };
10
5
  export type SocialLayout = "auto" | "horizontal" | "vertical" | "grid";
11
6
  /**
12
- * Render social provider sign-in buttons and handle initiation and pending state.
7
+ * Render social provider sign-in buttons. Each button owns its own sign-in mutation.
13
8
  *
14
- * @param isPending - Disables all provider buttons when true.
9
+ * @param isPending - External pending state (e.g. parent form submitting) that disables all buttons.
15
10
  * @param socialLayout - Preferred layout for the buttons; `"auto"` picks `"horizontal"` when there are four or more providers, otherwise `"vertical"`.
16
- * @param signInSocial - Callback invoked with the provider and callbackURL when a button is clicked.
17
11
  * @returns The JSX element that renders the configured social provider buttons.
18
12
  */
19
- export declare function ProviderButtons({ isPending, socialLayout, signInSocial }: ProviderButtonsProps): import("react/jsx-runtime").JSX.Element;
13
+ export declare function ProviderButtons({ isPending, socialLayout }: ProviderButtonsProps): import("react/jsx-runtime").JSX.Element;