@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,31 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAuth, useListAccounts } from "@better-auth-ui/react";
3
+ import { Card, cn, Skeleton, toast } from "@heroui/react";
4
+ import { ConnectedAccount } from "./connected-account";
5
+ /**
6
+ * Render a card showing linked social accounts and available social providers to connect.
7
+ *
8
+ * Linked accounts (excluding the "credential" provider) are shown with an unlink control;
9
+ * available providers are shown with a connect control. Button states and labels reflect
10
+ * ongoing link/unlink activity and use localization for provider-specific text.
11
+ *
12
+ * @returns A JSX element containing the connected accounts card
13
+ */
14
+ export function ConnectedAccounts({ className, ...props }) {
15
+ const { localization, socialProviders } = useAuth();
16
+ const { data: accounts, isPending } = useListAccounts({
17
+ throwOnError: (error) => {
18
+ if (error.error)
19
+ toast.danger(error.error.message, { timeout: 3000 });
20
+ return false;
21
+ }
22
+ });
23
+ 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.connectedAccounts }) }), _jsx(Card.Content, { className: "gap-3", children: isPending ? (_jsx(AccountRowSkeleton, {})) : (_jsxs(_Fragment, { children: [accounts
24
+ ?.filter((account) => account.providerId !== "credential")
25
+ .map((account) => (_jsx(ConnectedAccount, { account: account, provider: account.providerId }, account.id))), socialProviders?.map((provider) => {
26
+ return _jsx(ConnectedAccount, { provider: provider }, provider);
27
+ })] })) })] }));
28
+ }
29
+ function AccountRowSkeleton() {
30
+ return (_jsx("div", { className: "flex items-center rounded-3xl border p-3 justify-between", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Skeleton, { className: "size-10 rounded-xl" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Skeleton, { className: "h-4 w-20 rounded-lg" }), _jsx(Skeleton, { className: "h-3 w-32 rounded-lg" })] })] }) }));
31
+ }
@@ -0,0 +1,11 @@
1
+ import { type CardProps } from "@heroui/react";
2
+ import type { ComponentProps } from "react";
3
+ export type DangerZoneProps = {
4
+ className?: string;
5
+ variant?: CardProps["variant"];
6
+ };
7
+ /**
8
+ * Renders the danger zone heading and {@link DeleteUser}.
9
+ * Gate with `deleteUser.enabled` at the call site (e.g. {@link SecuritySettings}).
10
+ */
11
+ export declare function DangerZone({ className, variant, ...props }: DangerZoneProps & ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,12 @@
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 { DeleteUser } from "./delete-user";
5
+ /**
6
+ * Renders the danger zone heading and {@link DeleteUser}.
7
+ * Gate with `deleteUser.enabled` at the call site (e.g. {@link SecuritySettings}).
8
+ */
9
+ export function DangerZone({ className, variant, ...props }) {
10
+ const { localization } = useAuth();
11
+ return (_jsxs("div", { className: cn("flex w-full flex-col", className), ...props, children: [_jsx("h2", { className: cn("text-sm font-semibold mb-3"), children: localization.settings.dangerZone }), _jsx(DeleteUser, { variant: variant })] }));
12
+ }
@@ -0,0 +1,9 @@
1
+ import { type CardProps } from "@heroui/react";
2
+ export type DeleteUserProps = {
3
+ className?: string;
4
+ variant?: CardProps["variant"];
5
+ };
6
+ /**
7
+ * Danger-zone card to delete the authenticated account, with a confirmation dialog and toasts.
8
+ */
9
+ export declare function DeleteUser({ className, variant, ...props }: DeleteUserProps & CardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAuth, useDeleteUser, useListAccounts } from "@better-auth-ui/react";
3
+ import { TriangleExclamation } from "@gravity-ui/icons";
4
+ import { AlertDialog, Button, Card, cn, FieldError, Form, Input, Label, Spinner, TextField, toast } from "@heroui/react";
5
+ import { useState } from "react";
6
+ /**
7
+ * Danger-zone card to delete the authenticated account, with a confirmation dialog and toasts.
8
+ */
9
+ export function DeleteUser({ className, variant, ...props }) {
10
+ const { basePaths, deleteUser: deleteUserConfig, localization, navigate, viewPaths } = useAuth();
11
+ const { data: accounts } = useListAccounts();
12
+ const [confirmOpen, setConfirmOpen] = useState(false);
13
+ const [password, setPassword] = useState("");
14
+ const hasCredentialAccount = accounts?.some((account) => account.providerId === "credential");
15
+ const needsPassword = !deleteUserConfig?.sendDeleteAccountVerification && hasCredentialAccount;
16
+ const { mutate: deleteUser, isPending } = useDeleteUser();
17
+ const handleDialogOpenChange = (open) => {
18
+ setConfirmOpen(open);
19
+ setPassword("");
20
+ };
21
+ const handleSubmit = async (e) => {
22
+ e.preventDefault();
23
+ const params = {
24
+ ...(needsPassword ? { password } : {})
25
+ };
26
+ deleteUser(params, {
27
+ onSuccess: () => {
28
+ setConfirmOpen(false);
29
+ setPassword("");
30
+ if (deleteUserConfig?.sendDeleteAccountVerification) {
31
+ toast.success(localization.settings.deleteUserVerificationSent);
32
+ }
33
+ else {
34
+ toast.success(localization.settings.deleteUserSuccess);
35
+ navigate({
36
+ to: `${basePaths.auth}/${viewPaths.auth.signIn}`,
37
+ replace: true
38
+ });
39
+ }
40
+ },
41
+ onError: (error) => {
42
+ toast.danger(error.error?.message || error.message);
43
+ }
44
+ });
45
+ };
46
+ return (_jsx(Card, { className: cn("border border-danger", className), variant: variant, ...props, children: _jsxs(Card.Content, { className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium leading-tight", children: localization.settings.deleteUser }), _jsx("p", { className: "text-muted text-xs mt-0.5", children: localization.settings.deleteUserDescription })] }), _jsxs(AlertDialog, { children: [_jsx(Button, { isDisabled: !accounts, size: "sm", variant: "danger", onPress: () => setConfirmOpen(true), children: localization.settings.deleteUser }), _jsx(AlertDialog.Backdrop, { isOpen: confirmOpen, onOpenChange: handleDialogOpenChange, children: _jsx(AlertDialog.Container, { children: _jsx(AlertDialog.Dialog, { children: _jsxs(Form, { onSubmit: handleSubmit, children: [_jsx(AlertDialog.CloseTrigger, {}), _jsxs(AlertDialog.Header, { children: [_jsx(AlertDialog.Icon, { status: "danger", children: _jsx(TriangleExclamation, {}) }), _jsx(AlertDialog.Heading, { children: localization.settings.deleteUser })] }), _jsxs(AlertDialog.Body, { className: "overflow-visible", children: [_jsx("p", { className: "text-muted text-sm", children: localization.settings.deleteUserDescription }), needsPassword && (_jsxs(TextField, { className: "mt-4", name: "password", type: "password", isDisabled: isPending, value: password, onChange: setPassword, children: [_jsx(Label, { children: localization.auth.password }), _jsx(Input, { autoComplete: "current-password", placeholder: localization.auth.passwordPlaceholder, required: true, variant: "secondary" }), _jsx(FieldError, {})] }))] }), _jsxs(AlertDialog.Footer, { children: [_jsx(Button, { slot: "close", variant: "tertiary", isDisabled: isPending, children: localization.settings.cancel }), _jsxs(Button, { type: "submit", variant: "danger", isPending: isPending, children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), localization.settings.deleteUser] })] })] }) }) }) })] })] }) }));
47
+ }
@@ -0,0 +1,16 @@
1
+ import type { Account, SocialProvider } from "better-auth";
2
+ export type LinkedAccountProps = {
3
+ account?: Account;
4
+ provider: SocialProvider;
5
+ };
6
+ /**
7
+ * Render a single linked social account row with provider info and link/unlink control.
8
+ *
9
+ * Fetches additional account information from the provider using the accountInfo API
10
+ * and displays the provider name, account details, and a link/unlink button.
11
+ *
12
+ * @param account - The account object containing id, accountId, and providerId
13
+ * @param provider - The provider id
14
+ * @returns A JSX element containing the linked account row
15
+ */
16
+ export declare function LinkedAccount({ account, provider }: LinkedAccountProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,48 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { getProviderName } from "@better-auth-ui/core";
3
+ import { providerIcons, useAccountInfo, useAuth, useLinkSocial, useUnlinkAccount } from "@better-auth-ui/react";
4
+ import { Link, LinkSlash, PlugConnection } from "@gravity-ui/icons";
5
+ import { Button, cn, Skeleton, Spinner, toast } from "@heroui/react";
6
+ /**
7
+ * Render a single linked social account row with provider info and link/unlink control.
8
+ *
9
+ * Fetches additional account information from the provider using the accountInfo API
10
+ * and displays the provider name, account details, and a link/unlink button.
11
+ *
12
+ * @param account - The account object containing id, accountId, and providerId
13
+ * @param provider - The provider id
14
+ * @returns A JSX element containing the linked account row
15
+ */
16
+ export function LinkedAccount({ account, provider }) {
17
+ const { baseURL, localization } = useAuth();
18
+ const { data: accountInfo, isPending: isLoadingInfo } = useAccountInfo(account?.accountId, {
19
+ enabled: !!account,
20
+ throwOnError: (error) => {
21
+ if (error.error)
22
+ toast.danger(error.error.message);
23
+ return false;
24
+ }
25
+ });
26
+ const { mutate: linkSocial, isPending: isLinking } = useLinkSocial({
27
+ onError: (error) => toast.danger(error.error?.message || error.message)
28
+ });
29
+ const { mutate: unlinkAccount, isPending: isUnlinking } = useUnlinkAccount({
30
+ onError: (error) => toast.danger(error.error?.message || error.message),
31
+ onSuccess: () => toast.success(localization.settings.accountUnlinked)
32
+ });
33
+ const ProviderIcon = providerIcons[provider];
34
+ const providerName = getProviderName(provider);
35
+ const displayName = accountInfo?.data?.login ||
36
+ accountInfo?.data?.username ||
37
+ accountInfo?.user?.email ||
38
+ accountInfo?.user?.name ||
39
+ account?.accountId;
40
+ return (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: cn("flex size-10 shrink-0 items-center justify-center rounded-xl bg-surface-secondary"), children: ProviderIcon ? (_jsx(ProviderIcon, { className: cn("size-4.5", !account && "opacity-50") })) : (_jsx(PlugConnection, { className: cn("size-4.5", !account && "opacity-50") })) }), _jsxs("div", { className: "flex flex-col min-w-0", children: [_jsx("span", { className: "text-sm font-medium leading-tight", children: providerName }), account && isLoadingInfo ? (_jsx(Skeleton, { className: "h-3 w-24 my-0.5 rounded-lg" })) : (_jsx("span", { className: "text-xs text-muted truncate", children: account
41
+ ? displayName
42
+ : localization.settings.linkProvider.replace("{{provider}}", providerName) }))] }), account ? (_jsxs(Button, { className: "ml-auto shrink-0", variant: "outline", size: "sm", onPress: () => unlinkAccount({ providerId: account.providerId }), isPending: isUnlinking, "aria-label": localization.settings.unlinkProvider.replace("{{provider}}", providerName), children: [isUnlinking ? _jsx(Spinner, { color: "current", size: "sm" }) : _jsx(LinkSlash, {}), localization.settings.unlinkProvider
43
+ .replace("{{provider}}", "")
44
+ .trim()] })) : (_jsxs(Button, { className: "ml-auto shrink-0", variant: "outline", size: "sm", onPress: () => linkSocial({
45
+ provider,
46
+ callbackURL: `${baseURL}${window.location.pathname}`
47
+ }), isPending: isLinking, "aria-label": localization.settings.linkProvider.replace("{{provider}}", providerName), children: [isLinking ? _jsx(Spinner, { color: "current", size: "sm" }) : _jsx(Link, {}), localization.settings.link] }))] }));
48
+ }
@@ -0,0 +1,15 @@
1
+ import { type CardProps } from "@heroui/react";
2
+ export type LinkedAccountsProps = {
3
+ className?: string;
4
+ variant?: CardProps["variant"];
5
+ };
6
+ /**
7
+ * Render a card showing linked social accounts and available social providers to link.
8
+ *
9
+ * Linked accounts (excluding the "credential" provider) are shown with an unlink control;
10
+ * available providers are shown with a link control. Button states and labels reflect
11
+ * ongoing link/unlink activity and use localization for provider-specific text.
12
+ *
13
+ * @returns A JSX element containing the linked accounts card
14
+ */
15
+ export declare function LinkedAccounts({ className, variant, ...props }: LinkedAccountsProps & CardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAuth, useListAccounts } from "@better-auth-ui/react";
3
+ import { Card, cn, Skeleton, toast } from "@heroui/react";
4
+ import { LinkedAccount } from "./linked-account";
5
+ /**
6
+ * Render a card showing linked social accounts and available social providers to link.
7
+ *
8
+ * Linked accounts (excluding the "credential" provider) are shown with an unlink control;
9
+ * available providers are shown with a link control. Button states and labels reflect
10
+ * ongoing link/unlink activity and use localization for provider-specific text.
11
+ *
12
+ * @returns A JSX element containing the linked accounts card
13
+ */
14
+ export function LinkedAccounts({ className, variant, ...props }) {
15
+ const { localization, socialProviders } = useAuth();
16
+ const { data: accounts, isPending } = useListAccounts({
17
+ throwOnError: (error) => {
18
+ if (error.error)
19
+ toast.danger(error.error.message);
20
+ return false;
21
+ }
22
+ });
23
+ const linkedAccounts = accounts?.filter((account) => account.providerId !== "credential");
24
+ const allRows = [
25
+ ...(linkedAccounts?.map((account) => ({
26
+ key: account.id,
27
+ account,
28
+ provider: account.providerId
29
+ })) ?? []),
30
+ ...(socialProviders?.map((provider) => ({
31
+ key: provider,
32
+ account: undefined,
33
+ provider
34
+ })) ?? [])
35
+ ];
36
+ return (_jsxs("div", { children: [_jsx("h2", { className: cn("text-sm font-semibold mb-3"), children: localization.settings.linkedAccounts }), _jsx(Card, { className: cn(className), variant: variant, ...props, children: _jsx(Card.Content, { className: "gap-0", children: isPending
37
+ ? socialProviders?.map((provider, index) => (_jsxs("div", { children: [index > 0 && (_jsx("div", { className: "border-b border-dashed -mx-4 md:-mx-6 my-4" })), _jsx(AccountRowSkeleton, {})] }, provider)))
38
+ : allRows.map((row, index) => (_jsxs("div", { children: [index > 0 && (_jsx("div", { className: "border-b border-dashed -mx-4 md:-mx-6 my-4" })), _jsx(LinkedAccount, { account: row.account, provider: row.provider })] }, row.key))) }) })] }));
39
+ }
40
+ function AccountRowSkeleton() {
41
+ return (_jsx("div", { className: "flex items-center justify-between", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Skeleton, { className: "size-10 rounded-xl" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Skeleton, { className: "h-4 w-20 rounded-lg" }), _jsx(Skeleton, { className: "h-3 w-32 rounded-lg" })] })] }) }));
42
+ }
@@ -0,0 +1,17 @@
1
+ import { type CardProps } from "@heroui/react";
2
+ import type { ComponentProps } from "react";
3
+ export type SecuritySettingsProps = {
4
+ className?: string;
5
+ variant?: CardProps["variant"];
6
+ };
7
+ /**
8
+ * Renders the security settings layout including password management, linked accounts, and active sessions.
9
+ *
10
+ * ChangePassword is rendered when password authentication is enabled; LinkedAccounts is rendered when social providers are present.
11
+ * DangerZone is rendered when `deleteUser.enabled` is true in auth config.
12
+ *
13
+ * @param className - Optional additional CSS class names for the outer container.
14
+ * @param variant - Card variant forwarded to each security settings card.
15
+ * @returns The security settings container as a JSX element.
16
+ */
17
+ export declare function SecuritySettings({ className, variant, ...props }: SecuritySettingsProps & ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
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 { ActiveSessions } from "./active-sessions";
5
+ import { ChangePassword } from "./change-password";
6
+ import { DangerZone } from "./danger-zone";
7
+ import { LinkedAccounts } from "./linked-accounts";
8
+ /**
9
+ * Renders the security settings layout including password management, linked accounts, and active sessions.
10
+ *
11
+ * ChangePassword is rendered when password authentication is enabled; LinkedAccounts is rendered when social providers are present.
12
+ * DangerZone is rendered when `deleteUser.enabled` is true in auth config.
13
+ *
14
+ * @param className - Optional additional CSS class names for the outer container.
15
+ * @param variant - Card variant forwarded to each security settings card.
16
+ * @returns The security settings container as a JSX element.
17
+ */
18
+ export function SecuritySettings({ className, variant, ...props }) {
19
+ const { deleteUser, emailAndPassword, socialProviders } = useAuth();
20
+ return (_jsxs("div", { className: cn("flex w-full flex-col gap-4 md:gap-6", className), ...props, children: [emailAndPassword?.enabled && _jsx(ChangePassword, { variant: variant }), !!socialProviders?.length && _jsx(LinkedAccounts, { variant: variant }), _jsx(ActiveSessions, { variant: variant }), deleteUser?.enabled && _jsx(DangerZone, { variant: variant })] }));
21
+ }
@@ -0,0 +1,14 @@
1
+ import { type CardProps } from "@heroui/react";
2
+ export type SessionsProps = {
3
+ className?: string;
4
+ variant?: CardProps["variant"];
5
+ };
6
+ /**
7
+ * Render a card listing all active sessions for the current user with revoke controls.
8
+ *
9
+ * Shows each session's browser, OS, IP address, and creation time. The current session is marked
10
+ * and navigates to sign-out on click, while other sessions can be revoked individually.
11
+ *
12
+ * @returns A JSX element containing the sessions card
13
+ */
14
+ export declare function Sessions({ className, ...props }: SessionsProps & CardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useAuth, useListSessions, useRevokeSession, useSession } from "@better-auth-ui/react";
3
+ import { ArrowRightFromSquare, Display, Smartphone } from "@gravity-ui/icons";
4
+ import { Button, Card, Chip, cn, Skeleton, Spinner } from "@heroui/react";
5
+ import { UAParser } from "ua-parser-js";
6
+ /**
7
+ * Render a card listing all active sessions for the current user with revoke controls.
8
+ *
9
+ * Shows each session's browser, OS, IP address, and creation time. The current session is marked
10
+ * and navigates to sign-out on click, while other sessions can be revoked individually.
11
+ *
12
+ * @returns A JSX element containing the sessions card
13
+ */
14
+ export function Sessions({ className, ...props }) {
15
+ const { basePaths, localization, viewPaths, navigate } = useAuth();
16
+ const { data: sessionData } = useSession();
17
+ const { data: sessions, isPending } = useListSessions();
18
+ const { revokingSession, revokeSession } = useRevokeSession();
19
+ 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.sessions }) }), _jsx(Card.Content, { className: "gap-3", children: isPending ? (_jsx(SessionRowSkeleton, {})) : (sessions
20
+ ?.toSorted((session) => session.id === sessionData?.session.id ? -1 : 1)
21
+ .map((session) => {
22
+ const isCurrentSession = session.token === sessionData?.session.token;
23
+ const isRevoking = revokingSession === session.token;
24
+ const ua = new UAParser(session.userAgent || "").getResult();
25
+ const isMobile = ua.device.type === "mobile" ||
26
+ ua.device.type === "tablet" ||
27
+ ua.device.type === "wearable";
28
+ return (_jsxs(Card, { className: "flex-row border items-center p-3 shadow-none", children: [_jsx("div", { className: "flex size-10 items-center justify-center rounded-xl bg-surface-secondary", children: isMobile ? (_jsx(Smartphone, { className: "size-5" })) : (_jsx(Display, { className: "size-5" })) }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs("span", { className: "text-sm font-medium truncate", children: [ua.browser.name || "Unknown Browser", ua.os.name ? `, ${ua.os.name}` : ""] }), isCurrentSession && (_jsx(Chip, { color: "accent", size: "sm", className: "px-1.5", children: localization.settings.currentSession }))] }), _jsxs("div", { className: "flex items-center gap-1.5 text-xs text-muted", children: [session.ipAddress && _jsx("span", { children: session.ipAddress }), session.createdAt && (_jsxs(_Fragment, { children: [session.ipAddress && _jsx("span", { children: "\u2022" }), _jsx("span", { children: session.createdAt.toLocaleString([], {
29
+ dateStyle: "short",
30
+ timeStyle: "short"
31
+ }) })] }))] })] }), _jsx(Button, { isIconOnly: true, className: "ml-auto", variant: "ghost", size: "sm", onPress: () => isCurrentSession
32
+ ? navigate({
33
+ to: `${basePaths.auth}/${viewPaths.auth.signOut}`
34
+ })
35
+ : revokeSession(session.token), isPending: !!revokingSession, "aria-label": localization.settings.revokeSession, children: isRevoking ? (_jsx(Spinner, { color: "current", size: "sm" })) : (_jsx(ArrowRightFromSquare, {})) })] }, session.id));
36
+ })) })] }));
37
+ }
38
+ function SessionRowSkeleton() {
39
+ return (_jsx("div", { className: "flex items-center rounded-3xl border p-3 justify-between", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Skeleton, { className: "size-10 rounded-xl" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Skeleton, { className: "h-4 w-32 rounded-lg" }), _jsx(Skeleton, { className: "h-3 w-24 rounded-lg" })] })] }) }));
40
+ }
@@ -0,0 +1,5 @@
1
+ import type { AnyAuthConfig } from "@better-auth-ui/react";
2
+ export type AccountSettingsProps = AnyAuthConfig & {
3
+ className?: string;
4
+ };
5
+ export declare function AccountSettings({ className, ...config }: AccountSettingsProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "../../../lib/utils";
3
+ import { UserProfile } from "./user-profile";
4
+ export function AccountSettings({ className, ...config }) {
5
+ return (_jsx("div", { className: cn("w-full flex flex-col gap-4 md:gap-6", className), children: _jsx(UserProfile, { ...config }) }));
6
+ }
@@ -0,0 +1,5 @@
1
+ import { type AnyAuthConfig } from "@better-auth-ui/react";
2
+ export type UserProfileProps = AnyAuthConfig & {
3
+ className?: string;
4
+ };
5
+ export declare function UserProfile({ className, ...config }: UserProfileProps): 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, useUpdateUser } from "@better-auth-ui/react";
3
+ import { CheckIcon, PencilIcon } from "@heroicons/react/24/outline";
4
+ import { Button, Card, Description, FieldError, Fieldset, Form, Input, Label, Skeleton, Spinner, TextField } from "@heroui/react";
5
+ import { UserAvatar } from "../../user/user-avatar";
6
+ export function UserProfile({ className, ...config }) {
7
+ const { authClient, localization } = useAuth(config);
8
+ const { data: sessionData, isPending: isSessionPending } = authClient.useSession();
9
+ const [state, formAction, isPending] = useUpdateUser(config);
10
+ if (isSessionPending) {
11
+ return _jsx(UserProfileSkeleton, {});
12
+ }
13
+ return (_jsx(Card, { className: "p-4 md:p-6", children: _jsx(Form, { action: formAction, children: _jsxs(Fieldset, { className: "w-full gap-4 md:gap-6", children: [_jsx(Fieldset.Legend, { className: "text-xl", children: localization.settings.profile }), _jsx(Description, {}), _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs(Button, { isIconOnly: true, variant: "ghost", className: "p-0 h-auto w-auto rounded-full", children: [_jsx(UserAvatar, { size: "lg" }), _jsx("span", { className: "absolute right-0 bottom-0 size-3.5 rounded-full bg-background ring-2 ring-surface-quaternary flex items-center justify-center", children: _jsx(PencilIcon, { className: "size-2 text-muted" }) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("p", { className: "text-sm font-medium", children: sessionData?.user?.displayUsername ||
14
+ sessionData?.user?.name ||
15
+ sessionData?.user?.email }), (sessionData?.user?.displayUsername ||
16
+ sessionData?.user?.name) && (_jsx("p", { className: "text-muted text-xs leading-none", children: sessionData?.user?.email }))] })] }), _jsx(Fieldset.Group, { children: _jsxs(TextField, { name: "name", defaultValue: sessionData?.user?.name || state.name, isDisabled: isPending, children: [_jsx(Label, { children: localization.auth.name }), _jsx(Input, { placeholder: localization.auth.name }), _jsx(FieldError, {})] }) }), _jsx(Fieldset.Actions, { children: _jsxs(Button, { type: "submit", isPending: isPending, children: [isPending ? (_jsx(Spinner, { color: "current", size: "sm" })) : (_jsx(CheckIcon, { className: "size-4" })), localization.settings.saveChanges] }) })] }) }) }));
17
+ }
18
+ function UserProfileSkeleton() {
19
+ return (_jsxs(Card, { className: "p-4 md:p-6 gap-4 md:gap-6", children: [_jsx(Skeleton, { className: "h-7 w-16 rounded-xl" }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Skeleton, { className: "size-12 rounded-full" }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Skeleton, { className: "h-4 mt-0.5 w-24 rounded-lg" }), _jsx(Skeleton, { className: "h-3 mt-0.5 w-32 rounded-lg" })] })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Skeleton, { className: "h-4 w-12 my-0.5 rounded-lg" }), _jsx(Skeleton, { className: "h-9 w-full rounded-xl" })] }), _jsx(Skeleton, { className: "h-10 md:h-9 w-36 rounded-full mt-1" })] }));
20
+ }
@@ -0,0 +1,24 @@
1
+ import type { SettingsView } from "@better-auth-ui/react/core";
2
+ import { type CardProps } from "@heroui/react";
3
+ import { type ComponentProps } from "react";
4
+ export type SettingsProps = {
5
+ className?: string;
6
+ hideNav?: boolean;
7
+ path?: string;
8
+ variant?: CardProps["variant"];
9
+ /** @remarks `SettingsView` */
10
+ view?: SettingsView;
11
+ };
12
+ /**
13
+ * Renders the settings UI and activates the appropriate settings view based on `view` or `path`.
14
+ *
15
+ * @param className - Additional CSS class names applied to the root container
16
+ * @param path - Route path used to resolve which settings view to activate when `view` is not provided
17
+ * @param view - Explicit settings view to activate, e.g. `"account"` or `"security"`
18
+ * @param hideNav - When `true`, hide the navigation tabs
19
+ * @param variant - Card variant forwarded to each settings section card
20
+ * @returns A DOM tree containing the responsive settings tabs and the currently selected settings panel
21
+ *
22
+ * @throws Error if neither `view` nor `path` is provided
23
+ */
24
+ export declare function Settings({ className, hideNav, path, variant, view, ...props }: SettingsProps & ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAuth, useAuthenticate } from "@better-auth-ui/react";
3
+ import { cn, Tabs } from "@heroui/react";
4
+ import { useMemo } from "react";
5
+ import { AccountSettings } from "./account/account-settings";
6
+ import { SecuritySettings } from "./security/security-settings";
7
+ /**
8
+ * Renders the settings UI and activates the appropriate settings view based on `view` or `path`.
9
+ *
10
+ * @param className - Additional CSS class names applied to the root container
11
+ * @param path - Route path used to resolve which settings view to activate when `view` is not provided
12
+ * @param view - Explicit settings view to activate, e.g. `"account"` or `"security"`
13
+ * @param hideNav - When `true`, hide the navigation tabs
14
+ * @param variant - Card variant forwarded to each settings section card
15
+ * @returns A DOM tree containing the responsive settings tabs and the currently selected settings panel
16
+ *
17
+ * @throws Error if neither `view` nor `path` is provided
18
+ */
19
+ export function Settings({ className, hideNav, path, variant, view, ...props }) {
20
+ const { basePaths, localization, viewPaths } = useAuth();
21
+ useAuthenticate();
22
+ if (!view && !path) {
23
+ throw new Error("[Better Auth UI] Either `view` or `path` must be provided");
24
+ }
25
+ const settingsPathViews = useMemo(() => Object.fromEntries(Object.entries(viewPaths.settings).map(([k, v]) => [v, k])), [viewPaths.settings]);
26
+ const currentView = view || (path ? settingsPathViews[path] : undefined);
27
+ return (_jsxs(Tabs, { className: cn(className), orientation: "horizontal", selectedKey: currentView, ...props, children: [_jsx(Tabs.ListContainer, { children: _jsxs(Tabs.List, { "aria-label": localization.settings.settings, className: "overflow-auto w-fit", children: [_jsxs(Tabs.Tab, { id: "account", href: `${basePaths.settings}/${viewPaths.settings.account}`, children: [localization.settings.account, _jsx(Tabs.Indicator, {})] }), _jsxs(Tabs.Tab, { id: "security", href: `${basePaths.settings}/${viewPaths.settings.security}`, children: [localization.settings.security, _jsx(Tabs.Indicator, {})] })] }) }), _jsx(Tabs.Panel, { id: "account", className: "px-0", children: _jsx(AccountSettings, { variant: variant }) }), _jsx(Tabs.Panel, { id: "security", className: "px-0", children: _jsx(SecuritySettings, { variant: variant }) })] }));
28
+ }
@@ -0,0 +1,5 @@
1
+ import { type AnyAuthConfig } from "@better-auth-ui/react";
2
+ export type UserProfileProps = AnyAuthConfig & {
3
+ className?: string;
4
+ };
5
+ export declare function UserProfile({ className, ...config }: UserProfileProps): 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, useUpdateUser } from "@better-auth-ui/react";
3
+ import { CheckIcon, PencilIcon } from "@heroicons/react/24/outline";
4
+ import { Button, Card, Description, FieldError, Fieldset, Form, Input, Label, Skeleton, Spinner, TextField } from "@heroui/react";
5
+ import { UserAvatar } from "../user/user-avatar";
6
+ export function UserProfile({ className, ...config }) {
7
+ const { authClient, localization } = useAuth(config);
8
+ const { data: sessionData, isPending: isSessionPending } = authClient.useSession();
9
+ const [state, formAction, isPending] = useUpdateUser(config);
10
+ if (isSessionPending) {
11
+ return _jsx(UserProfileSkeleton, {});
12
+ }
13
+ return (_jsx(Card, { className: "p-4 md:p-6", children: _jsx(Form, { action: formAction, children: _jsxs(Fieldset, { className: "w-full gap-4 md:gap-6", children: [_jsx(Fieldset.Legend, { className: "text-xl", children: localization.settings.profile }), _jsx(Description, {}), _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs(Button, { type: "button", isIconOnly: true, variant: "ghost", className: "p-0 h-auto w-auto rounded-full", children: [_jsx(UserAvatar, { ...config, size: "lg" }), _jsx("span", { className: "absolute right-0 bottom-0 size-3.5 rounded-full bg-background ring-2 ring-surface-quaternary flex items-center justify-center", children: _jsx(PencilIcon, { className: "size-2 text-muted" }) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("p", { className: "text-sm font-medium", children: sessionData?.user?.displayUsername ||
14
+ sessionData?.user?.name ||
15
+ sessionData?.user?.email }), (sessionData?.user?.displayUsername ||
16
+ sessionData?.user?.name) && (_jsx("p", { className: "text-muted text-xs leading-none", children: sessionData?.user?.email }))] })] }), _jsx(Fieldset.Group, { children: _jsxs(TextField, { name: "name", defaultValue: sessionData?.user?.name || state.name, isDisabled: isPending, children: [_jsx(Label, { children: localization.auth.name }), _jsx(Input, { placeholder: localization.auth.name }), _jsx(FieldError, {})] }) }), _jsx(Fieldset.Actions, { children: _jsxs(Button, { type: "submit", isPending: isPending, children: [isPending ? (_jsx(Spinner, { color: "current", size: "sm" })) : (_jsx(CheckIcon, { className: "size-4" })), localization.settings.saveChanges] }) })] }) }) }));
17
+ }
18
+ function UserProfileSkeleton() {
19
+ return (_jsxs(Card, { className: "p-4 md:p-6 gap-4 md:gap-6", children: [_jsx(Skeleton, { className: "h-7 w-16 rounded-xl" }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Skeleton, { className: "size-12 rounded-full" }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Skeleton, { className: "h-4 mt-0.5 w-24 rounded-lg" }), _jsx(Skeleton, { className: "h-3 mt-0.5 w-32 rounded-lg" })] })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Skeleton, { className: "h-4 w-12 my-0.5 rounded-lg" }), _jsx(Skeleton, { className: "h-9 w-full rounded-xl" })] }), _jsx(Skeleton, { className: "h-10 md:h-9 w-36 rounded-full mt-1" })] }));
20
+ }
@@ -0,0 +1,16 @@
1
+ import type { Session, User } from "better-auth";
2
+ type DeviceSession = {
3
+ session: Session;
4
+ user: User;
5
+ };
6
+ export type SwitchAccountItemProps = {
7
+ deviceSession: DeviceSession;
8
+ };
9
+ /**
10
+ * Render a dropdown item for switching to a different authenticated session.
11
+ *
12
+ * @param deviceSession - The device session to display and switch to when pressed
13
+ * @returns The switch account dropdown item as a JSX element
14
+ */
15
+ export declare function SwitchAccountItem({ deviceSession }: SwitchAccountItemProps): import("react/jsx-runtime").JSX.Element;
16
+ export {};
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useSetActiveSession } from "@better-auth-ui/react";
3
+ import { Dropdown, Spinner, toast } from "@heroui/react";
4
+ import { UserView } from "./user-view";
5
+ /**
6
+ * Render a dropdown item for switching to a different authenticated session.
7
+ *
8
+ * @param deviceSession - The device session to display and switch to when pressed
9
+ * @returns The switch account dropdown item as a JSX element
10
+ */
11
+ export function SwitchAccountItem({ deviceSession }) {
12
+ const { mutate: setActiveSession, isPending } = useSetActiveSession({
13
+ onError: (error) => toast.danger(error.error?.message || error.message)
14
+ });
15
+ return (_jsxs(Dropdown.Item, { className: "px-2", isDisabled: isPending, onPress: () => setActiveSession({ sessionToken: deviceSession.session.token }), children: [_jsx(UserView, { user: deviceSession.user }), isPending && _jsx(Spinner, { color: "current", size: "sm", className: "ml-auto" })] }));
16
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Render the menu content for switching between multiple authenticated sessions.
3
+ *
4
+ * Shows the current session with a checkmark, lists other device sessions that can be activated,
5
+ * and provides an option to add a new account. This component should be rendered inside a
6
+ * Dropdown.SubmenuTrigger to defer the useListDeviceSessions query until the submenu is opened.
7
+ *
8
+ * @returns The switch account menu content as a JSX element
9
+ */
10
+ export declare function SwitchAccountMenu(): 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, useListDeviceSessions, useSession } from "@better-auth-ui/react";
3
+ import { Check, CirclePlus } from "@gravity-ui/icons";
4
+ import { Dropdown, Label, Separator, toast } from "@heroui/react";
5
+ import { SwitchAccountItem } from "./switch-account-item";
6
+ import { UserView } from "./user-view";
7
+ /**
8
+ * Render the menu content for switching between multiple authenticated sessions.
9
+ *
10
+ * Shows the current session with a checkmark, lists other device sessions that can be activated,
11
+ * and provides an option to add a new account. This component should be rendered inside a
12
+ * Dropdown.SubmenuTrigger to defer the useListDeviceSessions query until the submenu is opened.
13
+ *
14
+ * @returns The switch account menu content as a JSX element
15
+ */
16
+ export function SwitchAccountMenu() {
17
+ const { basePaths, viewPaths, localization } = useAuth();
18
+ const { data: session } = useSession();
19
+ const { data: deviceSessions, isPending } = useListDeviceSessions({
20
+ throwOnError: (error) => {
21
+ if (error.error)
22
+ toast.danger(error.error.message);
23
+ return false;
24
+ }
25
+ });
26
+ return (_jsx(Dropdown.Popover, { className: "min-w-40 md:min-w-56 max-w-[48svw]", children: _jsxs(Dropdown.Menu, { children: [_jsxs(Dropdown.Item, { className: "px-2", children: [_jsx(UserView, { isPending: isPending }), !isPending && _jsx(Check, { className: "ml-auto" })] }), deviceSessions
27
+ ?.filter((deviceSession) => deviceSession.session.id !== session?.session?.id)
28
+ .map((deviceSession) => (_jsx(SwitchAccountItem, { deviceSession: deviceSession }, deviceSession.session.id))), _jsx(Separator, {}), _jsxs(Dropdown.Item, { textValue: localization.auth.addAccount, href: `${basePaths.auth}/${viewPaths.auth.signIn}`, children: [_jsx(CirclePlus, { className: "text-muted" }), _jsx(Label, { children: localization.auth.addAccount })] })] }) }));
29
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Render the popover content for switching between multiple authenticated sessions.
3
+ *
4
+ * Shows the current session with a checkmark, lists other device sessions that can be activated,
5
+ * and provides an option to add a new account. This component should be rendered inside a
6
+ * Dropdown.SubmenuTrigger to defer the useListDeviceSessions query until the submenu is opened.
7
+ *
8
+ * @returns The switch account popover content as a JSX element
9
+ */
10
+ export declare function SwitchAccountPopover(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAuth, useListDeviceSessions, useSession, useSetActiveSession } from "@better-auth-ui/react";
3
+ import { Check, CirclePlus } from "@gravity-ui/icons";
4
+ import { Dropdown, Label, Separator } from "@heroui/react";
5
+ import { UserView } from "./user-view";
6
+ /**
7
+ * Render the popover content for switching between multiple authenticated sessions.
8
+ *
9
+ * Shows the current session with a checkmark, lists other device sessions that can be activated,
10
+ * and provides an option to add a new account. This component should be rendered inside a
11
+ * Dropdown.SubmenuTrigger to defer the useListDeviceSessions query until the submenu is opened.
12
+ *
13
+ * @returns The switch account popover content as a JSX element
14
+ */
15
+ export function SwitchAccountPopover() {
16
+ const { basePaths, viewPaths, localization } = useAuth();
17
+ const { settingActiveSession, setActiveSession } = useSetActiveSession();
18
+ const { data: sessionData } = useSession();
19
+ const { data: deviceSessions } = useListDeviceSessions();
20
+ return (_jsxs(Dropdown.Menu, { children: [_jsxs(Dropdown.Item, { className: "px-2", children: [_jsx(UserView, {}), _jsx(Check, { className: "ml-auto" })] }), deviceSessions
21
+ ?.filter((deviceSession) => deviceSession.session.id !== sessionData?.session?.id)
22
+ .map((deviceSession) => {
23
+ return (_jsx(Dropdown.Item, { className: "px-2", isDisabled: !!settingActiveSession, onPress: () => setActiveSession(deviceSession.session.token), children: _jsx(UserView, { user: deviceSession.user }) }, deviceSession.session.id));
24
+ }), _jsx(Separator, {}), _jsxs(Dropdown.Item, { textValue: localization.auth.addAccount, href: `${basePaths.auth}/${viewPaths.auth.signIn}`, children: [_jsx(CirclePlus, { className: "text-muted" }), _jsx(Label, { children: localization.auth.addAccount })] })] }));
25
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Render the popover content for switching between multiple authenticated sessions.
3
+ *
4
+ * Shows the current session with a checkmark, lists other device sessions that can be activated,
5
+ * and provides an option to add a new account. This component should be rendered inside a
6
+ * Dropdown.SubmenuTrigger to defer the useListDeviceSessions query until the submenu is opened.
7
+ *
8
+ * @returns The switch account submenu popover content as a JSX element
9
+ */
10
+ export declare function SwitchAccountSubmenu(): import("react/jsx-runtime").JSX.Element;