@better-auth-ui/heroui 1.6.8 → 1.6.9

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 (270) hide show
  1. package/dist/components/auth/additional-field.d.ts +2 -2
  2. package/dist/components/auth/additional-field.js +133 -266
  3. package/dist/components/auth/api-key/api-key-skeleton.js +4 -20
  4. package/dist/components/auth/api-key/api-key.d.ts +6 -2
  5. package/dist/components/auth/api-key/api-key.js +16 -54
  6. package/dist/components/auth/api-key/api-keys-empty.d.ts +3 -1
  7. package/dist/components/auth/api-key/api-keys-empty.js +8 -34
  8. package/dist/components/auth/api-key/api-keys.d.ts +10 -2
  9. package/dist/components/auth/api-key/api-keys.js +21 -40
  10. package/dist/components/auth/api-key/create-api-key-dialog.d.ts +3 -1
  11. package/dist/components/auth/api-key/create-api-key-dialog.js +43 -73
  12. package/dist/components/auth/api-key/delete-api-key-dialog.d.ts +4 -2
  13. package/dist/components/auth/api-key/delete-api-key-dialog.js +16 -50
  14. package/dist/components/auth/api-key/new-api-key-dialog.js +23 -59
  15. package/dist/components/auth/api-key/organization-api-keys.d.ts +14 -0
  16. package/dist/components/auth/api-key/organization-api-keys.js +22 -0
  17. package/dist/components/auth/auth-provider.d.ts +1 -1
  18. package/dist/components/auth/auth-provider.js +10 -16
  19. package/dist/components/auth/auth.d.ts +3 -3
  20. package/dist/components/auth/auth.js +86 -61
  21. package/dist/components/auth/delete-user/danger-zone.d.ts +3 -3
  22. package/dist/components/auth/delete-user/danger-zone.js +11 -17
  23. package/dist/components/auth/delete-user/delete-account.d.ts +9 -0
  24. package/dist/components/auth/delete-user/delete-account.js +50 -0
  25. package/dist/components/auth/email/email-changed-email.d.ts +2 -2
  26. package/dist/components/auth/email/email-changed-email.js +22 -29
  27. package/dist/components/auth/email/email-verification-email.d.ts +2 -2
  28. package/dist/components/auth/email/email-verification-email.js +22 -29
  29. package/dist/components/auth/email/magic-link-email.d.ts +2 -2
  30. package/dist/components/auth/email/magic-link-email.js +22 -29
  31. package/dist/components/auth/email/new-device-email.d.ts +2 -2
  32. package/dist/components/auth/email/new-device-email.js +22 -29
  33. package/dist/components/auth/email/organization-invitation-email.d.ts +3 -0
  34. package/dist/components/auth/email/organization-invitation-email.js +23 -0
  35. package/dist/components/auth/email/otp-email.d.ts +2 -2
  36. package/dist/components/auth/email/otp-email.js +21 -28
  37. package/dist/components/auth/email/password-changed-email.d.ts +2 -2
  38. package/dist/components/auth/email/password-changed-email.js +22 -29
  39. package/dist/components/auth/email/reset-password-email.d.ts +2 -2
  40. package/dist/components/auth/email/reset-password-email.js +22 -29
  41. package/dist/components/auth/error-toaster.js +32 -16
  42. package/dist/components/auth/field-separator.d.ts +1 -1
  43. package/dist/components/auth/field-separator.js +4 -17
  44. package/dist/components/auth/forgot-password.d.ts +1 -1
  45. package/dist/components/auth/forgot-password.js +36 -88
  46. package/dist/components/auth/magic-link/magic-link-button.d.ts +1 -1
  47. package/dist/components/auth/magic-link/magic-link-button.js +33 -19
  48. package/dist/components/auth/magic-link/magic-link.d.ts +2 -2
  49. package/dist/components/auth/magic-link/magic-link.js +39 -86
  50. package/dist/components/auth/multi-session/manage-account.d.ts +1 -1
  51. package/dist/components/auth/multi-session/manage-account.js +32 -48
  52. package/dist/components/auth/multi-session/manage-accounts.d.ts +1 -1
  53. package/dist/components/auth/multi-session/manage-accounts.js +32 -33
  54. package/dist/components/auth/multi-session/switch-account-submenu-content.d.ts +3 -1
  55. package/dist/components/auth/multi-session/switch-account-submenu-content.js +24 -27
  56. package/dist/components/auth/multi-session/switch-account-submenu-item.d.ts +3 -2
  57. package/dist/components/auth/multi-session/switch-account-submenu-item.js +16 -19
  58. package/dist/components/auth/multi-session/switch-account-submenu.d.ts +2 -1
  59. package/dist/components/auth/multi-session/switch-account-submenu.js +23 -23
  60. package/dist/components/auth/organization/change-organization-logo.d.ts +4 -0
  61. package/dist/components/auth/organization/change-organization-logo.js +69 -0
  62. package/dist/components/auth/organization/create-organization-dialog.d.ts +13 -0
  63. package/dist/components/auth/organization/create-organization-dialog.js +37 -0
  64. package/dist/components/auth/organization/delete-organization-dialog.d.ts +7 -0
  65. package/dist/components/auth/organization/delete-organization-dialog.js +25 -0
  66. package/dist/components/auth/organization/delete-organization-skeleton.d.ts +4 -0
  67. package/dist/components/auth/organization/delete-organization-skeleton.js +8 -0
  68. package/dist/components/auth/organization/delete-organization.d.ts +5 -0
  69. package/dist/components/auth/organization/delete-organization.js +27 -0
  70. package/dist/components/auth/organization/invite-member-dialog.d.ts +13 -0
  71. package/dist/components/auth/organization/invite-member-dialog.js +47 -0
  72. package/dist/components/auth/organization/leave-organization-dialog.d.ts +7 -0
  73. package/dist/components/auth/organization/leave-organization-dialog.js +21 -0
  74. package/dist/components/auth/organization/leave-organization.d.ts +4 -0
  75. package/dist/components/auth/organization/leave-organization.js +16 -0
  76. package/dist/components/auth/organization/organization-danger-zone.d.ts +16 -0
  77. package/dist/components/auth/organization/organization-danger-zone.js +23 -0
  78. package/dist/components/auth/organization/organization-invitation-row-skeleton.d.ts +5 -0
  79. package/dist/components/auth/organization/organization-invitation-row-skeleton.js +9 -0
  80. package/dist/components/auth/organization/organization-invitation-row.d.ts +5 -0
  81. package/dist/components/auth/organization/organization-invitation-row.js +31 -0
  82. package/dist/components/auth/organization/organization-invitations-empty.d.ts +8 -0
  83. package/dist/components/auth/organization/organization-invitations-empty.js +13 -0
  84. package/dist/components/auth/organization/organization-invitations.d.ts +9 -0
  85. package/dist/components/auth/organization/organization-invitations.js +66 -0
  86. package/dist/components/auth/organization/organization-logo.d.ts +15 -0
  87. package/dist/components/auth/organization/organization-logo.js +14 -0
  88. package/dist/components/auth/organization/organization-member-row-skeleton.d.ts +4 -0
  89. package/dist/components/auth/organization/organization-member-row-skeleton.js +9 -0
  90. package/dist/components/auth/organization/organization-member-row.d.ts +9 -0
  91. package/dist/components/auth/organization/organization-member-row.js +34 -0
  92. package/dist/components/auth/organization/organization-members.d.ts +9 -0
  93. package/dist/components/auth/organization/organization-members.js +67 -0
  94. package/dist/components/auth/organization/organization-people.d.ts +10 -0
  95. package/dist/components/auth/organization/organization-people.js +11 -0
  96. package/dist/components/auth/organization/organization-profile.d.ts +9 -0
  97. package/dist/components/auth/organization/organization-profile.js +34 -0
  98. package/dist/components/auth/organization/organization-row.d.ts +8 -0
  99. package/dist/components/auth/organization/organization-row.js +31 -0
  100. package/dist/components/auth/organization/organization-settings.d.ts +12 -0
  101. package/dist/components/auth/organization/organization-settings.js +13 -0
  102. package/dist/components/auth/organization/organization-switcher.d.ts +20 -0
  103. package/dist/components/auth/organization/organization-switcher.js +48 -0
  104. package/dist/components/auth/organization/organization-view-skeleton.d.ts +6 -0
  105. package/dist/components/auth/organization/organization-view-skeleton.js +9 -0
  106. package/dist/components/auth/organization/organization-view.d.ts +15 -0
  107. package/dist/components/auth/organization/organization-view.js +31 -0
  108. package/dist/components/auth/organization/organization.d.ts +17 -0
  109. package/dist/components/auth/organization/organization.js +60 -0
  110. package/dist/components/auth/organization/organizations-empty.d.ts +4 -0
  111. package/dist/components/auth/organization/organizations-empty.js +9 -0
  112. package/dist/components/auth/organization/organizations-settings.d.ts +17 -0
  113. package/dist/components/auth/organization/organizations-settings.js +17 -0
  114. package/dist/components/auth/organization/organizations.d.ts +10 -0
  115. package/dist/components/auth/organization/organizations.js +21 -0
  116. package/dist/components/auth/organization/remove-member-dialog.d.ts +9 -0
  117. package/dist/components/auth/organization/remove-member-dialog.js +20 -0
  118. package/dist/components/auth/organization/slug-field.d.ts +19 -0
  119. package/dist/components/auth/organization/slug-field.js +38 -0
  120. package/dist/components/auth/organization/user-invitation-row-skeleton.d.ts +4 -0
  121. package/dist/components/auth/organization/user-invitation-row-skeleton.js +8 -0
  122. package/dist/components/auth/organization/user-invitation-row.d.ts +10 -0
  123. package/dist/components/auth/organization/user-invitation-row.js +22 -0
  124. package/dist/components/auth/organization/user-invitations-empty.d.ts +4 -0
  125. package/dist/components/auth/organization/user-invitations-empty.js +12 -0
  126. package/dist/components/auth/organization/user-invitations.d.ts +10 -0
  127. package/dist/components/auth/organization/user-invitations.js +18 -0
  128. package/dist/components/auth/passkey/add-passkey-dialog.js +21 -64
  129. package/dist/components/auth/passkey/delete-passkey-dialog.js +13 -46
  130. package/dist/components/auth/passkey/passkey-button.d.ts +1 -1
  131. package/dist/components/auth/passkey/passkey-button.js +24 -23
  132. package/dist/components/auth/passkey/passkey-skeleton.js +4 -16
  133. package/dist/components/auth/passkey/passkey.d.ts +1 -1
  134. package/dist/components/auth/passkey/passkey.js +16 -47
  135. package/dist/components/auth/passkey/passkeys-empty.js +8 -34
  136. package/dist/components/auth/passkey/passkeys.d.ts +1 -1
  137. package/dist/components/auth/passkey/passkeys.js +15 -41
  138. package/dist/components/auth/provider-button.d.ts +2 -2
  139. package/dist/components/auth/provider-button.js +28 -24
  140. package/dist/components/auth/provider-buttons.js +28 -18
  141. package/dist/components/auth/reset-password.d.ts +1 -1
  142. package/dist/components/auth/reset-password.js +56 -146
  143. package/dist/components/auth/settings/account/account-settings.d.ts +2 -2
  144. package/dist/components/auth/settings/account/account-settings.js +21 -19
  145. package/dist/components/auth/settings/account/change-avatar.js +53 -88
  146. package/dist/components/auth/settings/account/change-email.d.ts +1 -1
  147. package/dist/components/auth/settings/account/change-email.js +27 -53
  148. package/dist/components/auth/settings/account/user-profile.d.ts +1 -1
  149. package/dist/components/auth/settings/account/user-profile.js +64 -85
  150. package/dist/components/auth/settings/security/active-session.d.ts +1 -1
  151. package/dist/components/auth/settings/security/active-session.js +50 -57
  152. package/dist/components/auth/settings/security/active-sessions.d.ts +1 -1
  153. package/dist/components/auth/settings/security/active-sessions.js +21 -32
  154. package/dist/components/auth/settings/security/change-password.d.ts +1 -1
  155. package/dist/components/auth/settings/security/change-password.js +76 -186
  156. package/dist/components/auth/settings/security/linked-account.d.ts +1 -1
  157. package/dist/components/auth/settings/security/linked-account.js +37 -55
  158. package/dist/components/auth/settings/security/linked-accounts.d.ts +1 -1
  159. package/dist/components/auth/settings/security/linked-accounts.js +34 -43
  160. package/dist/components/auth/settings/security/security-settings.d.ts +2 -2
  161. package/dist/components/auth/settings/security/security-settings.js +19 -21
  162. package/dist/components/auth/settings/settings.d.ts +4 -4
  163. package/dist/components/auth/settings/settings.js +52 -44
  164. package/dist/components/auth/sign-in.d.ts +2 -2
  165. package/dist/components/auth/sign-in.js +63 -132
  166. package/dist/components/auth/sign-out.js +32 -26
  167. package/dist/components/auth/sign-up.d.ts +2 -2
  168. package/dist/components/auth/sign-up.js +97 -211
  169. package/dist/components/auth/theme/appearance.d.ts +1 -1
  170. package/dist/components/auth/theme/appearance.js +23 -71
  171. package/dist/components/auth/theme/theme-toggle-item.js +56 -61
  172. package/dist/components/auth/user/user-avatar.d.ts +4 -4
  173. package/dist/components/auth/user/user-avatar.js +31 -28
  174. package/dist/components/auth/user/user-button.d.ts +6 -7
  175. package/dist/components/auth/user/user-button.js +38 -72
  176. package/dist/components/auth/user/user-view.d.ts +13 -7
  177. package/dist/components/auth/user/user-view.js +26 -36
  178. package/dist/components/auth/username/sign-in-username.d.ts +2 -2
  179. package/dist/components/auth/username/sign-in-username.js +87 -147
  180. package/dist/components/auth/username/username-field.d.ts +1 -1
  181. package/dist/components/auth/username/username-field.js +44 -52
  182. package/dist/email.d.ts +8 -7
  183. package/dist/email.js +8 -8
  184. package/dist/index.d.ts +21 -21
  185. package/dist/index.js +21 -22
  186. package/dist/lib/auth/api-key-plugin.d.ts +7 -4
  187. package/dist/lib/auth/api-key-plugin.js +12 -10
  188. package/dist/lib/auth/auth-plugin.d.ts +10 -6
  189. package/dist/lib/auth/auth-plugin.js +1 -0
  190. package/dist/lib/auth/delete-user-plugin.d.ts +6 -6
  191. package/dist/lib/auth/delete-user-plugin.js +6 -9
  192. package/dist/lib/auth/magic-link-plugin.d.ts +5 -5
  193. package/dist/lib/auth/magic-link-plugin.js +17 -12
  194. package/dist/lib/auth/multi-session-plugin.d.ts +5 -5
  195. package/dist/lib/auth/multi-session-plugin.js +8 -11
  196. package/dist/lib/auth/organization-plugin.d.ts +37 -0
  197. package/dist/lib/auth/organization-plugin.js +19 -0
  198. package/dist/lib/auth/passkey-plugin.d.ts +5 -5
  199. package/dist/lib/auth/passkey-plugin.js +8 -11
  200. package/dist/lib/auth/theme-plugin.d.ts +6 -6
  201. package/dist/lib/auth/theme-plugin.js +25 -22
  202. package/dist/lib/auth/username-plugin.d.ts +11 -11
  203. package/dist/lib/auth/username-plugin.js +18 -17
  204. package/dist/plugins.d.ts +46 -22
  205. package/dist/plugins.js +47 -22
  206. package/package.json +25 -19
  207. package/src/components/auth/api-key/api-key.tsx +25 -16
  208. package/src/components/auth/api-key/api-keys-empty.tsx +8 -4
  209. package/src/components/auth/api-key/api-keys.tsx +52 -14
  210. package/src/components/auth/api-key/create-api-key-dialog.tsx +15 -2
  211. package/src/components/auth/api-key/delete-api-key-dialog.tsx +10 -2
  212. package/src/components/auth/api-key/organization-api-keys.tsx +55 -0
  213. package/src/components/auth/delete-user/danger-zone.tsx +3 -3
  214. package/src/components/auth/delete-user/{delete-user.tsx → delete-account.tsx} +9 -9
  215. package/src/components/auth/email/organization-invitation-email.tsx +38 -0
  216. package/src/components/auth/error-toaster.tsx +28 -10
  217. package/src/components/auth/forgot-password.tsx +10 -2
  218. package/src/components/auth/multi-session/manage-accounts.tsx +1 -1
  219. package/src/components/auth/multi-session/switch-account-submenu-content.tsx +7 -2
  220. package/src/components/auth/multi-session/switch-account-submenu-item.tsx +4 -2
  221. package/src/components/auth/multi-session/switch-account-submenu.tsx +8 -4
  222. package/src/components/auth/organization/change-organization-logo.tsx +171 -0
  223. package/src/components/auth/organization/create-organization-dialog.tsx +133 -0
  224. package/src/components/auth/organization/delete-organization-dialog.tsx +97 -0
  225. package/src/components/auth/organization/delete-organization-skeleton.tsx +17 -0
  226. package/src/components/auth/organization/delete-organization.tsx +77 -0
  227. package/src/components/auth/organization/invite-member-dialog.tsx +177 -0
  228. package/src/components/auth/organization/leave-organization-dialog.tsx +95 -0
  229. package/src/components/auth/organization/leave-organization.tsx +59 -0
  230. package/src/components/auth/organization/organization-danger-zone.tsx +68 -0
  231. package/src/components/auth/organization/organization-invitation-row-skeleton.tsx +29 -0
  232. package/src/components/auth/organization/organization-invitation-row.tsx +97 -0
  233. package/src/components/auth/organization/organization-invitations-empty.tsx +39 -0
  234. package/src/components/auth/organization/organization-invitations.tsx +351 -0
  235. package/src/components/auth/organization/organization-logo.tsx +64 -0
  236. package/src/components/auth/organization/organization-member-row-skeleton.tsx +24 -0
  237. package/src/components/auth/organization/organization-member-row.tsx +157 -0
  238. package/src/components/auth/organization/organization-members.tsx +284 -0
  239. package/src/components/auth/organization/organization-people.tsx +26 -0
  240. package/src/components/auth/organization/organization-profile.tsx +141 -0
  241. package/src/components/auth/organization/organization-row.tsx +66 -0
  242. package/src/components/auth/organization/organization-settings.tsx +38 -0
  243. package/src/components/auth/organization/organization-switcher.tsx +233 -0
  244. package/src/components/auth/organization/organization-view-skeleton.tsx +36 -0
  245. package/src/components/auth/organization/organization-view.tsx +109 -0
  246. package/src/components/auth/organization/organization.tsx +162 -0
  247. package/src/components/auth/organization/organizations-empty.tsx +35 -0
  248. package/src/components/auth/organization/organizations-settings.tsx +36 -0
  249. package/src/components/auth/organization/organizations.tsx +80 -0
  250. package/src/components/auth/organization/remove-member-dialog.tsx +95 -0
  251. package/src/components/auth/organization/slug-field.tsx +111 -0
  252. package/src/components/auth/organization/user-invitation-row-skeleton.tsx +17 -0
  253. package/src/components/auth/organization/user-invitation-row.tsx +90 -0
  254. package/src/components/auth/organization/user-invitations-empty.tsx +30 -0
  255. package/src/components/auth/organization/user-invitations.tsx +59 -0
  256. package/src/components/auth/settings/account/change-email.tsx +1 -1
  257. package/src/components/auth/settings/account/user-profile.tsx +5 -5
  258. package/src/components/auth/settings/security/active-sessions.tsx +6 -4
  259. package/src/components/auth/settings/security/linked-accounts.tsx +2 -2
  260. package/src/components/auth/settings/settings.tsx +77 -14
  261. package/src/components/auth/user/user-avatar.tsx +4 -1
  262. package/src/components/auth/user/user-button.tsx +14 -11
  263. package/src/components/auth/user/user-view.tsx +32 -12
  264. package/src/email.ts +1 -0
  265. package/src/lib/auth/api-key-plugin.ts +10 -4
  266. package/src/lib/auth/auth-plugin.ts +6 -1
  267. package/src/lib/auth/organization-plugin.tsx +32 -0
  268. package/src/plugins.ts +25 -1
  269. package/dist/components/auth/delete-user/delete-user.d.ts +0 -9
  270. package/dist/components/auth/delete-user/delete-user.js +0 -95
@@ -1,8 +1,8 @@
1
1
  import type { SettingsView } from "@better-auth-ui/core"
2
2
  import { useAuth, useAuthenticate } from "@better-auth-ui/react"
3
+ import { Person, Shield } from "@gravity-ui/icons"
3
4
  import { type CardProps, cn, Tabs } from "@heroui/react"
4
5
  import { type ComponentProps, useMemo } from "react"
5
-
6
6
  import { AccountSettings } from "./account/account-settings"
7
7
  import { SecuritySettings } from "./security/security-settings"
8
8
 
@@ -25,7 +25,7 @@ export type SettingsProps = {
25
25
  * @param variant - Card variant forwarded to each settings section card
26
26
  * @returns A DOM tree containing the responsive settings tabs and the currently selected settings panel
27
27
  *
28
- * @throws Error if neither `view` nor `path` is provided
28
+ * @throws Error if neither `view` nor `path` is provided, or if `path` does not match any settings view
29
29
  */
30
30
  export function Settings({
31
31
  className,
@@ -35,22 +35,39 @@ export function Settings({
35
35
  view,
36
36
  ...props
37
37
  }: SettingsProps & ComponentProps<"div">) {
38
- const { authClient, basePaths, localization, viewPaths } = useAuth()
39
- useAuthenticate(authClient)
40
-
41
38
  if (!view && !path) {
42
39
  throw new Error("[Better Auth UI] Either `view` or `path` must be provided")
43
40
  }
44
41
 
45
- const settingsPathViews = useMemo(
46
- () =>
47
- Object.fromEntries(
48
- Object.entries(viewPaths.settings).map(([k, v]) => [v, k])
49
- ) as Record<string, SettingsView>,
50
- [viewPaths.settings]
51
- )
42
+ const { authClient, basePaths, localization, viewPaths, plugins } = useAuth()
43
+ useAuthenticate(authClient)
44
+
45
+ // Built-ins first, then plugin segments
46
+ const currentView = useMemo(() => {
47
+ if (view) return view
48
+ if (!path) return undefined
52
49
 
53
- const currentView = view || (path ? settingsPathViews[path] : undefined)
50
+ const match = [
51
+ viewPaths.settings,
52
+ ...plugins.map((plugin) => plugin.viewPaths?.settings)
53
+ ]
54
+ .flatMap((source) => Object.entries(source ?? {}))
55
+ .find(([, segment]) => segment === path)
56
+
57
+ return match?.[0] as SettingsView | undefined
58
+ }, [view, path, viewPaths.settings, plugins])
59
+
60
+ if (!currentView) {
61
+ const validPaths = [
62
+ viewPaths.settings,
63
+ ...plugins.map((plugin) => plugin.viewPaths?.settings)
64
+ ]
65
+ .flatMap((source) => Object.values(source ?? {}))
66
+ .join(", ")
67
+ throw new Error(
68
+ `[Better Auth UI] Unknown settings path "${path}". Valid paths are: ${validPaths}`
69
+ )
70
+ }
54
71
 
55
72
  return (
56
73
  <Tabs
@@ -62,12 +79,18 @@ export function Settings({
62
79
  <Tabs.ListContainer>
63
80
  <Tabs.List
64
81
  aria-label={localization.settings.settings}
65
- className="overflow-auto w-fit"
82
+ className="max-w-fit overflow-x-auto [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden"
66
83
  >
67
84
  <Tabs.Tab
68
85
  id="account"
69
86
  href={`${basePaths.settings}/${viewPaths.settings.account}`}
87
+ className="gap-2"
88
+ onPress={(e) =>
89
+ e.target.scrollIntoView({ behavior: "smooth", inline: "center" })
90
+ }
70
91
  >
92
+ <Person className="text-muted" />
93
+
71
94
  {localization.settings.account}
72
95
 
73
96
  <Tabs.Indicator />
@@ -76,11 +99,39 @@ export function Settings({
76
99
  <Tabs.Tab
77
100
  id="security"
78
101
  href={`${basePaths.settings}/${viewPaths.settings.security}`}
102
+ className="gap-2"
103
+ onPress={(e) =>
104
+ e.target.scrollIntoView({ behavior: "smooth", inline: "center" })
105
+ }
79
106
  >
107
+ <Shield className="text-muted" />
108
+
80
109
  {localization.settings.security}
81
110
 
82
111
  <Tabs.Indicator />
83
112
  </Tabs.Tab>
113
+
114
+ {plugins.flatMap(
115
+ (plugin) =>
116
+ plugin.settingsTabs?.map((settingsTab, index) => (
117
+ <Tabs.Tab
118
+ key={`${plugin.id}-${index.toString()}`}
119
+ id={settingsTab.view}
120
+ href={`${basePaths.settings}/${plugin.viewPaths?.settings?.[settingsTab.view]}`}
121
+ className="gap-2"
122
+ onPress={(e) =>
123
+ e.target.scrollIntoView({
124
+ behavior: "smooth",
125
+ inline: "center"
126
+ })
127
+ }
128
+ >
129
+ {settingsTab.label}
130
+
131
+ <Tabs.Indicator />
132
+ </Tabs.Tab>
133
+ )) ?? []
134
+ )}
84
135
  </Tabs.List>
85
136
  </Tabs.ListContainer>
86
137
 
@@ -91,6 +142,18 @@ export function Settings({
91
142
  <Tabs.Panel id="security" className="px-0">
92
143
  <SecuritySettings variant={variant} />
93
144
  </Tabs.Panel>
145
+
146
+ {plugins.flatMap((plugin) =>
147
+ plugin.settingsTabs?.map((settingsTab, index) => (
148
+ <Tabs.Panel
149
+ key={`${plugin.id}-${index.toString()}`}
150
+ id={settingsTab.view}
151
+ className="px-0"
152
+ >
153
+ <settingsTab.component variant={variant} />
154
+ </Tabs.Panel>
155
+ ))
156
+ )}
94
157
  </Tabs>
95
158
  )
96
159
  }
@@ -13,7 +13,10 @@ export type UserAvatarProps = {
13
13
  fallback?: ReactNode
14
14
  isPending?: boolean
15
15
  /** @remarks `User` */
16
- user?: User & { username?: string | null; displayUsername?: string | null }
16
+ user?: Partial<User> & {
17
+ username?: string | null
18
+ displayUsername?: string | null
19
+ }
17
20
  size?: AvatarProps["size"]
18
21
  }
19
22
 
@@ -46,16 +46,15 @@ export type UserButtonLink = {
46
46
  export type UserButtonProps = {
47
47
  className?: string
48
48
  size?: "default" | "icon"
49
- /**
50
- * The placement of the element with respect to its anchor element.
51
- * @default "bottom"
52
- */
49
+ /** The placement of the element with respect to its anchor element. */
53
50
  placement?: DropdownPopoverProps["placement"]
54
51
  variant?: ButtonProps["variant"]
55
52
  /** Additional menu entries rendered above the built-in items. */
56
53
  links?: (UserButtonLink | ReactElement)[]
57
54
  /** Hide the built-in "Settings" link. Useful when replacing it via `links`. */
58
55
  hideSettings?: boolean
56
+ /** When true, the subtitle line (email when name/username is shown) is hidden. */
57
+ hideSubtitle?: boolean
59
58
  }
60
59
 
61
60
  function renderUserLink(
@@ -91,11 +90,12 @@ function renderUserLink(
91
90
  */
92
91
  export function UserButton({
93
92
  className,
94
- placement = "bottom",
93
+ placement,
95
94
  size = "default",
96
95
  variant = "ghost",
97
96
  links,
98
- hideSettings = false
97
+ hideSettings,
98
+ hideSubtitle
99
99
  }: UserButtonProps) {
100
100
  const { authClient, basePaths, viewPaths, localization, plugins } = useAuth()
101
101
 
@@ -104,7 +104,10 @@ export function UserButton({
104
104
  const userMenuItems = plugins.flatMap(
105
105
  (plugin) =>
106
106
  plugin.userMenuItems?.map((Item, index) => (
107
- <Item key={`${plugin.id}-${index.toString()}`} />
107
+ <Item
108
+ key={`${plugin.id}-${index.toString()}`}
109
+ hideSubtitle={hideSubtitle}
110
+ />
108
111
  )) ?? []
109
112
  )
110
113
 
@@ -127,12 +130,12 @@ export function UserButton({
127
130
  <Button
128
131
  variant={variant}
129
132
  className={cn(
130
- "h-auto font-normal justify-start px-3 py-2 text-left",
133
+ "h-auto font-normal justify-start px-2 py-2 text-left",
131
134
  className
132
135
  )}
133
136
  >
134
137
  {session || sessionPending ? (
135
- <UserView isPending={sessionPending} />
138
+ <UserView isPending={sessionPending} hideSubtitle={hideSubtitle} />
136
139
  ) : (
137
140
  <>
138
141
  <UserAvatar />
@@ -141,7 +144,7 @@ export function UserButton({
141
144
  </>
142
145
  )}
143
146
 
144
- <ChevronsExpandVertical className="ml-auto size-3.5" />
147
+ <ChevronsExpandVertical className="ml-auto size-3 text-muted" />
145
148
  </Button>
146
149
  )}
147
150
 
@@ -151,7 +154,7 @@ export function UserButton({
151
154
  >
152
155
  {session && (
153
156
  <div className="px-3 pt-3 pb-1">
154
- <UserView />
157
+ <UserView hideSubtitle={hideSubtitle} />
155
158
  </div>
156
159
  )}
157
160
 
@@ -12,22 +12,32 @@ export type UserViewProps = {
12
12
  className?: string
13
13
  isPending?: boolean
14
14
  size?: AvatarProps["size"]
15
+ /**
16
+ * When true, the subtitle line (email when name/username is shown) is hidden.
17
+ * @default false
18
+ */
19
+ hideSubtitle?: boolean
15
20
  /** @remarks `User` */
16
- user?: User & { username?: string | null; displayUsername?: string | null }
21
+ user?: Partial<User> & {
22
+ username?: string | null
23
+ displayUsername?: string | null
24
+ }
17
25
  }
18
26
 
19
27
  /**
20
- * Render a compact user item with an avatar, a primary label (display username, name, or email), and an optional secondary email line.
28
+ * Render a compact user item with an avatar, a primary label (display username, name, or email), and an optional subtitle (email).
21
29
  *
22
30
  * @param isPending - If true and no `user` prop is provided, renders a loading skeleton instead of user details
23
- * @param size - Avatar size variant; defaults to `"sm"`
31
+ * @param size - Avatar size variant; defaults to `"md"`
32
+ * @param hideSubtitle - When true, omits the muted subtitle row under the primary label
24
33
  * @param user - Optional user to display; when omitted the current session user is used if available
25
34
  * @returns A React element containing the user's avatar and text labels
26
35
  */
27
36
  export function UserView({
28
37
  className,
29
38
  isPending,
30
- size = "sm",
39
+ size = "md",
40
+ hideSubtitle = false,
31
41
  user,
32
42
  ...props
33
43
  }: UserViewProps & ComponentProps<"div">) {
@@ -47,11 +57,16 @@ export function UserView({
47
57
  className={cn("flex items-center gap-2 min-w-0", className)}
48
58
  {...props}
49
59
  >
50
- <UserAvatar isPending size={size} />
60
+ <UserAvatar
61
+ isPending
62
+ className={size === "sm" ? "size-5 [&>span]:text-xs" : undefined}
63
+ size={size === "lg" ? "md" : "sm"}
64
+ />
51
65
 
52
66
  <div className="flex flex-col gap-1 min-w-0">
53
67
  <Skeleton className="h-3.5 w-24 rounded-lg" />
54
- <Skeleton className="h-3 w-32 rounded-lg" />
68
+
69
+ {!hideSubtitle ? <Skeleton className="h-3 w-32 rounded-lg" /> : null}
55
70
  </div>
56
71
  </div>
57
72
  )
@@ -62,20 +77,25 @@ export function UserView({
62
77
  className={cn("flex items-center gap-2 min-w-0", className)}
63
78
  {...props}
64
79
  >
65
- <UserAvatar user={resolvedUser} size={size} />
80
+ <UserAvatar
81
+ className={size === "sm" ? "size-5 [&>span]:text-xs" : undefined}
82
+ user={resolvedUser}
83
+ size={size === "lg" ? "md" : "sm"}
84
+ />
66
85
 
67
- <div className="min-w-0">
68
- <p className="text-sm font-medium truncate leading-tight">
86
+ <div className="flex flex-col min-w-0">
87
+ <p className="text-foreground text-sm font-medium leading-tight truncate">
69
88
  {resolvedUser?.displayUsername ||
70
89
  resolvedUser?.name ||
71
90
  resolvedUser?.email}
72
91
  </p>
73
92
 
74
- {(resolvedUser?.displayUsername || resolvedUser?.name) && (
75
- <p className="text-muted text-xs mb-0.5 truncate overflow-x-hidden">
93
+ {!hideSubtitle &&
94
+ (resolvedUser?.displayUsername || resolvedUser?.name) ? (
95
+ <p className="text-muted text-xs leading-tight truncate overflow-x-hidden">
76
96
  {resolvedUser?.email}
77
97
  </p>
78
- )}
98
+ ) : null}
79
99
  </div>
80
100
  </div>
81
101
  )
package/src/email.ts CHANGED
@@ -4,6 +4,7 @@ export * from "./components/auth/email/email-changed-email"
4
4
  export * from "./components/auth/email/email-verification-email"
5
5
  export * from "./components/auth/email/magic-link-email"
6
6
  export * from "./components/auth/email/new-device-email"
7
+ export * from "./components/auth/email/organization-invitation-email"
7
8
  export * from "./components/auth/email/otp-email"
8
9
  export * from "./components/auth/email/password-changed-email"
9
10
  export * from "./components/auth/email/reset-password-email"
@@ -5,11 +5,17 @@ import {
5
5
  } from "@better-auth-ui/core/plugins"
6
6
 
7
7
  import { ApiKeys } from "../../components/auth/api-key/api-keys"
8
+ import { OrganizationApiKeys } from "../../components/auth/api-key/organization-api-keys"
8
9
 
9
10
  export const apiKeyPlugin = createAuthPlugin(
10
11
  coreApiKeyPlugin.id,
11
- (options: ApiKeyPluginOptions = {}) => ({
12
- ...coreApiKeyPlugin(options),
13
- securityCards: [ApiKeys]
14
- })
12
+ (options: ApiKeyPluginOptions = {}) => {
13
+ const core = coreApiKeyPlugin(options)
14
+
15
+ return {
16
+ ...core,
17
+ securityCards: [ApiKeys],
18
+ ...(core.organization ? { organizationCards: [OrganizationApiKeys] } : {})
19
+ }
20
+ }
15
21
  )
@@ -3,6 +3,7 @@ import type {
3
3
  AccountCardProps,
4
4
  AuthPlugin as AuthPluginPrimitive,
5
5
  AuthPluginComponents as BaseAuthPluginComponents,
6
+ OrganizationCardProps,
6
7
  SecurityCardProps,
7
8
  UserMenuItemProps
8
9
  } from "@better-auth-ui/react"
@@ -36,7 +37,7 @@ declare module "@better-auth-ui/core" {
36
37
  /** Heroui slot component shapes — inherits from the framework-agnostic defaults and narrows slots that receive a heroui variant from the host. */
37
38
  export type AuthPluginComponents = Omit<
38
39
  BaseAuthPluginComponents,
39
- "securityCards" | "accountCards"
40
+ "securityCards" | "accountCards" | "organizationCards"
40
41
  > & {
41
42
  /** Rendered as cards inside security settings */
42
43
  securityCards?: ComponentType<
@@ -46,6 +47,10 @@ export type AuthPluginComponents = Omit<
46
47
  accountCards?: ComponentType<
47
48
  AccountCardProps & { variant?: CardProps["variant"] }
48
49
  >[]
50
+ /** Rendered as cards inside the active organization's settings */
51
+ organizationCards?: ComponentType<
52
+ OrganizationCardProps & { variant?: CardProps["variant"] }
53
+ >[]
49
54
  /** Rendered as items inside the `UserButton` dropdown (e.g. account switcher). */
50
55
  userMenuItems?: ComponentType<UserMenuItemProps>[]
51
56
  }
@@ -0,0 +1,32 @@
1
+ import { createAuthPlugin } from "@better-auth-ui/core"
2
+ import {
3
+ organizationPlugin as coreOrganizationPlugin,
4
+ type OrganizationLocalization,
5
+ type OrganizationPluginOptions
6
+ } from "@better-auth-ui/core/plugins"
7
+ import { Briefcase } from "@gravity-ui/icons"
8
+ import { OrganizationsSettings } from "../../components/auth/organization/organizations-settings"
9
+
10
+ export const organizationPlugin = createAuthPlugin(
11
+ coreOrganizationPlugin.id,
12
+ (options: OrganizationPluginOptions = {}) => {
13
+ const coreOptions = coreOrganizationPlugin(options)
14
+
15
+ return {
16
+ ...coreOptions,
17
+ localization: coreOptions.localization as OrganizationLocalization,
18
+ settingsTabs: [
19
+ {
20
+ view: "organizations",
21
+ label: (
22
+ <>
23
+ <Briefcase className="text-muted" />
24
+ {coreOptions.localization.organizations}
25
+ </>
26
+ ),
27
+ component: OrganizationsSettings
28
+ }
29
+ ]
30
+ }
31
+ }
32
+ )
package/src/plugins.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  "use client"
2
2
 
3
3
  export * from "./components/auth/api-key/api-keys"
4
+ export * from "./components/auth/api-key/organization-api-keys"
4
5
  export * from "./components/auth/delete-user/danger-zone"
5
- export * from "./components/auth/delete-user/delete-user"
6
+ export * from "./components/auth/delete-user/delete-account"
6
7
  // Plugin-contributed components that may be used standalone
7
8
  export * from "./components/auth/magic-link/magic-link"
8
9
  export * from "./components/auth/multi-session/manage-account"
@@ -10,6 +11,28 @@ export * from "./components/auth/multi-session/manage-accounts"
10
11
  export * from "./components/auth/multi-session/switch-account-submenu"
11
12
  export * from "./components/auth/multi-session/switch-account-submenu-content"
12
13
  export * from "./components/auth/multi-session/switch-account-submenu-item"
14
+ export * from "./components/auth/organization/change-organization-logo"
15
+ export * from "./components/auth/organization/create-organization-dialog"
16
+ export * from "./components/auth/organization/delete-organization"
17
+ export * from "./components/auth/organization/delete-organization-skeleton"
18
+ export * from "./components/auth/organization/invite-member-dialog"
19
+ export * from "./components/auth/organization/leave-organization"
20
+ export * from "./components/auth/organization/organization"
21
+ export * from "./components/auth/organization/organization-danger-zone"
22
+ export * from "./components/auth/organization/organization-invitations"
23
+ export * from "./components/auth/organization/organization-invitations-empty"
24
+ export * from "./components/auth/organization/organization-logo"
25
+ export * from "./components/auth/organization/organization-members"
26
+ export * from "./components/auth/organization/organization-people"
27
+ export * from "./components/auth/organization/organization-profile"
28
+ export * from "./components/auth/organization/organization-row"
29
+ export * from "./components/auth/organization/organization-settings"
30
+ export * from "./components/auth/organization/organization-switcher"
31
+ export * from "./components/auth/organization/organization-view"
32
+ export * from "./components/auth/organization/organization-view-skeleton"
33
+ export * from "./components/auth/organization/organizations"
34
+ export * from "./components/auth/organization/organizations-settings"
35
+ export * from "./components/auth/organization/user-invitations"
13
36
  export * from "./components/auth/passkey/passkeys"
14
37
  export * from "./components/auth/theme/appearance"
15
38
  export * from "./components/auth/theme/theme-toggle-item"
@@ -20,6 +43,7 @@ export * from "./lib/auth/auth-plugin"
20
43
  export * from "./lib/auth/delete-user-plugin"
21
44
  export * from "./lib/auth/magic-link-plugin"
22
45
  export * from "./lib/auth/multi-session-plugin"
46
+ export * from "./lib/auth/organization-plugin"
23
47
  export * from "./lib/auth/passkey-plugin"
24
48
  export * from "./lib/auth/theme-plugin"
25
49
  export * from "./lib/auth/username-plugin"
@@ -1,9 +0,0 @@
1
- import { 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 & Omit<CardProps, "children">): import("react/jsx-runtime").JSX.Element;
@@ -1,95 +0,0 @@
1
- import { deleteUserPlugin as e } from "../../../lib/auth/delete-user-plugin.js";
2
- import { authQueryKeys as t } from "@better-auth-ui/core";
3
- import { useAuth as n, useAuthPlugin as r, useDeleteUser as i, useListAccounts as a } from "@better-auth-ui/react";
4
- import { TriangleExclamation as o } from "@gravity-ui/icons";
5
- import { AlertDialog as s, Button as c, Card as l, FieldError as u, Form as d, Input as f, Label as p, Spinner as m, TextField as h, toast as g } from "@heroui/react";
6
- import { useState as _ } from "react";
7
- import { jsx as v, jsxs as y } from "react/jsx-runtime";
8
- import { useQueryClient as b } from "@tanstack/react-query";
9
- //#region src/components/auth/delete-user/delete-user.tsx
10
- function x({ className: x, variant: S, ...C }) {
11
- let { authClient: w, basePaths: T, localization: E, navigate: D, viewPaths: O } = n(), { localization: k, sendDeleteAccountVerification: A } = r(e), { data: j } = a(w), M = b(), [N, P] = _(!1), [F, I] = _(""), L = j?.some((e) => e.providerId === "credential"), R = !A && L, { mutate: z, isPending: B } = i(w), V = (e) => {
12
- P(e), I("");
13
- }, H = async (e) => {
14
- e.preventDefault(), z({ ...R ? { password: F } : {} }, { onSuccess: () => {
15
- P(!1), I(""), A ? g.success(k.deleteUserVerificationSent) : (g.success(k.deleteUserSuccess), M.removeQueries({ queryKey: t.all }), D({
16
- to: `${T.auth}/${O.auth.signIn}`,
17
- replace: !0
18
- }));
19
- } });
20
- };
21
- return /* @__PURE__ */ v(l, {
22
- className: x,
23
- variant: S,
24
- ...C,
25
- children: /* @__PURE__ */ y(l.Content, {
26
- className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
27
- children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
28
- className: "text-sm font-medium leading-tight",
29
- children: k.deleteUser
30
- }), /* @__PURE__ */ v("p", {
31
- className: "text-muted text-xs mt-0.5",
32
- children: k.deleteUserDescription
33
- })] }), /* @__PURE__ */ y(s, { children: [/* @__PURE__ */ v(c, {
34
- isDisabled: !j,
35
- size: "sm",
36
- variant: "danger-soft",
37
- onPress: () => P(!0),
38
- children: k.deleteUser
39
- }), /* @__PURE__ */ v(s.Backdrop, {
40
- isOpen: N,
41
- onOpenChange: V,
42
- children: /* @__PURE__ */ v(s.Container, { children: /* @__PURE__ */ v(s.Dialog, { children: /* @__PURE__ */ y(d, {
43
- onSubmit: H,
44
- children: [
45
- /* @__PURE__ */ v(s.CloseTrigger, {}),
46
- /* @__PURE__ */ y(s.Header, { children: [/* @__PURE__ */ v(s.Icon, {
47
- status: "danger",
48
- children: /* @__PURE__ */ v(o, {})
49
- }), /* @__PURE__ */ v(s.Heading, { children: k.deleteUser })] }),
50
- /* @__PURE__ */ y(s.Body, {
51
- className: "overflow-visible",
52
- children: [/* @__PURE__ */ v("p", {
53
- className: "text-muted text-sm",
54
- children: k.deleteUserDescription
55
- }), R && /* @__PURE__ */ y(h, {
56
- className: "mt-4",
57
- name: "password",
58
- type: "password",
59
- isDisabled: B,
60
- value: F,
61
- onChange: I,
62
- children: [
63
- /* @__PURE__ */ v(p, { children: E.auth.password }),
64
- /* @__PURE__ */ v(f, {
65
- autoComplete: "current-password",
66
- placeholder: E.auth.passwordPlaceholder,
67
- required: !0,
68
- variant: "secondary"
69
- }),
70
- /* @__PURE__ */ v(u, {})
71
- ]
72
- })]
73
- }),
74
- /* @__PURE__ */ y(s.Footer, { children: [/* @__PURE__ */ v(c, {
75
- slot: "close",
76
- variant: "tertiary",
77
- isDisabled: B,
78
- children: E.settings.cancel
79
- }), /* @__PURE__ */ y(c, {
80
- type: "submit",
81
- variant: "danger",
82
- isPending: B,
83
- children: [B && /* @__PURE__ */ v(m, {
84
- color: "current",
85
- size: "sm"
86
- }), k.deleteUser]
87
- })] })
88
- ]
89
- }) }) })
90
- })] })]
91
- })
92
- });
93
- }
94
- //#endregion
95
- export { x as DeleteUser };