@better-auth-ui/react 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 (250) hide show
  1. package/dist/components/auth/auth-provider.d.ts +32 -0
  2. package/dist/components/auth/auth-provider.js +44 -0
  3. package/dist/components/email/email-changed.d.ts +97 -0
  4. package/dist/components/email/email-changed.js +70 -0
  5. package/dist/components/email/email-localization.d.ts +61 -0
  6. package/dist/components/email/email-localization.js +24 -0
  7. package/dist/components/email/email-styles.d.ts +89 -0
  8. package/dist/components/email/email-styles.js +129 -0
  9. package/dist/components/email/email-verification.d.ts +97 -0
  10. package/dist/components/email/email-verification.js +75 -0
  11. package/dist/components/email/index.d.ts +9 -0
  12. package/dist/components/email/index.js +9 -0
  13. package/dist/components/email/magic-link.d.ts +93 -0
  14. package/dist/components/email/magic-link.js +72 -0
  15. package/dist/components/email/new-device.d.ts +123 -0
  16. package/dist/components/email/new-device.js +90 -0
  17. package/dist/components/email/otp-email.d.ts +88 -0
  18. package/dist/components/email/otp-email.js +65 -0
  19. package/dist/components/email/password-changed.d.ts +96 -0
  20. package/dist/components/email/password-changed.js +76 -0
  21. package/dist/components/email/reset-password.d.ts +90 -0
  22. package/dist/components/email/reset-password.js +68 -0
  23. package/dist/components/icons/apple.d.ts +8 -0
  24. package/dist/components/icons/apple.js +10 -0
  25. package/dist/components/icons/atlassian.d.ts +10 -0
  26. package/dist/components/icons/atlassian.js +14 -0
  27. package/dist/components/icons/cognito.d.ts +8 -0
  28. package/dist/components/icons/cognito.js +10 -0
  29. package/dist/components/icons/discord.d.ts +8 -0
  30. package/dist/components/icons/discord.js +10 -0
  31. package/dist/components/icons/dropbox.d.ts +8 -0
  32. package/dist/components/icons/dropbox.js +10 -0
  33. package/dist/components/icons/facebook.d.ts +10 -0
  34. package/dist/components/icons/facebook.js +12 -0
  35. package/dist/components/icons/figma.d.ts +11 -0
  36. package/dist/components/icons/figma.js +13 -0
  37. package/dist/components/icons/github.d.ts +10 -0
  38. package/dist/components/icons/github.js +12 -0
  39. package/dist/components/icons/gitlab.d.ts +8 -0
  40. package/dist/components/icons/gitlab.js +10 -0
  41. package/dist/components/icons/google.d.ts +8 -0
  42. package/dist/components/icons/google.js +10 -0
  43. package/dist/components/icons/huggingface.d.ts +8 -0
  44. package/dist/components/icons/huggingface.js +10 -0
  45. package/dist/components/icons/index.d.ts +35 -0
  46. package/dist/components/icons/index.js +35 -0
  47. package/dist/components/icons/kakao.d.ts +10 -0
  48. package/dist/components/icons/kakao.js +12 -0
  49. package/dist/components/icons/kick.d.ts +10 -0
  50. package/dist/components/icons/kick.js +12 -0
  51. package/dist/components/icons/line.d.ts +8 -0
  52. package/dist/components/icons/line.js +10 -0
  53. package/dist/components/icons/linear.d.ts +8 -0
  54. package/dist/components/icons/linear.js +10 -0
  55. package/dist/components/icons/linkedin.d.ts +8 -0
  56. package/dist/components/icons/linkedin.js +10 -0
  57. package/dist/components/icons/microsoft.d.ts +8 -0
  58. package/dist/components/icons/microsoft.js +10 -0
  59. package/dist/components/icons/naver.d.ts +8 -0
  60. package/dist/components/icons/naver.js +10 -0
  61. package/dist/components/icons/notion.d.ts +8 -0
  62. package/dist/components/icons/notion.js +10 -0
  63. package/dist/components/icons/paybin.d.ts +7 -0
  64. package/dist/components/icons/paybin.js +9 -0
  65. package/dist/components/icons/paypal.d.ts +8 -0
  66. package/dist/components/icons/paypal.js +10 -0
  67. package/dist/components/icons/polar.d.ts +8 -0
  68. package/dist/components/icons/polar.js +10 -0
  69. package/dist/components/icons/railway.d.ts +8 -0
  70. package/dist/components/icons/railway.js +10 -0
  71. package/dist/components/icons/reddit.d.ts +8 -0
  72. package/dist/components/icons/reddit.js +10 -0
  73. package/dist/components/icons/roblox.d.ts +11 -0
  74. package/dist/components/icons/roblox.js +13 -0
  75. package/dist/components/icons/salesforce.d.ts +8 -0
  76. package/dist/components/icons/salesforce.js +10 -0
  77. package/dist/components/icons/slack.d.ts +8 -0
  78. package/dist/components/icons/slack.js +10 -0
  79. package/dist/components/icons/spotify.d.ts +8 -0
  80. package/dist/components/icons/spotify.js +10 -0
  81. package/dist/components/icons/tiktok.d.ts +9 -0
  82. package/dist/components/icons/tiktok.js +11 -0
  83. package/dist/components/icons/twitch.d.ts +8 -0
  84. package/dist/components/icons/twitch.js +13 -0
  85. package/dist/components/icons/vercel.d.ts +8 -0
  86. package/dist/components/icons/vercel.js +10 -0
  87. package/dist/components/icons/vk.d.ts +8 -0
  88. package/dist/components/icons/vk.js +10 -0
  89. package/dist/components/icons/wechat.d.ts +8 -0
  90. package/dist/components/icons/wechat.js +10 -0
  91. package/dist/components/icons/x.d.ts +8 -0
  92. package/dist/components/icons/x.js +10 -0
  93. package/dist/components/icons/zoom.d.ts +8 -0
  94. package/dist/components/icons/zoom.js +12 -0
  95. package/dist/components/settings/account/theme-preview.d.ts +3 -0
  96. package/dist/components/settings/account/theme-preview.js +10 -0
  97. package/dist/core.d.ts +1 -0
  98. package/dist/core.js +1 -0
  99. package/dist/hooks/auth/use-auth-mutation.d.ts +18 -0
  100. package/dist/hooks/auth/use-auth-mutation.js +10 -0
  101. package/dist/hooks/auth/use-auth-query.d.ts +24 -0
  102. package/dist/hooks/auth/use-auth-query.js +10 -0
  103. package/dist/hooks/auth/use-authenticate.d.ts +9 -0
  104. package/dist/hooks/auth/use-authenticate.js +28 -0
  105. package/dist/hooks/auth/use-forgot-password.d.ts +20 -0
  106. package/dist/hooks/auth/use-forgot-password.js +14 -0
  107. package/dist/hooks/auth/use-request-password-reset.d.ts +26 -0
  108. package/dist/hooks/auth/use-request-password-reset.js +14 -0
  109. package/dist/hooks/auth/use-reset-password.d.ts +40 -0
  110. package/dist/hooks/auth/use-reset-password.js +13 -0
  111. package/dist/hooks/auth/use-send-verification-email.d.ts +24 -0
  112. package/dist/hooks/auth/use-send-verification-email.js +13 -0
  113. package/dist/hooks/auth/use-session.d.ts +9 -0
  114. package/dist/hooks/auth/use-session.js +18 -0
  115. package/dist/hooks/auth/use-sign-in-email.d.ts +53 -0
  116. package/dist/hooks/auth/use-sign-in-email.js +24 -0
  117. package/dist/hooks/auth/use-sign-in-magic-link.d.ts +32 -0
  118. package/dist/hooks/auth/use-sign-in-magic-link.js +13 -0
  119. package/dist/hooks/auth/use-sign-in-social.d.ts +93 -0
  120. package/dist/hooks/auth/use-sign-in-social.js +13 -0
  121. package/dist/hooks/auth/use-sign-out.d.ts +19 -0
  122. package/dist/hooks/auth/use-sign-out.js +24 -0
  123. package/dist/hooks/auth/use-sign-up-email.d.ts +526 -0
  124. package/dist/hooks/auth/use-sign-up-email.js +24 -0
  125. package/dist/hooks/auth/use-user.d.ts +513 -0
  126. package/dist/hooks/auth/use-user.js +14 -0
  127. package/dist/hooks/settings/use-account-info.d.ts +17 -0
  128. package/dist/hooks/settings/use-account-info.js +25 -0
  129. package/dist/hooks/settings/use-change-email.d.ts +24 -0
  130. package/dist/hooks/settings/use-change-email.js +23 -0
  131. package/dist/hooks/settings/use-change-password.d.ts +54 -0
  132. package/dist/hooks/settings/use-change-password.js +11 -0
  133. package/dist/hooks/settings/use-delete-user.d.ts +42 -0
  134. package/dist/hooks/settings/use-delete-user.js +11 -0
  135. package/dist/hooks/settings/use-link-social.d.ts +46 -0
  136. package/dist/hooks/settings/use-link-social.js +10 -0
  137. package/dist/hooks/settings/use-list-accounts.d.ts +20 -0
  138. package/dist/hooks/settings/use-list-accounts.js +23 -0
  139. package/dist/hooks/settings/use-list-device-sessions.d.ts +11 -0
  140. package/dist/hooks/settings/use-list-device-sessions.js +22 -0
  141. package/dist/hooks/settings/use-list-sessions.d.ts +20 -0
  142. package/dist/hooks/settings/use-list-sessions.js +22 -0
  143. package/dist/hooks/settings/use-revoke-multi-session.d.ts +19 -0
  144. package/dist/hooks/settings/use-revoke-multi-session.js +20 -0
  145. package/dist/hooks/settings/use-revoke-session.d.ts +19 -0
  146. package/dist/hooks/settings/use-revoke-session.js +21 -0
  147. package/dist/hooks/settings/use-set-active-session.d.ts +37 -0
  148. package/dist/hooks/settings/use-set-active-session.js +28 -0
  149. package/dist/hooks/settings/use-unlink-account.d.ts +21 -0
  150. package/dist/hooks/settings/use-unlink-account.js +21 -0
  151. package/dist/hooks/settings/use-update-user.d.ts +11 -0
  152. package/dist/hooks/settings/use-update-user.js +29 -0
  153. package/dist/hooks/use-hydrated.d.ts +6 -0
  154. package/dist/hooks/use-hydrated.js +18 -0
  155. package/dist/index.d.ts +32 -0
  156. package/dist/index.js +33 -0
  157. package/dist/lib/auth-client.d.ts +1979 -0
  158. package/dist/lib/auth-client.js +5 -0
  159. package/dist/lib/auth-config.d.ts +43 -0
  160. package/dist/lib/auth-config.js +1 -0
  161. package/dist/lib/auth-context.d.ts +2 -0
  162. package/dist/lib/auth-context.js +3 -0
  163. package/dist/lib/auth-hook-options.d.ts +8 -0
  164. package/dist/lib/auth-hook-options.js +1 -0
  165. package/dist/lib/provider-icons.d.ts +13 -0
  166. package/dist/lib/provider-icons.js +48 -0
  167. package/dist/lib/utils.d.ts +2 -0
  168. package/dist/lib/utils.js +5 -0
  169. package/package.json +64 -0
  170. package/src/components/auth/auth-provider.tsx +82 -0
  171. package/src/components/email/email-changed.tsx +381 -0
  172. package/src/components/email/email-localization.tsx +33 -0
  173. package/src/components/email/email-styles.tsx +175 -0
  174. package/src/components/email/email-verification.tsx +350 -0
  175. package/src/components/email/index.ts +9 -0
  176. package/src/components/email/magic-link.tsx +349 -0
  177. package/src/components/email/new-device.tsx +452 -0
  178. package/src/components/email/otp-email.tsx +321 -0
  179. package/src/components/email/password-changed.tsx +380 -0
  180. package/src/components/email/reset-password.tsx +343 -0
  181. package/src/components/icons/apple.tsx +24 -0
  182. package/src/components/icons/atlassian.tsx +43 -0
  183. package/src/components/icons/cognito.tsx +25 -0
  184. package/src/components/icons/discord.tsx +24 -0
  185. package/src/components/icons/dropbox.tsx +24 -0
  186. package/src/components/icons/facebook.tsx +30 -0
  187. package/src/components/icons/figma.tsx +43 -0
  188. package/src/components/icons/github.tsx +26 -0
  189. package/src/components/icons/gitlab.tsx +36 -0
  190. package/src/components/icons/google.tsx +42 -0
  191. package/src/components/icons/huggingface.tsx +44 -0
  192. package/src/components/icons/index.ts +35 -0
  193. package/src/components/icons/kakao.tsx +26 -0
  194. package/src/components/icons/kick.tsx +30 -0
  195. package/src/components/icons/line.tsx +24 -0
  196. package/src/components/icons/linear.tsx +24 -0
  197. package/src/components/icons/linkedin.tsx +28 -0
  198. package/src/components/icons/microsoft.tsx +24 -0
  199. package/src/components/icons/naver.tsx +24 -0
  200. package/src/components/icons/notion.tsx +25 -0
  201. package/src/components/icons/paybin.tsx +37 -0
  202. package/src/components/icons/paypal.tsx +36 -0
  203. package/src/components/icons/polar.tsx +31 -0
  204. package/src/components/icons/railway.tsx +24 -0
  205. package/src/components/icons/reddit.tsx +25 -0
  206. package/src/components/icons/roblox.tsx +28 -0
  207. package/src/components/icons/salesforce.tsx +24 -0
  208. package/src/components/icons/slack.tsx +36 -0
  209. package/src/components/icons/spotify.tsx +24 -0
  210. package/src/components/icons/tiktok.tsx +32 -0
  211. package/src/components/icons/twitch.tsx +50 -0
  212. package/src/components/icons/vercel.tsx +21 -0
  213. package/src/components/icons/vk.tsx +24 -0
  214. package/src/components/icons/wechat.tsx +24 -0
  215. package/src/components/icons/x.tsx +24 -0
  216. package/src/components/icons/zoom.tsx +48 -0
  217. package/src/components/settings/account/theme-preview.tsx +271 -0
  218. package/src/core.ts +1 -0
  219. package/src/hooks/auth/use-auth-mutation.ts +56 -0
  220. package/src/hooks/auth/use-auth-query.ts +50 -0
  221. package/src/hooks/auth/use-authenticate.ts +35 -0
  222. package/src/hooks/auth/use-request-password-reset.ts +24 -0
  223. package/src/hooks/auth/use-reset-password.ts +23 -0
  224. package/src/hooks/auth/use-send-verification-email.ts +23 -0
  225. package/src/hooks/auth/use-session.ts +26 -0
  226. package/src/hooks/auth/use-sign-in-email.ts +35 -0
  227. package/src/hooks/auth/use-sign-in-magic-link.ts +23 -0
  228. package/src/hooks/auth/use-sign-in-social.ts +23 -0
  229. package/src/hooks/auth/use-sign-out.ts +34 -0
  230. package/src/hooks/auth/use-sign-up-email.ts +35 -0
  231. package/src/hooks/auth/use-user.ts +21 -0
  232. package/src/hooks/settings/use-account-info.ts +30 -0
  233. package/src/hooks/settings/use-change-email.ts +33 -0
  234. package/src/hooks/settings/use-change-password.ts +21 -0
  235. package/src/hooks/settings/use-delete-user.ts +21 -0
  236. package/src/hooks/settings/use-link-social.ts +19 -0
  237. package/src/hooks/settings/use-list-accounts.ts +27 -0
  238. package/src/hooks/settings/use-list-device-sessions.ts +32 -0
  239. package/src/hooks/settings/use-list-sessions.ts +26 -0
  240. package/src/hooks/settings/use-revoke-multi-session.ts +30 -0
  241. package/src/hooks/settings/use-revoke-session.ts +31 -0
  242. package/src/hooks/settings/use-set-active-session.ts +46 -0
  243. package/src/hooks/settings/use-unlink-account.ts +31 -0
  244. package/src/hooks/settings/use-update-user.ts +44 -0
  245. package/src/index.ts +34 -0
  246. package/src/lib/auth-client.ts +37 -0
  247. package/src/lib/auth-config.ts +48 -0
  248. package/src/lib/auth-context.ts +6 -0
  249. package/src/lib/provider-icons.ts +90 -0
  250. package/src/lib/utils.ts +6 -0
@@ -0,0 +1,5 @@
1
+ import { magicLinkClient, multiSessionClient, usernameClient } from "better-auth/client/plugins";
2
+ import { createAuthClient } from "better-auth/react";
3
+ const authClient = createAuthClient({
4
+ plugins: [magicLinkClient(), multiSessionClient(), usernameClient()]
5
+ });
@@ -0,0 +1,43 @@
1
+ import type { AuthConfig as BaseAuthConfig } from "@better-auth-ui/react/core";
2
+ import type { ComponentType, PropsWithChildren } from "react";
3
+ import type { AnyAuthClient, AuthClient } from "./auth-client";
4
+ /**
5
+ * Extends the base AuthConfig with React-specific requirements including
6
+ * an authClient instance and a Link component for navigation.
7
+ *
8
+ * Users can augment this interface to provide their own auth client type:
9
+ * @example
10
+ * ```ts
11
+ * declare module "@better-auth-ui/react" {
12
+ * interface AuthConfig {
13
+ * AuthClient: typeof authClient
14
+ * }
15
+ * }
16
+ * ```
17
+ */
18
+ export interface AuthConfig extends BaseAuthConfig {
19
+ authClient: AuthClient;
20
+ /**
21
+ * React component for rendering links
22
+ * @remarks `LinkComponent`
23
+ */
24
+ Link: ComponentType<PropsWithChildren<{
25
+ className?: string;
26
+ href: string;
27
+ to?: string;
28
+ }>>;
29
+ }
30
+ type DeepPartial<T> = T extends (...args: any[]) => any ? T : T extends object ? {
31
+ [P in keyof T]?: DeepPartial<T[P]>;
32
+ } : T;
33
+ /**
34
+ * Partial AuthConfig with any Better Auth client instance.
35
+ */
36
+ export type AnyAuthConfig = DeepPartial<Omit<AuthConfig, "authClient">> & {
37
+ /**
38
+ * Better Auth client instance
39
+ * @remarks `AuthClient`
40
+ */
41
+ authClient?: AnyAuthClient;
42
+ };
43
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { AuthConfig } from "./auth-config";
2
+ export declare const AuthContext: import("react").Context<AuthConfig | undefined>;
@@ -0,0 +1,3 @@
1
+ "use client";
2
+ import { createContext } from "react";
3
+ export const AuthContext = createContext(undefined);
@@ -0,0 +1,8 @@
1
+ import type { AuthError } from "@better-auth-ui/core";
2
+ /**
3
+ * Common options for auth hooks.
4
+ */
5
+ export interface AuthHookOptions {
6
+ onError?: (error: AuthError) => unknown | Promise<unknown>;
7
+ onSuccess?: () => unknown | Promise<unknown>;
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { SocialProvider } from "better-auth/social-providers";
2
+ import type { ComponentPropsWithRef, ComponentType } from "react";
3
+ /**
4
+ * Mapping of social authentication provider names to their corresponding icon components.
5
+ *
6
+ * Provides React SVG icon components for all supported social authentication providers.
7
+ * Each icon is a React component that accepts standard SVG props and can be customized
8
+ * with className, size, color, etc.
9
+ *
10
+ * Supported providers include: Apple, Google, GitHub, Microsoft, Discord, Facebook,
11
+ * Twitter/X, and many others.
12
+ */
13
+ export declare const providerIcons: Record<SocialProvider, ComponentType<ComponentPropsWithRef<"svg">>>;
@@ -0,0 +1,48 @@
1
+ import { Apple, Atlassian, Cognito, Discord, Dropbox, Facebook, Figma, GitHub, GitLab, Google, HuggingFace, Kakao, Kick, Line, Linear, LinkedIn, Microsoft, Naver, Notion, Paybin, PayPal, Polar, Railway, Reddit, Roblox, Salesforce, Slack, Spotify, TikTok, Twitch, Vercel, VK, WeChat, X, Zoom } from "../components/icons";
2
+ /**
3
+ * Mapping of social authentication provider names to their corresponding icon components.
4
+ *
5
+ * Provides React SVG icon components for all supported social authentication providers.
6
+ * Each icon is a React component that accepts standard SVG props and can be customized
7
+ * with className, size, color, etc.
8
+ *
9
+ * Supported providers include: Apple, Google, GitHub, Microsoft, Discord, Facebook,
10
+ * Twitter/X, and many others.
11
+ */
12
+ export const providerIcons = {
13
+ apple: Apple,
14
+ atlassian: Atlassian,
15
+ cognito: Cognito,
16
+ discord: Discord,
17
+ dropbox: Dropbox,
18
+ facebook: Facebook,
19
+ figma: Figma,
20
+ github: GitHub,
21
+ gitlab: GitLab,
22
+ google: Google,
23
+ huggingface: HuggingFace,
24
+ kakao: Kakao,
25
+ kick: Kick,
26
+ line: Line,
27
+ linear: Linear,
28
+ linkedin: LinkedIn,
29
+ microsoft: Microsoft,
30
+ naver: Naver,
31
+ notion: Notion,
32
+ paybin: Paybin,
33
+ paypal: PayPal,
34
+ polar: Polar,
35
+ railway: Railway,
36
+ reddit: Reddit,
37
+ roblox: Roblox,
38
+ salesforce: Salesforce,
39
+ slack: Slack,
40
+ spotify: Spotify,
41
+ tiktok: TikTok,
42
+ twitch: Twitch,
43
+ twitter: X,
44
+ vercel: Vercel,
45
+ vk: VK,
46
+ wechat: WeChat,
47
+ zoom: Zoom
48
+ };
@@ -0,0 +1,2 @@
1
+ import { type ClassValue } from "clsx";
2
+ export declare function cn(...inputs: ClassValue[]): string;
@@ -0,0 +1,5 @@
1
+ import { clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+ export function cn(...inputs) {
4
+ return twMerge(clsx(inputs));
5
+ }
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@better-auth-ui/react",
3
+ "version": "1.6.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc",
7
+ "dev": "tsc --watch",
8
+ "email": "email dev --dir src/components/email -p 9000",
9
+ "test": "vitest"
10
+ },
11
+ "files": [
12
+ "src",
13
+ "dist"
14
+ ],
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "import": "./dist/index.js",
20
+ "types": "./dist/index.d.ts"
21
+ },
22
+ "./core": {
23
+ "import": "./dist/core.js",
24
+ "types": "./dist/core.d.ts"
25
+ }
26
+ },
27
+ "devDependencies": {
28
+ "@react-email/components": "^1.0.12",
29
+ "@react-email/preview-server": "^5.2.10",
30
+ "@tanstack/react-query": "^5.99.0",
31
+ "@testing-library/react": "^16.3.2",
32
+ "@testing-library/user-event": "^14.5.2",
33
+ "@types/react": "^19.2.14",
34
+ "@vitejs/plugin-react": "^6.0.1",
35
+ "@vitest/browser-playwright": "^4.1.4",
36
+ "better-auth": "^1.6.4",
37
+ "clsx": "^2.1.1",
38
+ "playwright": "^1.59.1",
39
+ "react": "^19.2.5",
40
+ "react-dom": "^19.2.5",
41
+ "react-email": "^5.2.10",
42
+ "tailwind-merge": "^3.5.0",
43
+ "tailwindcss": "^4.2.2",
44
+ "vitest": "^4.1.4",
45
+ "zod": "^4.3.6"
46
+ },
47
+ "dependencies": {
48
+ "@better-auth-ui/core": "*"
49
+ },
50
+ "peerDependencies": {
51
+ "@react-email/components": ">=1.0.12",
52
+ "@tanstack/react-query": ">=5.99.0",
53
+ "better-auth": ">=1.6.4",
54
+ "clsx": ">=2.0.0",
55
+ "react": ">=19.2.5",
56
+ "react-dom": ">=19.2.5",
57
+ "tailwind-merge": ">=3.5.0",
58
+ "tailwindcss": ">=4.2.2",
59
+ "zod": ">=4.3.0"
60
+ },
61
+ "publishConfig": {
62
+ "access": "public"
63
+ }
64
+ }
@@ -0,0 +1,82 @@
1
+ "use client"
2
+
3
+ import { deepmerge, defaultAuthConfig } from "@better-auth-ui/core"
4
+ import {
5
+ type AnyAuthClient,
6
+ type AnyAuthConfig,
7
+ type AuthConfig,
8
+ AuthContext
9
+ } from "@better-auth-ui/react"
10
+ import {
11
+ QueryClient,
12
+ QueryClientContext,
13
+ QueryClientProvider
14
+ } from "@tanstack/react-query"
15
+ import { type PropsWithChildren, useContext } from "react"
16
+
17
+ const fallbackQueryClient = new QueryClient()
18
+
19
+ const baseAuthConfig: AnyAuthConfig = {
20
+ ...defaultAuthConfig,
21
+ Link: (props) => <a {...props} />
22
+ }
23
+
24
+ export type AuthProviderProps = PropsWithChildren<AnyAuthConfig> & {
25
+ authClient: AnyAuthClient
26
+ navigate: (options: { to: string; replace?: boolean }) => void
27
+ /**
28
+ * TanStack QueryClient to use for your application's queries
29
+ */
30
+ queryClient?: QueryClient
31
+ }
32
+
33
+ /**
34
+ * Provides merged authentication configuration and a resolved React Query client to descendant components.
35
+ *
36
+ * The component merges the provided auth config with the library defaults, updates `redirectTo` from the
37
+ * current URL when the app is hydrated, wires a QueryClient (prop, context, or fallback) and installs an
38
+ * error handler that surfaces query errors via the configured toast. It then supplies the merged config
39
+ * via AuthContext and wraps children with QueryClientProvider.
40
+ *
41
+ * @returns The children wrapped with AuthContext.Provider and QueryClientProvider configured for auth.
42
+ */
43
+ export function AuthProvider({
44
+ children,
45
+ queryClient,
46
+ ...config
47
+ }: AuthProviderProps) {
48
+ const contextQueryClient = useContext(QueryClientContext)
49
+ const resolvedQueryClient =
50
+ queryClient || contextQueryClient || fallbackQueryClient
51
+
52
+ const mergedConfig = deepmerge(baseAuthConfig, config) as AuthConfig
53
+
54
+ mergedConfig.redirectTo =
55
+ (typeof window !== "undefined" &&
56
+ new URLSearchParams(window.location.search).get("redirectTo")?.trim()) ||
57
+ mergedConfig.redirectTo
58
+
59
+ return (
60
+ <AuthContext.Provider value={mergedConfig}>
61
+ <QueryClientProvider client={resolvedQueryClient}>
62
+ {children}
63
+ </QueryClientProvider>
64
+ </AuthContext.Provider>
65
+ )
66
+ }
67
+
68
+ /**
69
+ * Accesses the current authentication configuration from AuthContext.
70
+ *
71
+ * @returns The merged authentication configuration provided by AuthProvider.
72
+ * @throws If no AuthProvider is present in the component tree.
73
+ */
74
+ export function useAuth() {
75
+ const context = useContext(AuthContext)
76
+
77
+ if (!context) {
78
+ throw new Error("[Better Auth UI] AuthProvider is required")
79
+ }
80
+
81
+ return context
82
+ }
@@ -0,0 +1,381 @@
1
+ import {
2
+ Body,
3
+ Button,
4
+ Container,
5
+ Head,
6
+ Heading,
7
+ Hr,
8
+ Html,
9
+ Img,
10
+ Link,
11
+ Preview,
12
+ pixelBasedPreset,
13
+ Section,
14
+ Tailwind,
15
+ Text
16
+ } from "@react-email/components"
17
+ import type { ReactNode } from "react"
18
+
19
+ import { cn } from "../../lib/utils"
20
+ import {
21
+ type EmailClassNames,
22
+ type EmailColors,
23
+ EmailStyles
24
+ } from "./email-styles"
25
+
26
+ const emailChangedEmailLocalization = {
27
+ YOUR_EMAIL_ADDRESS_HAS_BEEN_CHANGED: "Your email address has been changed",
28
+ LOGO: "Logo",
29
+ EMAIL_ADDRESS_CHANGED: "Email address changed",
30
+ EMAIL_ADDRESS_FOR_YOUR_ACCOUNT_CHANGED:
31
+ "The email address for your {appName} account has been changed.",
32
+ PREVIOUS_EMAIL: "Previous email:",
33
+ NEW_EMAIL: "New email:",
34
+ IF_YOU_MADE_THIS_CHANGE:
35
+ "If you made this change, you can safely ignore this email.",
36
+ I_DIDNT_MAKE_THIS_CHANGE: "I didn't make this change",
37
+ EMAIL_SENT_BY: "Email sent by {appName}.",
38
+ IF_YOU_DIDNT_AUTHORIZE_THIS_CHANGE:
39
+ "If you didn't authorize this change, please contact support immediately {supportEmail} to secure your account.",
40
+ POWERED_BY_BETTER_AUTH: "Powered by {betterAuth}"
41
+ }
42
+
43
+ /**
44
+ * Localization strings for the EmailChangedEmail component.
45
+ *
46
+ * Contains all text content used in the email changed notification email template.
47
+ */
48
+ export type EmailChangedEmailLocalization = typeof emailChangedEmailLocalization
49
+
50
+ /**
51
+ * Props for the EmailChangedEmail component.
52
+ */
53
+ export interface EmailChangedEmailProps {
54
+ /** The previous email address that was changed */
55
+ oldEmail?: string
56
+ /** The new email address */
57
+ newEmail?: string
58
+ /** URL to revert the email change if unauthorized */
59
+ revertURL?: string
60
+ /** Name of the application sending the email */
61
+ appName?: string
62
+ /** Support email address for security concerns */
63
+ supportEmail?: string
64
+ /** Logo URL(s) - a single string or light/dark variants. If omitted, no logo is shown. */
65
+ logoURL?: string | { light: string; dark: string }
66
+ /** Custom CSS class names for styling specific parts of the email */
67
+ classNames?: EmailClassNames
68
+ /** Custom color scheme for light and dark modes */
69
+ colors?: EmailColors
70
+ /** Whether to show the "Powered by better-auth" footer */
71
+ poweredBy?: boolean
72
+ /** Whether to enable dark mode support */
73
+ darkMode?: boolean
74
+ /** Additional React nodes to inject into the email head */
75
+ head?: ReactNode
76
+ /**
77
+ * Localization overrides for customizing email text
78
+ * @remarks `EmailChangedEmailLocalization`
79
+ */
80
+ localization?: Partial<EmailChangedEmailLocalization>
81
+ }
82
+
83
+ /**
84
+ * Email template component that notifies users when their email address has been changed.
85
+ *
86
+ * This email includes:
87
+ * - Display of both old and new email addresses
88
+ * - Revert action button if unauthorized change occurred
89
+ * - Security information and support contact details
90
+ * - Customizable branding and styling
91
+ * - Support for light/dark mode themes
92
+ *
93
+ * @example
94
+ * ```tsx
95
+ * <EmailChangedEmail
96
+ * oldEmail="old@example.com"
97
+ * newEmail="new@example.com"
98
+ * revertURL="https://example.com/revert?token=abc123"
99
+ * appName="My App"
100
+ * supportEmail="support@example.com"
101
+ * logoURL="https://example.com/logo.png"
102
+ * darkMode={true}
103
+ * />
104
+ * ```
105
+ */
106
+ export const EmailChangedEmail = ({
107
+ oldEmail,
108
+ newEmail,
109
+ revertURL,
110
+ appName,
111
+ supportEmail,
112
+ logoURL,
113
+ colors,
114
+ classNames,
115
+ darkMode = true,
116
+ poweredBy,
117
+ head,
118
+ ...props
119
+ }: EmailChangedEmailProps) => {
120
+ const localization = {
121
+ ...EmailChangedEmail.localization,
122
+ ...props.localization
123
+ }
124
+
125
+ const previewText = localization.YOUR_EMAIL_ADDRESS_HAS_BEEN_CHANGED
126
+
127
+ return (
128
+ <Html>
129
+ <Head>
130
+ <meta content="light dark" name="color-scheme" />
131
+ <meta content="light dark" name="supported-color-schemes" />
132
+
133
+ <EmailStyles colors={colors} darkMode={darkMode} />
134
+
135
+ {head}
136
+ </Head>
137
+
138
+ <Preview>{previewText}</Preview>
139
+
140
+ <Tailwind config={{ presets: [pixelBasedPreset] }}>
141
+ <Body className={cn("bg-background font-sans", classNames?.body)}>
142
+ <Container
143
+ className={cn(
144
+ "mx-auto my-auto max-w-xl px-2 py-10",
145
+ classNames?.container
146
+ )}
147
+ >
148
+ <Section
149
+ className={cn(
150
+ "bg-card text-card-foreground rounded-none border border-border p-8",
151
+ classNames?.card
152
+ )}
153
+ >
154
+ {logoURL &&
155
+ (typeof logoURL === "string" ? (
156
+ <Img
157
+ src={logoURL}
158
+ width={48}
159
+ height={48}
160
+ alt={appName || localization.LOGO}
161
+ className={cn("mx-auto mb-8", classNames?.logo)}
162
+ />
163
+ ) : (
164
+ <>
165
+ <Img
166
+ src={logoURL.light}
167
+ width={48}
168
+ height={48}
169
+ alt={appName || localization.LOGO}
170
+ className={cn(
171
+ "mx-auto mb-8 logo-light",
172
+ classNames?.logo
173
+ )}
174
+ />
175
+ <Img
176
+ src={logoURL.dark}
177
+ width={48}
178
+ height={48}
179
+ alt={appName || localization.LOGO}
180
+ className={cn(
181
+ "hidden mx-auto mb-8 logo-dark",
182
+ classNames?.logo
183
+ )}
184
+ />
185
+ </>
186
+ ))}
187
+
188
+ <Heading
189
+ className={cn(
190
+ "m-0 mb-5 text-2xl font-semibold",
191
+ classNames?.title
192
+ )}
193
+ >
194
+ {localization.EMAIL_ADDRESS_CHANGED}
195
+ </Heading>
196
+
197
+ <Text className={cn("text-sm font-normal", classNames?.content)}>
198
+ {localization.EMAIL_ADDRESS_FOR_YOUR_ACCOUNT_CHANGED.replace(
199
+ "{appName}",
200
+ appName || ""
201
+ )
202
+ .replace(/\s{2,}/g, " ")
203
+ .replace(" .", ".")}
204
+ </Text>
205
+
206
+ {(oldEmail || newEmail) && (
207
+ <Section
208
+ className={cn(
209
+ "my-6 border border-border bg-muted p-4",
210
+ classNames?.codeBlock
211
+ )}
212
+ >
213
+ {oldEmail && (
214
+ <>
215
+ <Text
216
+ className={cn(
217
+ "m-0 mb-2 text-xs text-muted-foreground",
218
+ classNames?.description
219
+ )}
220
+ >
221
+ {localization.PREVIOUS_EMAIL}
222
+ </Text>
223
+
224
+ <Text
225
+ className={cn(
226
+ "m-0 mb-4 text-sm font-semibold",
227
+ classNames?.content
228
+ )}
229
+ >
230
+ {oldEmail}
231
+ </Text>
232
+ </>
233
+ )}
234
+
235
+ {newEmail && (
236
+ <>
237
+ <Text
238
+ className={cn(
239
+ "m-0 mb-2 text-xs text-muted-foreground",
240
+ classNames?.description
241
+ )}
242
+ >
243
+ {localization.NEW_EMAIL}
244
+ </Text>
245
+
246
+ <Text
247
+ className={cn(
248
+ "m-0 text-sm font-semibold text-primary",
249
+ classNames?.content
250
+ )}
251
+ >
252
+ {newEmail}
253
+ </Text>
254
+ </>
255
+ )}
256
+ </Section>
257
+ )}
258
+
259
+ <Text className={cn("text-sm font-normal", classNames?.content)}>
260
+ {localization.IF_YOU_MADE_THIS_CHANGE}
261
+ </Text>
262
+
263
+ {revertURL && (
264
+ <Section className="my-6">
265
+ <Button
266
+ href={revertURL}
267
+ className={cn(
268
+ "inline-block whitespace-nowrap rounded-none text-sm font-medium py-2.5 px-6 bg-primary text-primary-foreground no-underline",
269
+ classNames?.button
270
+ )}
271
+ >
272
+ {localization.I_DIDNT_MAKE_THIS_CHANGE}
273
+ </Button>
274
+ </Section>
275
+ )}
276
+
277
+ <Hr
278
+ className={cn(
279
+ "my-6 w-full border border-solid border-border",
280
+ classNames?.separator
281
+ )}
282
+ />
283
+
284
+ {appName && (
285
+ <Text
286
+ className={cn(
287
+ "mb-3 text-xs text-muted-foreground",
288
+ classNames?.description
289
+ )}
290
+ >
291
+ {localization.EMAIL_SENT_BY.replace("{appName}", appName)}
292
+ </Text>
293
+ )}
294
+
295
+ <Text
296
+ className={cn(
297
+ "mt-3 text-xs text-muted-foreground",
298
+ classNames?.description
299
+ )}
300
+ >
301
+ {(() => {
302
+ const [beforeSupportEmail, afterSupportEmail] =
303
+ localization.IF_YOU_DIDNT_AUTHORIZE_THIS_CHANGE.split(
304
+ "{supportEmail}"
305
+ )
306
+
307
+ return supportEmail ? (
308
+ <>
309
+ {beforeSupportEmail}
310
+ <Link
311
+ href={`mailto:${supportEmail}`}
312
+ className={cn(
313
+ "text-primary underline",
314
+ classNames?.link
315
+ )}
316
+ >
317
+ {supportEmail}
318
+ </Link>
319
+ {afterSupportEmail}
320
+ </>
321
+ ) : (
322
+ localization.IF_YOU_DIDNT_AUTHORIZE_THIS_CHANGE.replace(
323
+ "{supportEmail}",
324
+ ""
325
+ )
326
+ .replace(/\s{2,}/g, " ")
327
+ .replace(" .", ".")
328
+ )
329
+ })()}
330
+ </Text>
331
+
332
+ {poweredBy && (
333
+ <Text
334
+ className={cn(
335
+ "mt-4 mb-0 text-center text-[11px] text-muted-foreground",
336
+ classNames?.poweredBy
337
+ )}
338
+ >
339
+ {(() => {
340
+ const [beforeBetterAuth, afterBetterAuth] =
341
+ localization.POWERED_BY_BETTER_AUTH.split("{betterAuth}")
342
+
343
+ return (
344
+ <>
345
+ {beforeBetterAuth}
346
+ <Link
347
+ href="https://better-auth.com"
348
+ className={cn(
349
+ "text-primary underline",
350
+ classNames?.link
351
+ )}
352
+ >
353
+ better-auth
354
+ </Link>
355
+ {afterBetterAuth}
356
+ </>
357
+ )
358
+ })()}
359
+ </Text>
360
+ )}
361
+ </Section>
362
+ </Container>
363
+ </Body>
364
+ </Tailwind>
365
+ </Html>
366
+ )
367
+ }
368
+
369
+ EmailChangedEmail.localization = emailChangedEmailLocalization
370
+
371
+ EmailChangedEmail.PreviewProps = {
372
+ oldEmail: "old@example.com",
373
+ newEmail: "new@example.com",
374
+ supportEmail: "support@example.com",
375
+ revertURL: "https://better-auth-ui.com/auth/revert-email?token=example-token",
376
+ appName: "Better Auth",
377
+ poweredBy: true,
378
+ darkMode: true
379
+ } as EmailChangedEmailProps
380
+
381
+ export default EmailChangedEmail