@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,34 +1,20 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { getProviderName } from "@better-auth-ui/core";
3
- import { providerIcons, useAuth } from "@better-auth-ui/react";
4
- import { Button, cn } from "@heroui/react";
5
- import { useMemo } from "react";
6
- /**
7
- * Render social provider sign-in buttons and handle initiation and pending state.
8
- *
9
- * @param isPending - Disables all provider buttons when true.
10
- * @param socialLayout - Preferred layout for the buttons; `"auto"` picks `"horizontal"` when there are four or more providers, otherwise `"vertical"`.
11
- * @param signInSocial - Callback invoked with the provider and callbackURL when a button is clicked.
12
- * @returns The JSX element that renders the configured social provider buttons.
13
- */
14
- export function ProviderButtons({ isPending, socialLayout = "auto", signInSocial }) {
15
- const { baseURL, localization, redirectTo, socialProviders } = useAuth();
16
- const callbackURL = `${baseURL}${redirectTo}`;
17
- const resolvedSocialLayout = useMemo(() => {
18
- if (socialLayout === "auto") {
19
- if (socialProviders?.length && socialProviders.length >= 4) {
20
- return "horizontal";
21
- }
22
- return "vertical";
23
- }
24
- return socialLayout;
25
- }, [socialLayout, socialProviders?.length]);
26
- return (_jsx("div", { className: cn("gap-3", resolvedSocialLayout === "grid" && "grid grid-cols-2", resolvedSocialLayout === "vertical" && "flex flex-col", resolvedSocialLayout === "horizontal" && "flex flex-wrap"), children: socialProviders?.map((provider) => {
27
- const ProviderIcon = providerIcons[provider];
28
- return (_jsxs(Button, { className: cn("w-full", resolvedSocialLayout === "horizontal" && "flex-1"), variant: "tertiary", isPending: isPending, onPress: () => signInSocial({ provider, callbackURL }), children: [_jsx(ProviderIcon, {}), resolvedSocialLayout === "vertical"
29
- ? localization.auth.continueWith.replace("{{provider}}", getProviderName(provider))
30
- : resolvedSocialLayout === "grid"
31
- ? getProviderName(provider)
32
- : null] }, provider));
33
- }) }));
1
+ import { ProviderButton as e } from "./provider-button.js";
2
+ import { useAuth as t } from "@better-auth-ui/react";
3
+ import { cn as n } from "@heroui/react";
4
+ import { jsx as r } from "react/jsx-runtime";
5
+ import { useMemo as i } from "react";
6
+ //#region src/components/auth/provider-buttons.tsx
7
+ function a({ isPending: a, socialLayout: o = "auto" }) {
8
+ let { socialProviders: s } = t(), c = i(() => o === "auto" ? s?.length && s.length >= 4 ? "horizontal" : "vertical" : o, [o, s?.length]);
9
+ return /* @__PURE__ */ r("div", {
10
+ className: n("gap-3", c === "grid" && "grid grid-cols-2", c === "vertical" && "flex flex-col", c === "horizontal" && "flex flex-wrap"),
11
+ children: s?.map((t) => /* @__PURE__ */ r(e, {
12
+ provider: t,
13
+ isDisabled: a,
14
+ label: c === "vertical" ? "continueWith" : c === "grid" ? "providerName" : "none",
15
+ className: n("w-full", c === "horizontal" && "flex-1")
16
+ }, t))
17
+ });
34
18
  }
19
+ //#endregion
20
+ export { a as ProviderButtons };
@@ -1,4 +1,4 @@
1
- import { type CardProps } from "@heroui/react";
1
+ import { CardProps } from '@heroui/react';
2
2
  export type ResetPasswordProps = {
3
3
  className?: string;
4
4
  variant?: CardProps["variant"];
@@ -8,4 +8,4 @@ export type ResetPasswordProps = {
8
8
  *
9
9
  * Renders password (and optional confirm-password) inputs with visibility toggles, applies min/max length constraints from the auth configuration, shows field errors, and submits the new password to the auth client.
10
10
  */
11
- export declare function ResetPassword({ className, variant, ...props }: ResetPasswordProps & CardProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function ResetPassword({ className, variant, ...props }: ResetPasswordProps & Omit<CardProps, "children">): import("react/jsx-runtime").JSX.Element;
@@ -1,58 +1,144 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useAuth, useResetPassword } from "@better-auth-ui/react";
3
- import { Eye, EyeSlash } from "@gravity-ui/icons";
4
- import { Button, Card, cn, Description, FieldError, Form, InputGroup, Label, Link, Spinner, TextField, toast } from "@heroui/react";
5
- import { useEffect, useState } from "react";
6
- /**
7
- * Renders a reset password form that verifies a "token" URL parameter on mount and redirects to sign-in if absent.
8
- *
9
- * Renders password (and optional confirm-password) inputs with visibility toggles, applies min/max length constraints from the auth configuration, shows field errors, and submits the new password to the auth client.
10
- */
11
- export function ResetPassword({ className, variant, ...props }) {
12
- const { basePaths, emailAndPassword, localization, viewPaths, navigate } = useAuth();
13
- const { mutate: resetPassword, isPending } = useResetPassword({
14
- onError: (error) => toast.danger(error.error?.message || error.message),
15
- onSuccess: () => {
16
- toast.success(localization.auth.passwordResetSuccess);
17
- navigate({ to: `${basePaths.auth}/${viewPaths.auth.signIn}` });
18
- }
19
- });
20
- const [isPasswordVisible, setIsPasswordVisible] = useState(false);
21
- const [isConfirmPasswordVisible, setIsConfirmPasswordVisible] = useState(false);
22
- useEffect(() => {
23
- const searchParams = new URLSearchParams(window.location.search);
24
- const token = searchParams.get("token");
25
- if (!token) {
26
- toast.danger(localization.auth.invalidResetPasswordToken);
27
- navigate({ to: `${basePaths.auth}/${viewPaths.auth.signIn}` });
28
- }
29
- }, [
30
- basePaths.auth,
31
- localization.auth.invalidResetPasswordToken,
32
- viewPaths.auth.signIn,
33
- navigate
34
- ]);
35
- function handleSubmit(e) {
36
- e.preventDefault();
37
- const searchParams = new URLSearchParams(window.location.search);
38
- const token = searchParams.get("token");
39
- if (!token) {
40
- toast.danger(localization.auth.invalidResetPasswordToken);
41
- navigate({ to: `${basePaths.auth}/${viewPaths.auth.signIn}` });
42
- return;
43
- }
44
- const formData = new FormData(e.currentTarget);
45
- const password = formData.get("password");
46
- const confirmPassword = formData.get("confirmPassword");
47
- if (emailAndPassword?.confirmPassword && password !== confirmPassword) {
48
- toast.danger(localization.auth.passwordsDoNotMatch);
49
- return;
50
- }
51
- resetPassword({ token, newPassword: password });
52
- }
53
- 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.resetPassword }) }), _jsx(Card.Content, { children: _jsxs(Form, { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs(TextField, { minLength: emailAndPassword?.minPasswordLength, maxLength: emailAndPassword?.maxPasswordLength, name: "password", autoComplete: "new-password", isDisabled: isPending, children: [_jsx(Label, { children: localization.auth.password }), _jsxs(InputGroup, { variant: variant === "transparent" ? "primary" : "secondary", children: [_jsx(InputGroup.Input, { name: "password", placeholder: localization.auth.newPasswordPlaceholder, type: isPasswordVisible ? "text" : "password", required: true }), _jsx(InputGroup.Suffix, { className: "px-0", children: _jsx(Button, { isIconOnly: true, "aria-label": isPasswordVisible
54
- ? localization.auth.hidePassword
55
- : localization.auth.showPassword, size: "sm", variant: "ghost", onPress: () => setIsPasswordVisible(!isPasswordVisible), isDisabled: isPending, children: isPasswordVisible ? _jsx(EyeSlash, {}) : _jsx(Eye, {}) }) })] }), _jsx(FieldError, {})] }), emailAndPassword?.confirmPassword && (_jsxs(TextField, { minLength: emailAndPassword?.minPasswordLength, maxLength: emailAndPassword?.maxPasswordLength, name: "confirmPassword", autoComplete: "new-password", isDisabled: isPending, children: [_jsx(Label, { children: localization.auth.confirmPassword }), _jsxs(InputGroup, { variant: variant === "transparent" ? "primary" : "secondary", children: [_jsx(InputGroup.Input, { placeholder: localization.auth.confirmPasswordPlaceholder, type: isConfirmPasswordVisible ? "text" : "password", required: true, name: "confirmPassword" }), _jsx(InputGroup.Suffix, { className: "px-0", children: _jsx(Button, { isIconOnly: true, "aria-label": isConfirmPasswordVisible
56
- ? localization.auth.hidePassword
57
- : localization.auth.showPassword, size: "sm", variant: "ghost", onPress: () => setIsConfirmPasswordVisible(!isConfirmPasswordVisible), isDisabled: isPending, children: isConfirmPasswordVisible ? _jsx(EyeSlash, {}) : _jsx(Eye, {}) }) })] }), _jsx(FieldError, {})] })), _jsx("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.resetPassword] }) })] }) }), _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, useResetPassword as t } from "@better-auth-ui/react";
2
+ import { Button as n, Card as r, Description as i, FieldError as a, Form as o, InputGroup 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
+ import { useEffect as g, useState as _ } from "react";
5
+ import { Eye as v, EyeSlash as y } from "@gravity-ui/icons";
6
+ //#region src/components/auth/reset-password.tsx
7
+ function b({ className: b, variant: x, ...S }) {
8
+ let { basePaths: C, emailAndPassword: w, localization: T, viewPaths: E, navigate: D } = e(), { mutate: O, isPending: k } = t({ onSuccess: () => {
9
+ p.success(T.auth.passwordResetSuccess), D({ to: `${C.auth}/${E.auth.signIn}` });
10
+ } }), [A, j] = _(!1), [M, N] = _(!1);
11
+ g(() => {
12
+ new URLSearchParams(window.location.search).get("token") || (p.danger(T.auth.invalidResetPasswordToken), D({ to: `${C.auth}/${E.auth.signIn}` }));
13
+ }, [
14
+ C.auth,
15
+ T.auth.invalidResetPasswordToken,
16
+ E.auth.signIn,
17
+ D
18
+ ]);
19
+ function P(e) {
20
+ e.preventDefault();
21
+ let t = new URLSearchParams(window.location.search).get("token");
22
+ if (!t) {
23
+ p.danger(T.auth.invalidResetPasswordToken), D({ to: `${C.auth}/${E.auth.signIn}` });
24
+ return;
25
+ }
26
+ let n = new FormData(e.currentTarget), r = n.get("password"), i = n.get("confirmPassword");
27
+ if (w?.confirmPassword && r !== i) {
28
+ p.danger(T.auth.passwordsDoNotMatch);
29
+ return;
30
+ }
31
+ O({
32
+ token: t,
33
+ newPassword: r
34
+ });
35
+ }
36
+ return /* @__PURE__ */ h(r, {
37
+ className: f("w-full max-w-sm p-4 md:p-6", b),
38
+ variant: x,
39
+ ...S,
40
+ children: [
41
+ /* @__PURE__ */ m(r.Header, { children: /* @__PURE__ */ m(r.Title, {
42
+ className: "text-xl font-semibold mb-1",
43
+ children: T.auth.resetPassword
44
+ }) }),
45
+ /* @__PURE__ */ m(r.Content, { children: /* @__PURE__ */ h(o, {
46
+ onSubmit: P,
47
+ className: "flex flex-col gap-4",
48
+ children: [
49
+ /* @__PURE__ */ h(d, {
50
+ minLength: w?.minPasswordLength,
51
+ maxLength: w?.maxPasswordLength,
52
+ name: "password",
53
+ autoComplete: "new-password",
54
+ isDisabled: k,
55
+ children: [
56
+ /* @__PURE__ */ m(c, { children: T.auth.password }),
57
+ /* @__PURE__ */ h(s, {
58
+ variant: x === "transparent" ? "primary" : "secondary",
59
+ children: [/* @__PURE__ */ m(s.Input, {
60
+ name: "password",
61
+ placeholder: T.auth.newPasswordPlaceholder,
62
+ type: A ? "text" : "password",
63
+ required: !0
64
+ }), /* @__PURE__ */ m(s.Suffix, {
65
+ className: "px-0",
66
+ children: /* @__PURE__ */ m(n, {
67
+ isIconOnly: !0,
68
+ "aria-label": A ? T.auth.hidePassword : T.auth.showPassword,
69
+ size: "sm",
70
+ variant: "ghost",
71
+ onPress: () => j(!A),
72
+ isDisabled: k,
73
+ children: m(A ? y : v, {})
74
+ })
75
+ })]
76
+ }),
77
+ /* @__PURE__ */ m(a, {})
78
+ ]
79
+ }),
80
+ w?.confirmPassword && /* @__PURE__ */ h(d, {
81
+ minLength: w?.minPasswordLength,
82
+ maxLength: w?.maxPasswordLength,
83
+ name: "confirmPassword",
84
+ autoComplete: "new-password",
85
+ isDisabled: k,
86
+ children: [
87
+ /* @__PURE__ */ m(c, { children: T.auth.confirmPassword }),
88
+ /* @__PURE__ */ h(s, {
89
+ variant: x === "transparent" ? "primary" : "secondary",
90
+ children: [/* @__PURE__ */ m(s.Input, {
91
+ placeholder: T.auth.confirmPasswordPlaceholder,
92
+ type: M ? "text" : "password",
93
+ required: !0,
94
+ name: "confirmPassword"
95
+ }), /* @__PURE__ */ m(s.Suffix, {
96
+ className: "px-0",
97
+ children: /* @__PURE__ */ m(n, {
98
+ isIconOnly: !0,
99
+ "aria-label": M ? T.auth.hidePassword : T.auth.showPassword,
100
+ size: "sm",
101
+ variant: "ghost",
102
+ onPress: () => N(!M),
103
+ isDisabled: k,
104
+ children: m(M ? y : v, {})
105
+ })
106
+ })]
107
+ }),
108
+ /* @__PURE__ */ m(a, {})
109
+ ]
110
+ }),
111
+ /* @__PURE__ */ m("div", {
112
+ className: "flex flex-col gap-3",
113
+ children: /* @__PURE__ */ h(n, {
114
+ type: "submit",
115
+ className: "w-full",
116
+ isPending: k,
117
+ children: [k && /* @__PURE__ */ m(u, {
118
+ color: "current",
119
+ size: "sm"
120
+ }), T.auth.resetPassword]
121
+ })
122
+ })
123
+ ]
124
+ }) }),
125
+ /* @__PURE__ */ m(r.Footer, {
126
+ className: "flex-col",
127
+ children: /* @__PURE__ */ h(i, {
128
+ className: "text-sm",
129
+ children: [
130
+ T.auth.rememberYourPassword,
131
+ " ",
132
+ /* @__PURE__ */ m(l, {
133
+ href: `${C.auth}/${E.auth.signIn}`,
134
+ className: "text-accent decoration-accent no-underline hover:underline",
135
+ children: T.auth.signIn
136
+ })
137
+ ]
138
+ })
139
+ })
140
+ ]
141
+ });
58
142
  }
143
+ //#endregion
144
+ export { b as ResetPassword };
@@ -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 interface SignInProps {
4
4
  className?: string;
5
5
  socialLayout?: SocialLayout;
@@ -11,4 +11,4 @@ export interface SignInProps {
11
11
  *
12
12
  * @returns The sign-in JSX element containing email/password fields, optional magic-link button, and social provider buttons.
13
13
  */
14
- export declare function SignIn({ className, socialLayout, socialPosition, variant, ...props }: SignInProps & CardProps): import("react/jsx-runtime").JSX.Element;
14
+ export declare function SignIn({ className, socialLayout, socialPosition, variant, ...props }: SignInProps & Omit<CardProps, "children">): import("react/jsx-runtime").JSX.Element;
@@ -1,65 +1,152 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useAuth, useSendVerificationEmail, useSignInEmail, useSignInSocial } from "@better-auth-ui/react";
3
- import { Button, Card, Checkbox, 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 the sign-in UI using auth context for configuration and localization.
11
- *
12
- * @returns The sign-in JSX element containing email/password fields, optional magic-link button, and social provider buttons.
13
- */
14
- export function SignIn({ className, socialLayout, socialPosition = "bottom", variant, ...props }) {
15
- const { basePaths, baseURL, emailAndPassword, localization, magicLink, passkey, redirectTo, socialProviders, viewPaths, navigate } = useAuth();
16
- const [password, setPassword] = useState("");
17
- const { mutate: sendVerificationEmail } = useSendVerificationEmail({
18
- onError: (error) => toast.danger(error.error?.message || error.message),
19
- onSuccess: () => toast.success(localization.auth.verificationEmailSent)
20
- });
21
- const { mutate: signInEmail, isPending: signInPending } = useSignInEmail({
22
- onError: (error, { email }) => {
23
- setPassword("");
24
- if (error.error?.code === "EMAIL_NOT_VERIFIED") {
25
- toast.danger(error.error?.message || error.message, {
26
- actionProps: {
27
- children: localization.auth.resend,
28
- onClick: () => sendVerificationEmail({
29
- email,
30
- callbackURL: `${baseURL}${redirectTo}`
31
- })
32
- }
33
- });
34
- }
35
- else {
36
- toast.danger(error.error?.message || error.message);
37
- }
38
- },
39
- onSuccess: () => navigate({ to: redirectTo })
40
- });
41
- const [socialRedirecting, setSocialRedirecting] = useState(false);
42
- const { mutate: signInSocial, isPending: socialPending } = useSignInSocial({
43
- onError: (error) => toast.danger(error.error?.message || error.message),
44
- onSuccess: () => {
45
- setSocialRedirecting(true);
46
- setTimeout(() => {
47
- setSocialRedirecting(false);
48
- }, 5000);
49
- }
50
- });
51
- const handleSubmit = (e) => {
52
- e.preventDefault();
53
- const formData = new FormData(e.currentTarget);
54
- const email = formData.get("email");
55
- const rememberMe = formData.get("rememberMe") === "on";
56
- signInEmail({
57
- email,
58
- password,
59
- ...(emailAndPassword?.rememberMe ? { rememberMe } : {})
60
- });
61
- };
62
- const isPending = signInPending || socialPending || socialRedirecting;
63
- const showSeparator = emailAndPassword?.enabled && !!socialProviders?.length;
64
- return (_jsxs(Card, { className: cn("w-full max-w-sm gap-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 }))] })), emailAndPassword?.enabled && (_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, variant: variant === "transparent" ? "primary" : "secondary", required: true }), _jsx(FieldError, {})] }), _jsxs(TextField, { minLength: emailAndPassword?.minPasswordLength, maxLength: emailAndPassword?.maxPasswordLength, name: "password", type: "password", autoComplete: "current-password", isDisabled: isPending, value: password, onChange: setPassword, children: [_jsx(Label, { children: localization.auth.password }), _jsx(Input, { placeholder: localization.auth.passwordPlaceholder, variant: variant === "transparent" ? "primary" : "secondary", required: true }), _jsx(FieldError, {})] }), emailAndPassword?.rememberMe && (_jsxs(Checkbox, { name: "rememberMe", isDisabled: isPending, variant: variant === "transparent" ? "primary" : "secondary", children: [_jsx(Checkbox.Control, { children: _jsx(Checkbox.Indicator, {}) }), _jsx(Checkbox.Content, { children: _jsx(Label, { children: localization.auth.rememberMe }) })] })), _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.signIn] }), magicLink && (_jsx(MagicLinkButton, { view: "signIn", 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 }))] }))] }), _jsxs(Card.Footer, { className: "flex-col gap-3", children: [emailAndPassword?.forgotPassword && (_jsx(Link, { href: `${basePaths.auth}/${viewPaths.auth.forgotPassword}`, className: "no-underline hover:underline", children: localization.auth.forgotPasswordLink })), emailAndPassword?.enabled && (_jsxs(Description, { className: "text-sm", children: [localization.auth.needToCreateAnAccount, " ", _jsx(Link, { href: `${basePaths.auth}/${viewPaths.auth.signUp}`, className: "text-accent no-underline hover:underline decoration-accent-hover", 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, useSendVerificationEmail as a, useSignInEmail as o, useSignInUsername as s } from "@better-auth-ui/react";
6
+ import { Button as c, Card as l, Checkbox as u, Description as d, FieldError as f, Form as p, Input as m, Label as h, Link as g, Spinner as _, TextField as v, cn as y, toast as b } from "@heroui/react";
7
+ import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
8
+ import { useState as w } from "react";
9
+ //#region src/components/auth/sign-in.tsx
10
+ function T(e) {
11
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e);
65
12
  }
13
+ function E({ className: E, socialLayout: D, socialPosition: O = "bottom", variant: k, ...A }) {
14
+ let { basePaths: j, baseURL: M, emailAndPassword: N, localization: P, magicLink: F, passkey: I, redirectTo: L, socialProviders: R, username: z, viewPaths: B, navigate: V } = i(), [H, U] = w(""), { mutate: W } = a({ onSuccess: () => b.success(P.auth.verificationEmailSent) }), { mutate: G, isPending: K } = o({
15
+ onError: (e, { email: t }) => {
16
+ U(""), e.error?.code === "EMAIL_NOT_VERIFIED" ? b.danger(e.error?.message || e.message, { actionProps: {
17
+ children: P.auth.resend,
18
+ onClick: () => W({
19
+ email: t,
20
+ callbackURL: `${M}${L}`
21
+ })
22
+ } }) : b.danger(e.error?.message || e.message);
23
+ },
24
+ onSuccess: () => V({ to: L })
25
+ }), { mutate: q, isPending: J } = s({
26
+ onError: (e) => {
27
+ U(""), b.danger(e.error?.message || e.message);
28
+ },
29
+ onSuccess: () => V({ to: L })
30
+ }), Y = (e) => {
31
+ e.preventDefault();
32
+ let t = new FormData(e.currentTarget), n = t.get("email"), r = t.get("rememberMe") === "on";
33
+ z?.enabled && !T(n) ? q({
34
+ username: n,
35
+ password: H
36
+ }) : G({
37
+ email: n,
38
+ password: H,
39
+ ...N?.rememberMe ? { rememberMe: r } : {}
40
+ });
41
+ }, X = K || J, Z = N?.enabled && !!R?.length;
42
+ return /* @__PURE__ */ C(l, {
43
+ className: y("w-full max-w-sm gap-4 md:p-6", E),
44
+ variant: k,
45
+ ...A,
46
+ children: [
47
+ /* @__PURE__ */ S(l.Header, { children: /* @__PURE__ */ S(l.Title, {
48
+ className: "text-xl font-semibold mb-1",
49
+ children: P.auth.signIn
50
+ }) }),
51
+ /* @__PURE__ */ C(l.Content, {
52
+ className: "gap-4",
53
+ children: [
54
+ O === "top" && /* @__PURE__ */ C(x, { children: [!!R?.length && /* @__PURE__ */ S(r, {
55
+ socialLayout: D,
56
+ isPending: X
57
+ }), Z && /* @__PURE__ */ S(e, { children: P.auth.or })] }),
58
+ N?.enabled && /* @__PURE__ */ C(p, {
59
+ onSubmit: Y,
60
+ className: "flex flex-col gap-4",
61
+ children: [
62
+ /* @__PURE__ */ C(v, {
63
+ name: "email",
64
+ type: z?.enabled ? "text" : "email",
65
+ autoComplete: z?.enabled ? "username" : "email",
66
+ isDisabled: X,
67
+ children: [
68
+ /* @__PURE__ */ S(h, { children: z?.enabled ? P.auth.username : P.auth.email }),
69
+ /* @__PURE__ */ S(m, {
70
+ placeholder: z?.enabled ? P.auth.usernameOrEmailPlaceholder : P.auth.emailPlaceholder,
71
+ variant: k === "transparent" ? "primary" : "secondary",
72
+ required: !0
73
+ }),
74
+ /* @__PURE__ */ S(f, {})
75
+ ]
76
+ }),
77
+ /* @__PURE__ */ C(v, {
78
+ minLength: N?.minPasswordLength,
79
+ maxLength: N?.maxPasswordLength,
80
+ name: "password",
81
+ type: "password",
82
+ autoComplete: "current-password",
83
+ isDisabled: X,
84
+ value: H,
85
+ onChange: U,
86
+ children: [
87
+ /* @__PURE__ */ S(h, { children: P.auth.password }),
88
+ /* @__PURE__ */ S(m, {
89
+ placeholder: P.auth.passwordPlaceholder,
90
+ variant: k === "transparent" ? "primary" : "secondary",
91
+ required: !0
92
+ }),
93
+ /* @__PURE__ */ S(f, {})
94
+ ]
95
+ }),
96
+ N?.rememberMe && /* @__PURE__ */ C(u, {
97
+ name: "rememberMe",
98
+ isDisabled: X,
99
+ variant: k === "transparent" ? "primary" : "secondary",
100
+ children: [/* @__PURE__ */ S(u.Control, { children: /* @__PURE__ */ S(u.Indicator, {}) }), /* @__PURE__ */ S(u.Content, { children: /* @__PURE__ */ S(h, { children: P.auth.rememberMe }) })]
101
+ }),
102
+ /* @__PURE__ */ C("div", {
103
+ className: "flex flex-col gap-3",
104
+ children: [
105
+ /* @__PURE__ */ C(c, {
106
+ type: "submit",
107
+ className: "w-full",
108
+ isPending: X,
109
+ children: [X && /* @__PURE__ */ S(_, {
110
+ color: "current",
111
+ size: "sm"
112
+ }), P.auth.signIn]
113
+ }),
114
+ F && /* @__PURE__ */ S(t, {
115
+ view: "signIn",
116
+ isPending: X
117
+ }),
118
+ I && /* @__PURE__ */ S(n, { isPending: X })
119
+ ]
120
+ })
121
+ ]
122
+ }),
123
+ O === "bottom" && /* @__PURE__ */ C(x, { children: [Z && /* @__PURE__ */ S(e, { children: P.auth.or }), !!R?.length && /* @__PURE__ */ S(r, {
124
+ socialLayout: D,
125
+ isPending: X
126
+ })] })
127
+ ]
128
+ }),
129
+ /* @__PURE__ */ C(l.Footer, {
130
+ className: "flex-col gap-3",
131
+ children: [N?.forgotPassword && /* @__PURE__ */ S(g, {
132
+ href: `${j.auth}/${B.auth.forgotPassword}`,
133
+ className: "no-underline hover:underline",
134
+ children: P.auth.forgotPasswordLink
135
+ }), N?.enabled && /* @__PURE__ */ C(d, {
136
+ className: "text-sm",
137
+ children: [
138
+ P.auth.needToCreateAnAccount,
139
+ " ",
140
+ /* @__PURE__ */ S(g, {
141
+ href: `${j.auth}/${B.auth.signUp}`,
142
+ className: "text-accent no-underline hover:underline decoration-accent-hover",
143
+ children: P.auth.signUp
144
+ })
145
+ ]
146
+ })]
147
+ })
148
+ ]
149
+ });
150
+ }
151
+ //#endregion
152
+ export { E as SignIn };
@@ -1,33 +1,27 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useAuth, useSignOut } from "@better-auth-ui/react";
3
- import { cn, Spinner, toast } from "@heroui/react";
4
- import { useEffect, useRef } from "react";
5
- /**
6
- * Initiates sign-out on mount and renders a loading card while sign-out proceeds.
7
- *
8
- * @returns A Card containing a centered Spinner shown during the sign-out process
9
- */
10
- export function SignOut({ className }) {
11
- const { basePaths, navigate, viewPaths } = useAuth();
12
- const { mutate: signOut } = useSignOut({
13
- onError: (error) => {
14
- toast.danger(error.error?.message || error.message);
15
- navigate({
16
- to: `${basePaths.auth}/${viewPaths.auth.signIn}`,
17
- replace: true
18
- });
19
- },
20
- onSuccess: () => navigate({
21
- to: `${basePaths.auth}/${viewPaths.auth.signIn}`,
22
- replace: true
23
- })
24
- });
25
- const hasSignedOut = useRef(false);
26
- useEffect(() => {
27
- if (hasSignedOut.current)
28
- return;
29
- hasSignedOut.current = true;
30
- signOut();
31
- }, [signOut]);
32
- return (_jsx(Spinner, { className: cn("mx-auto my-auto", className), color: "current" }));
1
+ import { useAuth as e, useSignOut as t } from "@better-auth-ui/react";
2
+ import { Spinner as n, cn as r, toast as i } from "@heroui/react";
3
+ import { jsx as a } from "react/jsx-runtime";
4
+ import { useEffect as o, useRef as s } from "react";
5
+ //#region src/components/auth/sign-out.tsx
6
+ function c({ className: c }) {
7
+ let { basePaths: l, navigate: u, viewPaths: d } = e(), { mutate: f } = t({
8
+ onError: (e) => {
9
+ i.danger(e.error?.message || e.message), u({
10
+ to: `${l.auth}/${d.auth.signIn}`,
11
+ replace: !0
12
+ });
13
+ },
14
+ onSuccess: () => u({
15
+ to: `${l.auth}/${d.auth.signIn}`,
16
+ replace: !0
17
+ })
18
+ }), p = s(!1);
19
+ return o(() => {
20
+ p.current || (p.current = !0, f());
21
+ }, [f]), /* @__PURE__ */ a(n, {
22
+ className: r("mx-auto my-auto", c),
23
+ color: "current"
24
+ });
33
25
  }
26
+ //#endregion
27
+ export { c as SignOut };
@@ -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 SignUpProps = {
4
4
  className?: string;
5
5
  socialLayout?: SocialLayout;
@@ -16,4 +16,4 @@ export type SignUpProps = {
16
16
  * @param socialPosition - Position of social provider buttons relative to the form; `"top"` or `"bottom"` (default `"bottom"`)
17
17
  * @returns The sign-up form React element
18
18
  */
19
- export declare function SignUp({ className, socialLayout, socialPosition, variant, ...props }: SignUpProps & CardProps): import("react/jsx-runtime").JSX.Element;
19
+ export declare function SignUp({ className, socialLayout, socialPosition, variant, ...props }: SignUpProps & Omit<CardProps, "children">): import("react/jsx-runtime").JSX.Element;