@better-auth-ui/heroui 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/dist/components/account/account.d.ts +18 -0
  2. package/dist/components/account/account.js +24 -0
  3. package/dist/components/account/settings/account-settings.d.ts +5 -0
  4. package/dist/components/account/settings/account-settings.js +6 -0
  5. package/dist/components/account/settings/settings.d.ts +5 -0
  6. package/dist/components/account/settings/settings.js +5 -0
  7. package/dist/components/account/settings/user-profile.d.ts +5 -0
  8. package/dist/components/account/settings/user-profile.js +20 -0
  9. package/dist/components/auth/auth-provider.d.ts +9 -0
  10. package/dist/components/auth/auth-provider.js +12 -0
  11. package/dist/components/auth/auth.d.ts +23 -0
  12. package/dist/components/auth/auth.js +42 -0
  13. package/dist/components/auth/field-separator.d.ts +4 -0
  14. package/dist/components/auth/field-separator.js +5 -0
  15. package/dist/components/auth/forgot-password.d.ts +15 -0
  16. package/dist/components/auth/forgot-password.js +28 -0
  17. package/dist/components/auth/magic-link-button.d.ts +13 -0
  18. package/dist/components/auth/magic-link-button.js +19 -0
  19. package/dist/components/auth/magic-link.d.ts +17 -0
  20. package/dist/components/auth/magic-link.js +43 -0
  21. package/dist/components/auth/provider-buttons.d.ts +19 -0
  22. package/dist/components/auth/provider-buttons.js +34 -0
  23. package/dist/components/auth/reset-password.d.ts +11 -0
  24. package/dist/components/auth/reset-password.js +58 -0
  25. package/dist/components/auth/sign-in.d.ts +14 -0
  26. package/dist/components/auth/sign-in.js +64 -0
  27. package/dist/components/auth/sign-out.d.ts +9 -0
  28. package/dist/components/auth/sign-out.js +33 -0
  29. package/dist/components/auth/sign-up.d.ts +19 -0
  30. package/dist/components/auth/sign-up.js +71 -0
  31. package/dist/components/email/email-changed-email.d.ts +3 -0
  32. package/dist/components/email/email-changed-email.js +23 -0
  33. package/dist/components/email/email-verification-email.d.ts +3 -0
  34. package/dist/components/email/email-verification-email.js +23 -0
  35. package/dist/components/email/magic-link-email.d.ts +3 -0
  36. package/dist/components/email/magic-link-email.js +23 -0
  37. package/dist/components/email/new-device-email.d.ts +3 -0
  38. package/dist/components/email/new-device-email.js +23 -0
  39. package/dist/components/email/otp-email.d.ts +3 -0
  40. package/dist/components/email/otp-email.js +22 -0
  41. package/dist/components/email/password-changed-email.d.ts +3 -0
  42. package/dist/components/email/password-changed-email.js +23 -0
  43. package/dist/components/email/reset-password-email.d.ts +3 -0
  44. package/dist/components/email/reset-password-email.js +23 -0
  45. package/dist/components/settings/account/account-settings.d.ts +16 -0
  46. package/dist/components/settings/account/account-settings.js +20 -0
  47. package/dist/components/settings/account/accounts.d.ts +14 -0
  48. package/dist/components/settings/account/accounts.js +26 -0
  49. package/dist/components/settings/account/appearance.d.ts +16 -0
  50. package/dist/components/settings/account/appearance.js +28 -0
  51. package/dist/components/settings/account/change-avatar.d.ts +4 -0
  52. package/dist/components/settings/account/change-avatar.js +56 -0
  53. package/dist/components/settings/account/change-email.d.ts +15 -0
  54. package/dist/components/settings/account/change-email.js +29 -0
  55. package/dist/components/settings/account/manage-account.d.ts +19 -0
  56. package/dist/components/settings/account/manage-account.js +32 -0
  57. package/dist/components/settings/account/manage-accounts.d.ts +14 -0
  58. package/dist/components/settings/account/manage-accounts.js +37 -0
  59. package/dist/components/settings/account/theme-selector.d.ts +16 -0
  60. package/dist/components/settings/account/theme-selector.js +33 -0
  61. package/dist/components/settings/account/theme-settings.d.ts +16 -0
  62. package/dist/components/settings/account/theme-settings.js +31 -0
  63. package/dist/components/settings/account/user-profile.d.ts +11 -0
  64. package/dist/components/settings/account/user-profile.js +23 -0
  65. package/dist/components/settings/account-settings.d.ts +5 -0
  66. package/dist/components/settings/account-settings.js +6 -0
  67. package/dist/components/settings/account.d.ts +18 -0
  68. package/dist/components/settings/account.js +24 -0
  69. package/dist/components/settings/security/active-session.d.ts +14 -0
  70. package/dist/components/settings/security/active-session.js +53 -0
  71. package/dist/components/settings/security/active-sessions.d.ts +14 -0
  72. package/dist/components/settings/security/active-sessions.js +28 -0
  73. package/dist/components/settings/security/change-password.d.ts +15 -0
  74. package/dist/components/settings/security/change-password.js +79 -0
  75. package/dist/components/settings/security/connected-account.d.ts +16 -0
  76. package/dist/components/settings/security/connected-account.js +46 -0
  77. package/dist/components/settings/security/connected-accounts.d.ts +15 -0
  78. package/dist/components/settings/security/connected-accounts.js +31 -0
  79. package/dist/components/settings/security/danger-zone.d.ts +11 -0
  80. package/dist/components/settings/security/danger-zone.js +12 -0
  81. package/dist/components/settings/security/delete-user.d.ts +9 -0
  82. package/dist/components/settings/security/delete-user.js +47 -0
  83. package/dist/components/settings/security/linked-account.d.ts +16 -0
  84. package/dist/components/settings/security/linked-account.js +48 -0
  85. package/dist/components/settings/security/linked-accounts.d.ts +15 -0
  86. package/dist/components/settings/security/linked-accounts.js +42 -0
  87. package/dist/components/settings/security/security-settings.d.ts +17 -0
  88. package/dist/components/settings/security/security-settings.js +21 -0
  89. package/dist/components/settings/security/sessions.d.ts +14 -0
  90. package/dist/components/settings/security/sessions.js +40 -0
  91. package/dist/components/settings/settings/account-settings.d.ts +5 -0
  92. package/dist/components/settings/settings/account-settings.js +6 -0
  93. package/dist/components/settings/settings/user-profile.d.ts +5 -0
  94. package/dist/components/settings/settings/user-profile.js +20 -0
  95. package/dist/components/settings/settings.d.ts +24 -0
  96. package/dist/components/settings/settings.js +28 -0
  97. package/dist/components/settings/user-profile.d.ts +5 -0
  98. package/dist/components/settings/user-profile.js +20 -0
  99. package/dist/components/user/switch-account-item.d.ts +16 -0
  100. package/dist/components/user/switch-account-item.js +16 -0
  101. package/dist/components/user/switch-account-menu.d.ts +10 -0
  102. package/dist/components/user/switch-account-menu.js +29 -0
  103. package/dist/components/user/switch-account-popover.d.ts +10 -0
  104. package/dist/components/user/switch-account-popover.js +25 -0
  105. package/dist/components/user/switch-account-submenu.d.ts +10 -0
  106. package/dist/components/user/switch-account-submenu.js +25 -0
  107. package/dist/components/user/user-avatar.d.ts +25 -0
  108. package/dist/components/user/user-avatar.js +31 -0
  109. package/dist/components/user/user-button.d.ts +25 -0
  110. package/dist/components/user/user-button.js +24 -0
  111. package/dist/components/user/user-view.d.ts +22 -0
  112. package/dist/components/user/user-view.js +24 -0
  113. package/dist/core.d.ts +1 -0
  114. package/dist/core.js +1 -0
  115. package/dist/hooks/use-auth.d.ts +2 -0
  116. package/dist/hooks/use-auth.js +8 -0
  117. package/dist/hooks/use-redirect-to.d.ts +8 -0
  118. package/dist/hooks/use-redirect-to.js +19 -0
  119. package/dist/hooks/use-sign-in.d.ts +8 -0
  120. package/dist/hooks/use-sign-in.js +53 -0
  121. package/dist/index.d.ts +33 -0
  122. package/dist/index.js +34 -0
  123. package/dist/lib/utils.d.ts +2 -0
  124. package/dist/lib/utils.js +5 -0
  125. package/dist/react-exports.d.ts +1 -0
  126. package/dist/react-exports.js +1 -0
  127. package/dist/server.d.ts +1 -0
  128. package/dist/server.js +1 -0
  129. package/dist/src/components/auth/auth-provider.d.ts +8 -0
  130. package/dist/src/components/auth/auth-provider.js +13 -0
  131. package/dist/src/components/auth/auth.d.ts +22 -0
  132. package/dist/src/components/auth/auth.js +42 -0
  133. package/dist/src/components/auth/field-separator.d.ts +4 -0
  134. package/dist/src/components/auth/field-separator.js +5 -0
  135. package/dist/src/components/auth/forgot-password.d.ts +15 -0
  136. package/dist/src/components/auth/forgot-password.js +29 -0
  137. package/dist/src/components/auth/magic-link-button.d.ts +13 -0
  138. package/dist/src/components/auth/magic-link-button.js +20 -0
  139. package/dist/src/components/auth/magic-link.d.ts +17 -0
  140. package/dist/src/components/auth/magic-link.js +37 -0
  141. package/dist/src/components/auth/provider-buttons.d.ts +19 -0
  142. package/dist/src/components/auth/provider-buttons.js +35 -0
  143. package/dist/src/components/auth/reset-password.d.ts +11 -0
  144. package/dist/src/components/auth/reset-password.js +59 -0
  145. package/dist/src/components/auth/sign-in.d.ts +14 -0
  146. package/dist/src/components/auth/sign-in.js +58 -0
  147. package/dist/src/components/auth/sign-out.d.ts +11 -0
  148. package/dist/src/components/auth/sign-out.js +34 -0
  149. package/dist/src/components/auth/sign-up.d.ts +19 -0
  150. package/dist/src/components/auth/sign-up.js +65 -0
  151. package/dist/src/components/email/email-changed-email.d.ts +3 -0
  152. package/dist/src/components/email/email-changed-email.js +23 -0
  153. package/dist/src/components/email/email-verification-email.d.ts +3 -0
  154. package/dist/src/components/email/email-verification-email.js +23 -0
  155. package/dist/src/components/email/magic-link-email.d.ts +3 -0
  156. package/dist/src/components/email/magic-link-email.js +23 -0
  157. package/dist/src/components/email/new-device-email.d.ts +3 -0
  158. package/dist/src/components/email/new-device-email.js +23 -0
  159. package/dist/src/components/email/otp-email.d.ts +3 -0
  160. package/dist/src/components/email/otp-email.js +22 -0
  161. package/dist/src/components/email/password-changed-email.d.ts +3 -0
  162. package/dist/src/components/email/password-changed-email.js +23 -0
  163. package/dist/src/components/email/reset-password-email.d.ts +3 -0
  164. package/dist/src/components/email/reset-password-email.js +23 -0
  165. package/dist/src/components/settings/account/account-settings.d.ts +13 -0
  166. package/dist/src/components/settings/account/account-settings.js +19 -0
  167. package/dist/src/components/settings/account/appearance.d.ts +16 -0
  168. package/dist/src/components/settings/account/appearance.js +28 -0
  169. package/dist/src/components/settings/account/change-email.d.ts +15 -0
  170. package/dist/src/components/settings/account/change-email.js +35 -0
  171. package/dist/src/components/settings/account/manage-account.d.ts +19 -0
  172. package/dist/src/components/settings/account/manage-account.js +27 -0
  173. package/dist/src/components/settings/account/manage-accounts.d.ts +14 -0
  174. package/dist/src/components/settings/account/manage-accounts.js +27 -0
  175. package/dist/src/components/settings/account/user-profile.d.ts +13 -0
  176. package/dist/src/components/settings/account/user-profile.js +29 -0
  177. package/dist/src/components/settings/security/active-session.d.ts +14 -0
  178. package/dist/src/components/settings/security/active-session.js +35 -0
  179. package/dist/src/components/settings/security/active-sessions.d.ts +14 -0
  180. package/dist/src/components/settings/security/active-sessions.js +29 -0
  181. package/dist/src/components/settings/security/change-password.d.ts +15 -0
  182. package/dist/src/components/settings/security/change-password.js +57 -0
  183. package/dist/src/components/settings/security/linked-account.d.ts +16 -0
  184. package/dist/src/components/settings/security/linked-account.js +46 -0
  185. package/dist/src/components/settings/security/linked-accounts.d.ts +15 -0
  186. package/dist/src/components/settings/security/linked-accounts.js +31 -0
  187. package/dist/src/components/settings/security/security-settings.d.ts +15 -0
  188. package/dist/src/components/settings/security/security-settings.js +18 -0
  189. package/dist/src/components/settings/settings.d.ts +29 -0
  190. package/dist/src/components/settings/settings.js +39 -0
  191. package/dist/src/components/user/switch-account-item.d.ts +16 -0
  192. package/dist/src/components/user/switch-account-item.js +14 -0
  193. package/dist/src/components/user/switch-account-menu.d.ts +10 -0
  194. package/dist/src/components/user/switch-account-menu.js +23 -0
  195. package/dist/src/components/user/user-avatar.d.ts +24 -0
  196. package/dist/src/components/user/user-avatar.js +31 -0
  197. package/dist/src/components/user/user-button.d.ts +21 -0
  198. package/dist/src/components/user/user-button.js +24 -0
  199. package/dist/src/components/user/user-view.d.ts +21 -0
  200. package/dist/src/components/user/user-view.js +24 -0
  201. package/dist/src/core.d.ts +1 -0
  202. package/dist/src/core.js +1 -0
  203. package/dist/src/index.d.ts +31 -0
  204. package/dist/src/index.js +32 -0
  205. package/dist/src/lib/utils.d.ts +2 -0
  206. package/dist/src/lib/utils.js +5 -0
  207. package/dist/src/react-exports.d.ts +1 -0
  208. package/dist/src/react-exports.js +1 -0
  209. package/dist/styles.css +1 -0
  210. package/package.json +63 -0
  211. package/src/components/auth/auth-provider.tsx +27 -0
  212. package/src/components/auth/auth.tsx +87 -0
  213. package/src/components/auth/field-separator.tsx +14 -0
  214. package/src/components/auth/forgot-password.tsx +107 -0
  215. package/src/components/auth/magic-link-button.tsx +43 -0
  216. package/src/components/auth/magic-link.tsx +181 -0
  217. package/src/components/auth/provider-buttons.tsx +85 -0
  218. package/src/components/auth/reset-password.tsx +210 -0
  219. package/src/components/auth/sign-in.tsx +260 -0
  220. package/src/components/auth/sign-out.tsx +44 -0
  221. package/src/components/auth/sign-up.tsx +314 -0
  222. package/src/components/email/email-changed-email.tsx +38 -0
  223. package/src/components/email/email-verification-email.tsx +38 -0
  224. package/src/components/email/magic-link-email.tsx +38 -0
  225. package/src/components/email/new-device-email.tsx +38 -0
  226. package/src/components/email/otp-email.tsx +33 -0
  227. package/src/components/email/password-changed-email.tsx +38 -0
  228. package/src/components/email/reset-password-email.tsx +38 -0
  229. package/src/components/settings/account/account-settings.tsx +48 -0
  230. package/src/components/settings/account/appearance.tsx +157 -0
  231. package/src/components/settings/account/change-avatar.tsx +142 -0
  232. package/src/components/settings/account/change-email.tsx +111 -0
  233. package/src/components/settings/account/manage-account.tsx +123 -0
  234. package/src/components/settings/account/manage-accounts.tsx +78 -0
  235. package/src/components/settings/account/user-profile.tsx +103 -0
  236. package/src/components/settings/security/active-session.tsx +123 -0
  237. package/src/components/settings/security/active-sessions.tsx +77 -0
  238. package/src/components/settings/security/change-password.tsx +335 -0
  239. package/src/components/settings/security/danger-zone.tsx +32 -0
  240. package/src/components/settings/security/delete-user.tsx +187 -0
  241. package/src/components/settings/security/linked-account.tsx +136 -0
  242. package/src/components/settings/security/linked-accounts.tsx +98 -0
  243. package/src/components/settings/security/security-settings.tsx +43 -0
  244. package/src/components/settings/settings.tsx +96 -0
  245. package/src/components/user/switch-account-item.tsx +39 -0
  246. package/src/components/user/switch-account-menu.tsx +64 -0
  247. package/src/components/user/user-avatar.tsx +88 -0
  248. package/src/components/user/user-button.tsx +221 -0
  249. package/src/components/user/user-view.tsx +74 -0
  250. package/src/core.ts +1 -0
  251. package/src/index.tsx +35 -0
  252. package/src/react-exports.ts +1 -0
  253. package/src/styles.css +1 -0
@@ -0,0 +1,19 @@
1
+ import { type CardProps } from "@heroui/react";
2
+ import { type SocialLayout } from "./provider-buttons";
3
+ export type SignUpProps = {
4
+ className?: string;
5
+ socialLayout?: SocialLayout;
6
+ socialPosition?: "top" | "bottom";
7
+ variant?: CardProps["variant"];
8
+ };
9
+ /**
10
+ * Render a sign-up form with name, email, password (and optional confirm password) fields, optional social provider buttons, and password visibility controls.
11
+ *
12
+ * The component reflects request state by disabling inputs and showing a pending indicator during sign-up or social sign-in.
13
+ *
14
+ * @param className - Additional CSS classes applied to the outer card container
15
+ * @param socialLayout - Social layout to apply to the provider buttons component
16
+ * @param socialPosition - Position of social provider buttons relative to the form; `"top"` or `"bottom"` (default `"bottom"`)
17
+ * @returns The sign-up form React element
18
+ */
19
+ export declare function SignUp({ className, socialLayout, socialPosition, variant, ...props }: SignUpProps & CardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,71 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAuth, useSignInSocial, useSignUpEmail } from "@better-auth-ui/react";
3
+ import { Eye, EyeSlash } from "@gravity-ui/icons";
4
+ import { Button, Card, cn, Description, FieldError, Form, Input, InputGroup, Label, Link, Spinner, TextField, toast } from "@heroui/react";
5
+ import { useState } from "react";
6
+ import { FieldSeparator } from "./field-separator";
7
+ import { MagicLinkButton } from "./magic-link-button";
8
+ import { ProviderButtons } from "./provider-buttons";
9
+ /**
10
+ * Render a sign-up form with name, email, password (and optional confirm password) fields, optional social provider buttons, and password visibility controls.
11
+ *
12
+ * The component reflects request state by disabling inputs and showing a pending indicator during sign-up or social sign-in.
13
+ *
14
+ * @param className - Additional CSS classes applied to the outer card container
15
+ * @param socialLayout - Social layout to apply to the provider buttons component
16
+ * @param socialPosition - Position of social provider buttons relative to the form; `"top"` or `"bottom"` (default `"bottom"`)
17
+ * @returns The sign-up form React element
18
+ */
19
+ export function SignUp({ className, socialLayout, socialPosition = "bottom", variant, ...props }) {
20
+ const { basePaths, emailAndPassword, localization, magicLink, redirectTo, socialProviders, viewPaths, navigate } = useAuth();
21
+ const [password, setPassword] = useState("");
22
+ const [confirmPassword, setConfirmPassword] = useState("");
23
+ const { mutate: signUpEmail, isPending: signUpPending } = useSignUpEmail({
24
+ onError: (error) => {
25
+ setPassword("");
26
+ setConfirmPassword("");
27
+ toast.danger(error.error?.message || error.message);
28
+ },
29
+ onSuccess: () => {
30
+ if (emailAndPassword?.requireEmailVerification) {
31
+ toast.success(localization.auth.verifyYourEmail);
32
+ navigate({ to: `${basePaths.auth}/${viewPaths.auth.signIn}` });
33
+ }
34
+ else {
35
+ navigate({ to: redirectTo });
36
+ }
37
+ }
38
+ });
39
+ const [socialRedirecting, setSocialRedirecting] = useState(false);
40
+ const { mutate: signInSocial, isPending: socialPending } = useSignInSocial({
41
+ onError: (error) => toast.danger(error.error?.message || error.message),
42
+ onSuccess: () => {
43
+ setSocialRedirecting(true);
44
+ setTimeout(() => {
45
+ setSocialRedirecting(false);
46
+ }, 5000);
47
+ }
48
+ });
49
+ const [isPasswordVisible, setIsPasswordVisible] = useState(false);
50
+ const [isConfirmPasswordVisible, setIsConfirmPasswordVisible] = useState(false);
51
+ const isPending = signUpPending || socialPending || socialRedirecting;
52
+ const handleSubmit = (e) => {
53
+ e.preventDefault();
54
+ const formData = new FormData(e.currentTarget);
55
+ const name = formData.get("name");
56
+ const email = formData.get("email");
57
+ if (emailAndPassword?.confirmPassword && password !== confirmPassword) {
58
+ toast.danger(localization.auth.passwordsDoNotMatch);
59
+ setPassword("");
60
+ setConfirmPassword("");
61
+ return;
62
+ }
63
+ signUpEmail({ name, email, password });
64
+ };
65
+ const showSeparator = emailAndPassword?.enabled && !!socialProviders?.length;
66
+ 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.signUp }) }), _jsxs(Card.Content, { className: "gap-4", children: [socialPosition === "top" && (_jsxs(_Fragment, { children: [!!socialProviders?.length && (_jsx(ProviderButtons, { isPending: isPending, socialLayout: socialLayout, signInSocial: signInSocial })), showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or }))] })), emailAndPassword?.enabled && (_jsxs(Form, { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs(TextField, { name: "name", type: "text", autoComplete: "name", isDisabled: isPending, children: [_jsx(Label, { children: localization.auth.name }), _jsx(Input, { placeholder: localization.auth.namePlaceholder, required: true, variant: variant === "transparent" ? "primary" : "secondary" }), _jsx(FieldError, {})] }), _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(TextField, { minLength: emailAndPassword?.minPasswordLength, maxLength: emailAndPassword?.maxPasswordLength, name: "password", autoComplete: "new-password", isDisabled: isPending, value: password, onChange: setPassword, children: [_jsx(Label, { children: localization.auth.password }), _jsxs(InputGroup, { variant: variant === "transparent" ? "primary" : "secondary", children: [_jsx(InputGroup.Input, { placeholder: localization.auth.passwordPlaceholder, type: isPasswordVisible ? "text" : "password", name: "password", required: true }), _jsx(InputGroup.Suffix, { className: "px-0", children: _jsx(Button, { isIconOnly: true, "aria-label": isPasswordVisible
67
+ ? localization.auth.hidePassword
68
+ : 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, value: confirmPassword, onChange: setConfirmPassword, children: [_jsx(Label, { children: localization.auth.confirmPassword }), _jsxs(InputGroup, { variant: variant === "transparent" ? "primary" : "secondary", children: [_jsx(InputGroup.Input, { name: "confirmPassword", placeholder: localization.auth.confirmPasswordPlaceholder, type: isConfirmPasswordVisible ? "text" : "password", required: true }), _jsx(InputGroup.Suffix, { className: "px-0", children: _jsx(Button, { isIconOnly: true, "aria-label": isConfirmPasswordVisible
69
+ ? localization.auth.hidePassword
70
+ : localization.auth.showPassword, size: "sm", variant: "ghost", onPress: () => setIsConfirmPasswordVisible(!isConfirmPasswordVisible), isDisabled: isPending, children: isConfirmPasswordVisible ? _jsx(EyeSlash, {}) : _jsx(Eye, {}) }) })] }), _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.signUp] }), magicLink && (_jsx(MagicLinkButton, { view: "signUp", 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.alreadyHaveAnAccount, " ", _jsx(Link, { href: `${basePaths.auth}/${viewPaths.auth.signIn}`, className: "text-accent decoration-accent no-underline hover:underline", children: localization.auth.signIn })] }) })] }));
71
+ }
@@ -0,0 +1,3 @@
1
+ import { type EmailChangedEmailProps } from "@better-auth-ui/react";
2
+ export type { EmailChangedEmailProps } from "@better-auth-ui/react";
3
+ export declare function EmailChangedEmail({ colors, classNames, ...props }: EmailChangedEmailProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { EmailChangedEmail as EmailChangedEmailPrimitive } from "@better-auth-ui/react";
3
+ import { cn } from "@heroui/react";
4
+ export function EmailChangedEmail({ colors, classNames, ...props }) {
5
+ return (_jsx(EmailChangedEmailPrimitive, { colors: {
6
+ light: {
7
+ background: "#F5F5F5",
8
+ primary: "#0285F7",
9
+ primaryForeground: "#FCFCFC",
10
+ ...colors?.light
11
+ },
12
+ dark: {
13
+ background: "#060607",
14
+ primary: "#0584F6",
15
+ primaryForeground: "#FCFCFC",
16
+ ...colors?.dark
17
+ }
18
+ }, classNames: {
19
+ ...classNames,
20
+ card: cn("border-none rounded-3xl", classNames?.card),
21
+ button: cn("rounded-full", classNames?.button)
22
+ }, ...props }));
23
+ }
@@ -0,0 +1,3 @@
1
+ import { type EmailVerificationEmailProps } from "@better-auth-ui/react";
2
+ export type { EmailVerificationEmailProps } from "@better-auth-ui/react";
3
+ export declare function EmailVerificationEmail({ colors, classNames, ...props }: EmailVerificationEmailProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { EmailVerificationEmail as EmailVerificationEmailPrimitive } from "@better-auth-ui/react";
3
+ import { cn } from "@heroui/react";
4
+ export function EmailVerificationEmail({ colors, classNames, ...props }) {
5
+ return (_jsx(EmailVerificationEmailPrimitive, { colors: {
6
+ light: {
7
+ background: "#F5F5F5",
8
+ primary: "#0285F7",
9
+ primaryForeground: "#FCFCFC",
10
+ ...colors?.light
11
+ },
12
+ dark: {
13
+ background: "#060607",
14
+ primary: "#0584F6",
15
+ primaryForeground: "#FCFCFC",
16
+ ...colors?.dark
17
+ }
18
+ }, classNames: {
19
+ ...classNames,
20
+ card: cn("border-none rounded-3xl", classNames?.card),
21
+ button: cn("rounded-full", classNames?.button)
22
+ }, ...props }));
23
+ }
@@ -0,0 +1,3 @@
1
+ import { type MagicLinkEmailProps } from "@better-auth-ui/react";
2
+ export type { MagicLinkEmailProps } from "@better-auth-ui/react";
3
+ export declare function MagicLinkEmail({ colors, classNames, ...props }: MagicLinkEmailProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { MagicLinkEmail as MagicLinkEmailPrimitive } from "@better-auth-ui/react";
3
+ import { cn } from "@heroui/react";
4
+ export function MagicLinkEmail({ colors, classNames, ...props }) {
5
+ return (_jsx(MagicLinkEmailPrimitive, { colors: {
6
+ light: {
7
+ background: "#F5F5F5",
8
+ primary: "#0285F7",
9
+ primaryForeground: "#FCFCFC",
10
+ ...colors?.light
11
+ },
12
+ dark: {
13
+ background: "#060607",
14
+ primary: "#0584F6",
15
+ primaryForeground: "#FCFCFC",
16
+ ...colors?.dark
17
+ }
18
+ }, classNames: {
19
+ ...classNames,
20
+ card: cn("border-none rounded-3xl", classNames?.card),
21
+ button: cn("rounded-full", classNames?.button)
22
+ }, ...props }));
23
+ }
@@ -0,0 +1,3 @@
1
+ import { type NewDeviceEmailProps } from "@better-auth-ui/react";
2
+ export type { NewDeviceEmailProps } from "@better-auth-ui/react";
3
+ export declare function NewDeviceEmail({ colors, classNames, ...props }: NewDeviceEmailProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { NewDeviceEmail as NewDeviceEmailPrimitive } from "@better-auth-ui/react";
3
+ import { cn } from "@heroui/react";
4
+ export function NewDeviceEmail({ colors, classNames, ...props }) {
5
+ return (_jsx(NewDeviceEmailPrimitive, { colors: {
6
+ light: {
7
+ background: "#F5F5F5",
8
+ primary: "#0285F7",
9
+ primaryForeground: "#FCFCFC",
10
+ ...colors?.light
11
+ },
12
+ dark: {
13
+ background: "#060607",
14
+ primary: "#0584F6",
15
+ primaryForeground: "#FCFCFC",
16
+ ...colors?.dark
17
+ }
18
+ }, classNames: {
19
+ ...classNames,
20
+ card: cn("border-none rounded-3xl", classNames?.card),
21
+ button: cn("rounded-full", classNames?.button)
22
+ }, ...props }));
23
+ }
@@ -0,0 +1,3 @@
1
+ import { type OtpEmailProps } from "@better-auth-ui/react";
2
+ export type { OtpEmailProps } from "@better-auth-ui/react";
3
+ export declare function OtpEmail({ colors, classNames, ...props }: OtpEmailProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { OtpEmail as OtpEmailPrimitive } from "@better-auth-ui/react";
3
+ import { cn } from "@heroui/react";
4
+ export function OtpEmail({ colors, classNames, ...props }) {
5
+ return (_jsx(OtpEmailPrimitive, { colors: {
6
+ light: {
7
+ background: "#F5F5F5",
8
+ primary: "#0285F7",
9
+ primaryForeground: "#FCFCFC",
10
+ ...colors?.light
11
+ },
12
+ dark: {
13
+ background: "#060607",
14
+ primary: "#0584F6",
15
+ primaryForeground: "#FCFCFC",
16
+ ...colors?.dark
17
+ }
18
+ }, classNames: {
19
+ ...classNames,
20
+ card: cn("border-none rounded-3xl", classNames?.card)
21
+ }, ...props }));
22
+ }
@@ -0,0 +1,3 @@
1
+ import { type PasswordChangedEmailProps } from "@better-auth-ui/react";
2
+ export type { PasswordChangedEmailProps } from "@better-auth-ui/react";
3
+ export declare function PasswordChangedEmail({ colors, classNames, ...props }: PasswordChangedEmailProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PasswordChangedEmail as PasswordChangedEmailPrimitive } from "@better-auth-ui/react";
3
+ import { cn } from "@heroui/react";
4
+ export function PasswordChangedEmail({ colors, classNames, ...props }) {
5
+ return (_jsx(PasswordChangedEmailPrimitive, { colors: {
6
+ light: {
7
+ background: "#F5F5F5",
8
+ primary: "#0285F7",
9
+ primaryForeground: "#FCFCFC",
10
+ ...colors?.light
11
+ },
12
+ dark: {
13
+ background: "#060607",
14
+ primary: "#0584F6",
15
+ primaryForeground: "#FCFCFC",
16
+ ...colors?.dark
17
+ }
18
+ }, classNames: {
19
+ ...classNames,
20
+ card: cn("border-none rounded-3xl", classNames?.card),
21
+ button: cn("rounded-full", classNames?.button)
22
+ }, ...props }));
23
+ }
@@ -0,0 +1,3 @@
1
+ import { type ResetPasswordEmailProps } from "@better-auth-ui/react";
2
+ export type { ResetPasswordEmailProps } from "@better-auth-ui/react";
3
+ export declare function ResetPasswordEmail({ colors, classNames, ...props }: ResetPasswordEmailProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ResetPasswordEmail as ResetPasswordEmailPrimitive } from "@better-auth-ui/react";
3
+ import { cn } from "@heroui/react";
4
+ export function ResetPasswordEmail({ colors, classNames, ...props }) {
5
+ return (_jsx(ResetPasswordEmailPrimitive, { colors: {
6
+ light: {
7
+ background: "#F5F5F5",
8
+ primary: "#0285F7",
9
+ primaryForeground: "#FCFCFC",
10
+ ...colors?.light
11
+ },
12
+ dark: {
13
+ background: "#060607",
14
+ primary: "#0584F6",
15
+ primaryForeground: "#FCFCFC",
16
+ ...colors?.dark
17
+ }
18
+ }, classNames: {
19
+ ...classNames,
20
+ card: cn("border-none rounded-3xl", classNames?.card),
21
+ button: cn("rounded-full", classNames?.button)
22
+ }, ...props }));
23
+ }
@@ -0,0 +1,16 @@
1
+ import { type CardProps } from "@heroui/react";
2
+ import type { ComponentProps } from "react";
3
+ export type AccountSettingsProps = {
4
+ className?: string;
5
+ variant?: CardProps["variant"];
6
+ };
7
+ /**
8
+ * Renders the account settings layout including user profile, change email, appearance, and accounts management.
9
+ *
10
+ * UserProfile, ChangeEmail, and Appearance are always rendered; Accounts is rendered when `multiSession` is enabled.
11
+ *
12
+ * @param className - Optional additional CSS class names for the outer container.
13
+ * @param variant - Card variant forwarded to each account settings card.
14
+ * @returns The account settings container as a JSX element.
15
+ */
16
+ export declare function AccountSettings({ className, variant, ...props }: AccountSettingsProps & ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAuth } from "@better-auth-ui/react";
3
+ import { cn } from "@heroui/react";
4
+ import { Appearance } from "./appearance";
5
+ import { ChangeEmail } from "./change-email";
6
+ import { ManageAccounts } from "./manage-accounts";
7
+ import { UserProfile } from "./user-profile";
8
+ /**
9
+ * Renders the account settings layout including user profile, change email, appearance, and accounts management.
10
+ *
11
+ * UserProfile, ChangeEmail, and Appearance are always rendered; Accounts is rendered when `multiSession` is enabled.
12
+ *
13
+ * @param className - Optional additional CSS class names for the outer container.
14
+ * @param variant - Card variant forwarded to each account settings card.
15
+ * @returns The account settings container as a JSX element.
16
+ */
17
+ export function AccountSettings({ className, variant, ...props }) {
18
+ const { multiSession, emailAndPassword, magicLink, appearance: { setTheme } } = useAuth();
19
+ return (_jsxs("div", { className: cn("flex w-full flex-col gap-4 md:gap-6", className), ...props, children: [_jsx(UserProfile, { variant: variant }), (emailAndPassword?.enabled || magicLink) && (_jsx(ChangeEmail, { variant: variant })), setTheme && _jsx(Appearance, { variant: variant }), multiSession && _jsx(ManageAccounts, { variant: variant })] }));
20
+ }
@@ -0,0 +1,14 @@
1
+ import { type CardProps } from "@heroui/react";
2
+ export type AccountsProps = {
3
+ className?: string;
4
+ variant?: CardProps["variant"];
5
+ };
6
+ /**
7
+ * Render a card that lists and manages all device sessions for the current user.
8
+ *
9
+ * Shows each session with user information and actions to switch to or revoke a session.
10
+ * When device session data is loading, a pending placeholder row is displayed.
11
+ *
12
+ * @returns A JSX element containing the accounts management card
13
+ */
14
+ export declare function Accounts({ className, ...props }: AccountsProps & CardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAuth, useListDeviceSessions, useRevokeMultiSession, useSession, useSetActiveSession } from "@better-auth-ui/react";
3
+ import { ArrowRightArrowLeft, ArrowRightFromSquare, CirclePlus } from "@gravity-ui/icons";
4
+ import { Button, buttonVariants, Card, cn, Spinner } from "@heroui/react";
5
+ import { UserView } from "../../user/user-view";
6
+ /**
7
+ * Render a card that lists and manages all device sessions for the current user.
8
+ *
9
+ * Shows each session with user information and actions to switch to or revoke a session.
10
+ * When device session data is loading, a pending placeholder row is displayed.
11
+ *
12
+ * @returns A JSX element containing the accounts management card
13
+ */
14
+ export function Accounts({ className, ...props }) {
15
+ const { basePaths, localization, viewPaths, Link } = useAuth();
16
+ const { data: sessionData } = useSession();
17
+ const { data: deviceSessions, isPending } = useListDeviceSessions();
18
+ const { settingActiveSession, setActiveSession } = useSetActiveSession();
19
+ const { revokingSession, revokeSession } = useRevokeMultiSession();
20
+ return (_jsxs(Card, { className: cn("p-4 md:p-6 gap-4", className), ...props, children: [_jsx(Card.Header, { children: _jsx(Card.Title, { className: "text-xl", children: localization.settings.accounts }) }), _jsx(Card.Content, { className: "gap-3", children: !isPending ? (deviceSessions?.map((deviceSession) => {
21
+ const isActive = deviceSession.session.userId === sessionData?.session.userId;
22
+ const isSwitching = settingActiveSession === deviceSession.session.token;
23
+ const isRevoking = revokingSession === deviceSession.session.token;
24
+ return (_jsxs(Card, { className: "flex-row items-center border p-3 shadow-none", children: [_jsx(UserView, { user: deviceSession.user, size: "md" }), _jsxs("div", { className: "flex items-center gap-1 shrink-0 ml-auto", children: [!isActive && (_jsx(Button, { isIconOnly: true, variant: "ghost", size: "sm", onPress: () => setActiveSession(deviceSession.session.token), isPending: isSwitching || isRevoking, "aria-label": localization.auth.switchAccount, children: isSwitching ? (_jsx(Spinner, { color: "current", size: "sm" })) : (_jsx(ArrowRightArrowLeft, {})) })), _jsx(Button, { isIconOnly: true, variant: "ghost", size: "sm", onPress: () => revokeSession(deviceSession.session.token), isPending: isSwitching || isRevoking, "aria-label": localization.auth.signOut, children: isRevoking ? (_jsx(Spinner, { color: "current", size: "sm" })) : (_jsx(ArrowRightFromSquare, {})) })] })] }, deviceSession.session.id));
25
+ })) : (_jsx("div", { className: "flex items-center rounded-3xl border p-3", children: _jsx(UserView, { isPending: true, size: "md" }) })) }), _jsx(Card.Footer, { children: _jsxs(Link, { href: `${basePaths.auth}/${viewPaths.auth.signIn}`, className: cn(buttonVariants({ variant: "secondary" })), children: [_jsx(CirclePlus, {}), localization.auth.addAccount] }) })] }));
26
+ }
@@ -0,0 +1,16 @@
1
+ import { type CardProps } from "@heroui/react";
2
+ export type AppearanceProps = {
3
+ className?: string;
4
+ variant?: CardProps["variant"];
5
+ };
6
+ /**
7
+ * Renders a theme selector card with visual theme previews.
8
+ *
9
+ * Displays a card containing radio buttons for selecting between system, light,
10
+ * and dark themes. Each option shows a visual preview of the theme. Only renders
11
+ * if theme settings are configured (theme, setTheme, and themes are provided).
12
+ *
13
+ * @param className - Optional additional CSS class names for the card container.
14
+ * @returns A JSX element containing the theme selector card, or null if theme settings are not configured.
15
+ */
16
+ export declare function Appearance({ className, variant, ...props }: AppearanceProps & CardProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ThemePreviewDark, ThemePreviewLight, ThemePreviewSystem, useAuth, useSession } from "@better-auth-ui/react";
3
+ import { Display, Moon, Sun } from "@gravity-ui/icons";
4
+ import { Card, cn, Label, Radio, RadioGroup } from "@heroui/react";
5
+ /**
6
+ * Renders a theme selector card with visual theme previews.
7
+ *
8
+ * Displays a card containing radio buttons for selecting between system, light,
9
+ * and dark themes. Each option shows a visual preview of the theme. Only renders
10
+ * if theme settings are configured (theme, setTheme, and themes are provided).
11
+ *
12
+ * @param className - Optional additional CSS class names for the card container.
13
+ * @returns A JSX element containing the theme selector card, or null if theme settings are not configured.
14
+ */
15
+ export function Appearance({ className, variant, ...props }) {
16
+ const { localization, appearance: { theme, setTheme, themes } } = useAuth();
17
+ const { data: session } = useSession();
18
+ if (!setTheme || !themes?.length) {
19
+ return null;
20
+ }
21
+ return (_jsxs("div", { children: [_jsx("h2", { className: cn("text-sm font-semibold mb-3"), children: localization.settings.appearance }), _jsx(Card, { className: cn("p-4 gap-4", className), variant: variant, ...props, children: _jsxs(Card.Content, { children: [_jsx(Label, { children: localization.settings.theme }), _jsx(RadioGroup, { variant: variant === "transparent" ? "secondary" : "primary", value: session ? theme : "", onChange: setTheme, isDisabled: !session || !theme, children: _jsxs("div", { className: "grid gap-3 grid-cols-2 sm:grid-cols-3", children: [themes.includes("system") && (_jsx(Radio, { value: "system", className: cn("mt-0 px-4 pb-4 pt-3 rounded-xl", "border border-transparent data-[selected=true]:border-accent data-[selected=true]:bg-accent/10", "data-[focus-visible=true]:border-accent data-[focus-visible=true]:bg-accent/10", variant === "transparent"
22
+ ? "bg-surface"
23
+ : "bg-surface-secondary"), children: _jsxs(Radio.Content, { className: "gap-2", children: [_jsxs("div", { className: "flex gap-2 justify-between", children: [_jsxs(Label, { className: "flex gap-2 items-center", children: [_jsx(Display, { className: "text-muted" }), localization.settings.system] }), _jsx(Radio.Control, { children: _jsx(Radio.Indicator, {}) })] }), _jsx(ThemePreviewSystem, { className: "w-full" })] }) })), themes.includes("light") && (_jsx(Radio, { value: "light", className: cn("mt-0 px-4 pb-4 pt-3 rounded-xl", "border border-transparent data-[selected=true]:border-accent data-[selected=true]:bg-accent/10", "data-[focus-visible=true]:border-accent data-[focus-visible=true]:bg-accent/10", variant === "transparent"
24
+ ? "bg-surface"
25
+ : "bg-surface-secondary"), children: _jsxs(Radio.Content, { className: "gap-2", children: [_jsxs("div", { className: "flex gap-2 justify-between", children: [_jsxs(Label, { className: "flex gap-2 items-center", children: [_jsx(Sun, { className: "text-muted" }), localization.settings.light] }), _jsx(Radio.Control, { children: _jsx(Radio.Indicator, {}) })] }), _jsx(ThemePreviewLight, { className: "w-full" })] }) })), themes.includes("dark") && (_jsx(Radio, { value: "dark", className: cn("mt-0 px-4 pb-4 pt-3 rounded-xl", "border border-transparent data-[selected=true]:border-accent data-[selected=true]:bg-accent/10", "data-[focus-visible=true]:border-accent data-[focus-visible=true]:bg-accent/10", variant === "transparent"
26
+ ? "bg-surface"
27
+ : "bg-surface-secondary"), children: _jsxs(Radio.Content, { className: "gap-2", children: [_jsxs("div", { className: "flex gap-2 justify-between", children: [_jsxs(Label, { className: "flex gap-2 items-center", children: [_jsx(Moon, { className: "text-muted" }), localization.settings.dark] }), _jsx(Radio.Control, { children: _jsx(Radio.Indicator, {}) })] }), _jsx(ThemePreviewDark, { className: "w-full" })] }) }))] }) })] }) })] }));
28
+ }
@@ -0,0 +1,4 @@
1
+ export type ChangeAvatarProps = {
2
+ className?: string;
3
+ };
4
+ export declare function ChangeAvatar({ className }: ChangeAvatarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { fileToBase64 } from "@better-auth-ui/core";
3
+ import { useAuth, useSession, useUpdateUser } from "@better-auth-ui/react";
4
+ import { CloudArrowUpIn, TrashBin } from "@gravity-ui/icons";
5
+ import { Button, cn, Dropdown, Label, Spinner, toast } from "@heroui/react";
6
+ import { useRef, useState } from "react";
7
+ import { UserAvatar } from "../../user/user-avatar";
8
+ export function ChangeAvatar({ className }) {
9
+ const { localization, avatar } = useAuth();
10
+ const { data: session } = useSession();
11
+ const { mutate: updateUser, isPending: updatePending } = useUpdateUser({
12
+ onError: (error) => toast.danger(error.error?.message || error.message)
13
+ });
14
+ const fileInputRef = useRef(null);
15
+ const [isUploading, setIsUploading] = useState(false);
16
+ const [isDeleting, setIsDeleting] = useState(false);
17
+ const isPending = updatePending || isUploading || isDeleting;
18
+ async function handleFileChange(e) {
19
+ const file = e.target.files?.[0];
20
+ if (!file)
21
+ return;
22
+ e.target.value = "";
23
+ setIsUploading(true);
24
+ try {
25
+ const resized = (await avatar.resize?.(file, avatar.size, avatar.extension)) || file;
26
+ const image = (await avatar.upload?.(resized)) || (await fileToBase64(resized));
27
+ updateUser({ image }, {
28
+ onSuccess: () => toast.success(localization.settings.avatarChangedSuccess)
29
+ });
30
+ }
31
+ catch (error) {
32
+ if (error instanceof Error) {
33
+ toast.danger(error.message);
34
+ }
35
+ }
36
+ setIsUploading(false);
37
+ }
38
+ async function handleDelete() {
39
+ const currentImage = session?.user.image;
40
+ updateUser({ image: null }, {
41
+ onSuccess: async () => {
42
+ if (currentImage) {
43
+ setIsDeleting(true);
44
+ try {
45
+ await avatar.delete?.(currentImage);
46
+ }
47
+ finally {
48
+ setIsDeleting(false);
49
+ }
50
+ }
51
+ toast.success(localization.settings.avatarDeletedSuccess);
52
+ }
53
+ });
54
+ }
55
+ return (_jsxs("div", { className: cn("flex flex-col gap-1", className), children: [_jsx(Label, { isDisabled: !session, children: localization.settings.avatar }), _jsx("input", { ref: fileInputRef, type: "file", accept: "image/*", className: "hidden", onChange: handleFileChange }), _jsxs("div", { className: "flex items-center gap-4", children: [_jsx(Button, { type: "button", isIconOnly: true, variant: "ghost", className: "p-0 h-auto w-auto rounded-full", isDisabled: !session || isPending, onPress: () => fileInputRef.current?.click(), children: _jsx(UserAvatar, { size: "lg", isPending: isPending }) }), _jsxs(Dropdown, { children: [_jsxs(Button, { isDisabled: !session || isPending, size: "sm", variant: "secondary", children: [isPending && _jsx(Spinner, { size: "sm" }), localization.settings.changeAvatar] }), _jsx(Dropdown.Popover, { className: "min-w-fit", children: _jsxs(Dropdown.Menu, { children: [_jsxs(Dropdown.Item, { textValue: localization.settings.uploadAvatar, onAction: () => fileInputRef.current?.click(), children: [_jsx(CloudArrowUpIn, { className: "text-muted" }), _jsx(Label, { children: localization.settings.uploadAvatar })] }), _jsxs(Dropdown.Item, { textValue: localization.settings.deleteAvatar, isDisabled: !session?.user.image, onAction: handleDelete, variant: "danger", children: [_jsx(TrashBin, { className: "text-danger" }), _jsx(Label, { children: localization.settings.deleteAvatar })] })] }) })] })] })] }));
56
+ }
@@ -0,0 +1,15 @@
1
+ import { type CardProps } from "@heroui/react";
2
+ export type ChangeEmailProps = {
3
+ className?: string;
4
+ variant?: CardProps["variant"];
5
+ };
6
+ /**
7
+ * Render a card containing a form to view and update the authenticated user's email.
8
+ *
9
+ * Shows a loading skeleton until session data is available, displays the current
10
+ * email as the form's default value, and sends a verification email to the
11
+ * new address upon successful submission.
12
+ *
13
+ * @returns A JSX element rendering the change-email card and form
14
+ */
15
+ export declare function ChangeEmail({ className, variant, ...props }: ChangeEmailProps & CardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAuth, useChangeEmail, useSession } from "@better-auth-ui/react";
3
+ import { Button, Card, cn, FieldError, Fieldset, Form, Input, Label, Skeleton, Spinner, TextField, toast } from "@heroui/react";
4
+ /**
5
+ * Render a card containing a form to view and update the authenticated user's email.
6
+ *
7
+ * Shows a loading skeleton until session data is available, displays the current
8
+ * email as the form's default value, and sends a verification email to the
9
+ * new address upon successful submission.
10
+ *
11
+ * @returns A JSX element rendering the change-email card and form
12
+ */
13
+ export function ChangeEmail({ className, variant, ...props }) {
14
+ const { localization, baseURL, viewPaths } = useAuth();
15
+ const { data: session } = useSession();
16
+ const { mutate: changeEmail, isPending } = useChangeEmail({
17
+ onSuccess: () => toast.success(localization.settings.changeEmailSuccess),
18
+ onError: (error) => toast.danger(error.error?.message || error.message)
19
+ });
20
+ function handleSubmit(e) {
21
+ e.preventDefault();
22
+ const formData = new FormData(e.currentTarget);
23
+ changeEmail({
24
+ newEmail: formData.get("email"),
25
+ callbackURL: `${baseURL}/${viewPaths.settings.account}`
26
+ });
27
+ }
28
+ return (_jsxs("div", { children: [_jsx("h2", { className: cn("text-sm font-semibold mb-3"), children: localization.settings.changeEmail }), _jsx(Card, { className: cn("p-4 gap-4", className), variant: variant, ...props, children: _jsx(Card.Content, { children: _jsx(Form, { onSubmit: handleSubmit, children: _jsxs(Fieldset, { className: "w-full gap-4", children: [_jsx(Fieldset.Group, { children: _jsxs(TextField, { name: "email", type: "email", defaultValue: session?.user.email, isDisabled: isPending || !session, children: [_jsx(Label, { children: localization.auth.email }), session ? (_jsx(Input, { required: true, variant: variant === "transparent" ? "primary" : "secondary", autoComplete: "email", placeholder: localization.auth.emailPlaceholder })) : (_jsx(Skeleton, { className: "h-10 md:h-9 w-full rounded-xl" })), _jsx(FieldError, {})] }, session?.user.email) }), _jsx(Fieldset.Actions, { children: _jsxs(Button, { type: "submit", isPending: isPending, isDisabled: !session, size: "sm", children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), localization.settings.updateEmail] }) })] }) }) }) })] }));
29
+ }
@@ -0,0 +1,19 @@
1
+ import type { Session, User } from "better-auth";
2
+ export type DeviceSession = {
3
+ session: Session;
4
+ user: User;
5
+ };
6
+ export type ManageAccountProps = {
7
+ deviceSession?: DeviceSession | null;
8
+ isPending?: boolean;
9
+ };
10
+ /**
11
+ * Render a single account row with user info and a dropdown for switch/sign-out actions.
12
+ *
13
+ * Shows the user's avatar and info. A three-dot menu provides options to
14
+ * switch account (for non-active sessions) and sign out.
15
+ *
16
+ * @param deviceSession - The device session object containing session and user data
17
+ * @returns A JSX element containing the account row
18
+ */
19
+ export declare function ManageAccount({ deviceSession, isPending }: ManageAccountProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAuth, useRevokeMultiSession, useSetActiveSession, useUser } from "@better-auth-ui/react";
3
+ import { ArrowRightArrowLeft, ArrowRightFromSquare, Ellipsis } from "@gravity-ui/icons";
4
+ import { Button, Dropdown, Spinner, toast } from "@heroui/react";
5
+ import { UserView } from "../../user/user-view";
6
+ /**
7
+ * Render a single account row with user info and a dropdown for switch/sign-out actions.
8
+ *
9
+ * Shows the user's avatar and info. A three-dot menu provides options to
10
+ * switch account (for non-active sessions) and sign out.
11
+ *
12
+ * @param deviceSession - The device session object containing session and user data
13
+ * @returns A JSX element containing the account row
14
+ */
15
+ export function ManageAccount({ deviceSession, isPending }) {
16
+ const { localization } = useAuth();
17
+ const { data: user } = useUser();
18
+ const { mutate: setActiveSession, isPending: isSwitching } = useSetActiveSession({
19
+ onError: (error) => toast.danger(error.error?.message || error.message)
20
+ });
21
+ const { mutate: revokeSession, isPending: isRevoking } = useRevokeMultiSession({
22
+ onError: (error) => toast.danger(error.error?.message || error.message),
23
+ onSuccess: () => toast.success(localization.settings.revokeSessionSuccess)
24
+ });
25
+ const isActive = deviceSession?.session.userId === user?.id;
26
+ const isBusy = isSwitching || isRevoking;
27
+ return (_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(UserView, { user: deviceSession?.user, isPending: isPending, size: "md" }), deviceSession && isActive && (_jsxs(Button, { className: "shrink-0", variant: "outline", size: "sm", onPress: () => revokeSession({ sessionToken: deviceSession.session.token }), isDisabled: isBusy, children: [isRevoking ? (_jsx(Spinner, { color: "current", size: "sm" })) : (_jsx(ArrowRightFromSquare, {})), localization.auth.signOut] })), deviceSession && !isActive && (_jsxs(Dropdown, { children: [_jsx(Button, { isIconOnly: true, variant: "ghost", className: "shrink-0", size: "sm", isDisabled: isBusy, children: _jsx(Ellipsis, {}) }), _jsx(Dropdown.Popover, { children: _jsxs(Dropdown.Menu, { children: [_jsxs(Dropdown.Item, { textValue: localization.auth.switchAccount, onAction: () => setActiveSession({
28
+ sessionToken: deviceSession.session.token
29
+ }), children: [_jsx(ArrowRightArrowLeft, { className: "text-muted" }), localization.auth.switchAccount] }), _jsxs(Dropdown.Item, { textValue: localization.auth.signOut, onAction: () => revokeSession({
30
+ sessionToken: deviceSession.session.token
31
+ }), children: [_jsx(ArrowRightFromSquare, { className: "text-muted" }), localization.auth.signOut] })] }) })] }))] }));
32
+ }
@@ -0,0 +1,14 @@
1
+ import { type CardProps } from "@heroui/react";
2
+ export type ManageAccountsProps = {
3
+ className?: string;
4
+ variant?: CardProps["variant"];
5
+ };
6
+ /**
7
+ * Render a card that lists and manages all device sessions for the current user.
8
+ *
9
+ * Shows each session with user information and actions to switch to or revoke a session.
10
+ * When device session data is loading, a pending placeholder row is displayed.
11
+ *
12
+ * @returns A JSX element containing the accounts management card
13
+ */
14
+ export declare function ManageAccounts({ className, variant, ...props }: ManageAccountsProps & CardProps): import("react/jsx-runtime").JSX.Element;