@better-auth-ui/heroui 1.6.0 → 1.6.1

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 (143) hide show
  1. package/dist/components/auth/magic-link.js +3 -2
  2. package/dist/components/auth/passkey-button.d.ts +4 -0
  3. package/dist/components/auth/passkey-button.js +13 -0
  4. package/dist/components/auth/sign-in.js +3 -2
  5. package/dist/components/settings/security/passkey.d.ts +8 -0
  6. package/dist/components/settings/security/passkey.js +14 -0
  7. package/dist/components/settings/security/passkeys.d.ts +6 -0
  8. package/dist/components/settings/security/passkeys.js +21 -0
  9. package/dist/components/settings/security/security-settings.js +3 -2
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.js +2 -0
  12. package/package.json +6 -1
  13. package/src/components/auth/magic-link.tsx +4 -0
  14. package/src/components/auth/passkey-button.tsx +36 -0
  15. package/src/components/auth/sign-in.tsx +4 -0
  16. package/src/components/settings/security/passkey.tsx +51 -0
  17. package/src/components/settings/security/passkeys.tsx +104 -0
  18. package/src/components/settings/security/security-settings.tsx +3 -1
  19. package/src/index.tsx +2 -0
  20. package/dist/components/account/account.d.ts +0 -18
  21. package/dist/components/account/account.js +0 -24
  22. package/dist/components/account/settings/account-settings.d.ts +0 -5
  23. package/dist/components/account/settings/account-settings.js +0 -6
  24. package/dist/components/account/settings/settings.d.ts +0 -5
  25. package/dist/components/account/settings/settings.js +0 -5
  26. package/dist/components/account/settings/user-profile.d.ts +0 -5
  27. package/dist/components/account/settings/user-profile.js +0 -20
  28. package/dist/components/settings/account/accounts.d.ts +0 -14
  29. package/dist/components/settings/account/accounts.js +0 -26
  30. package/dist/components/settings/account/theme-selector.d.ts +0 -16
  31. package/dist/components/settings/account/theme-selector.js +0 -33
  32. package/dist/components/settings/account/theme-settings.d.ts +0 -16
  33. package/dist/components/settings/account/theme-settings.js +0 -31
  34. package/dist/components/settings/account-settings.d.ts +0 -5
  35. package/dist/components/settings/account-settings.js +0 -6
  36. package/dist/components/settings/account.d.ts +0 -18
  37. package/dist/components/settings/account.js +0 -24
  38. package/dist/components/settings/security/connected-account.d.ts +0 -16
  39. package/dist/components/settings/security/connected-account.js +0 -46
  40. package/dist/components/settings/security/connected-accounts.d.ts +0 -15
  41. package/dist/components/settings/security/connected-accounts.js +0 -31
  42. package/dist/components/settings/security/sessions.d.ts +0 -14
  43. package/dist/components/settings/security/sessions.js +0 -40
  44. package/dist/components/settings/settings/account-settings.d.ts +0 -5
  45. package/dist/components/settings/settings/account-settings.js +0 -6
  46. package/dist/components/settings/settings/user-profile.d.ts +0 -5
  47. package/dist/components/settings/settings/user-profile.js +0 -20
  48. package/dist/components/settings/user-profile.d.ts +0 -5
  49. package/dist/components/settings/user-profile.js +0 -20
  50. package/dist/components/user/switch-account-popover.d.ts +0 -10
  51. package/dist/components/user/switch-account-popover.js +0 -25
  52. package/dist/components/user/switch-account-submenu.d.ts +0 -10
  53. package/dist/components/user/switch-account-submenu.js +0 -25
  54. package/dist/hooks/use-auth.d.ts +0 -2
  55. package/dist/hooks/use-auth.js +0 -8
  56. package/dist/hooks/use-redirect-to.d.ts +0 -8
  57. package/dist/hooks/use-redirect-to.js +0 -19
  58. package/dist/hooks/use-sign-in.d.ts +0 -8
  59. package/dist/hooks/use-sign-in.js +0 -53
  60. package/dist/lib/utils.d.ts +0 -2
  61. package/dist/lib/utils.js +0 -5
  62. package/dist/server.d.ts +0 -1
  63. package/dist/server.js +0 -1
  64. package/dist/src/components/auth/auth-provider.d.ts +0 -8
  65. package/dist/src/components/auth/auth-provider.js +0 -13
  66. package/dist/src/components/auth/auth.d.ts +0 -22
  67. package/dist/src/components/auth/auth.js +0 -42
  68. package/dist/src/components/auth/field-separator.d.ts +0 -4
  69. package/dist/src/components/auth/field-separator.js +0 -5
  70. package/dist/src/components/auth/forgot-password.d.ts +0 -15
  71. package/dist/src/components/auth/forgot-password.js +0 -29
  72. package/dist/src/components/auth/magic-link-button.d.ts +0 -13
  73. package/dist/src/components/auth/magic-link-button.js +0 -20
  74. package/dist/src/components/auth/magic-link.d.ts +0 -17
  75. package/dist/src/components/auth/magic-link.js +0 -37
  76. package/dist/src/components/auth/provider-buttons.d.ts +0 -19
  77. package/dist/src/components/auth/provider-buttons.js +0 -35
  78. package/dist/src/components/auth/reset-password.d.ts +0 -11
  79. package/dist/src/components/auth/reset-password.js +0 -59
  80. package/dist/src/components/auth/sign-in.d.ts +0 -14
  81. package/dist/src/components/auth/sign-in.js +0 -58
  82. package/dist/src/components/auth/sign-out.d.ts +0 -11
  83. package/dist/src/components/auth/sign-out.js +0 -34
  84. package/dist/src/components/auth/sign-up.d.ts +0 -19
  85. package/dist/src/components/auth/sign-up.js +0 -65
  86. package/dist/src/components/email/email-changed-email.d.ts +0 -3
  87. package/dist/src/components/email/email-changed-email.js +0 -23
  88. package/dist/src/components/email/email-verification-email.d.ts +0 -3
  89. package/dist/src/components/email/email-verification-email.js +0 -23
  90. package/dist/src/components/email/magic-link-email.d.ts +0 -3
  91. package/dist/src/components/email/magic-link-email.js +0 -23
  92. package/dist/src/components/email/new-device-email.d.ts +0 -3
  93. package/dist/src/components/email/new-device-email.js +0 -23
  94. package/dist/src/components/email/otp-email.d.ts +0 -3
  95. package/dist/src/components/email/otp-email.js +0 -22
  96. package/dist/src/components/email/password-changed-email.d.ts +0 -3
  97. package/dist/src/components/email/password-changed-email.js +0 -23
  98. package/dist/src/components/email/reset-password-email.d.ts +0 -3
  99. package/dist/src/components/email/reset-password-email.js +0 -23
  100. package/dist/src/components/settings/account/account-settings.d.ts +0 -13
  101. package/dist/src/components/settings/account/account-settings.js +0 -19
  102. package/dist/src/components/settings/account/appearance.d.ts +0 -16
  103. package/dist/src/components/settings/account/appearance.js +0 -28
  104. package/dist/src/components/settings/account/change-email.d.ts +0 -15
  105. package/dist/src/components/settings/account/change-email.js +0 -35
  106. package/dist/src/components/settings/account/manage-account.d.ts +0 -19
  107. package/dist/src/components/settings/account/manage-account.js +0 -27
  108. package/dist/src/components/settings/account/manage-accounts.d.ts +0 -14
  109. package/dist/src/components/settings/account/manage-accounts.js +0 -27
  110. package/dist/src/components/settings/account/user-profile.d.ts +0 -13
  111. package/dist/src/components/settings/account/user-profile.js +0 -29
  112. package/dist/src/components/settings/security/active-session.d.ts +0 -14
  113. package/dist/src/components/settings/security/active-session.js +0 -35
  114. package/dist/src/components/settings/security/active-sessions.d.ts +0 -14
  115. package/dist/src/components/settings/security/active-sessions.js +0 -29
  116. package/dist/src/components/settings/security/change-password.d.ts +0 -15
  117. package/dist/src/components/settings/security/change-password.js +0 -57
  118. package/dist/src/components/settings/security/linked-account.d.ts +0 -16
  119. package/dist/src/components/settings/security/linked-account.js +0 -46
  120. package/dist/src/components/settings/security/linked-accounts.d.ts +0 -15
  121. package/dist/src/components/settings/security/linked-accounts.js +0 -31
  122. package/dist/src/components/settings/security/security-settings.d.ts +0 -15
  123. package/dist/src/components/settings/security/security-settings.js +0 -18
  124. package/dist/src/components/settings/settings.d.ts +0 -29
  125. package/dist/src/components/settings/settings.js +0 -39
  126. package/dist/src/components/user/switch-account-item.d.ts +0 -16
  127. package/dist/src/components/user/switch-account-item.js +0 -14
  128. package/dist/src/components/user/switch-account-menu.d.ts +0 -10
  129. package/dist/src/components/user/switch-account-menu.js +0 -23
  130. package/dist/src/components/user/user-avatar.d.ts +0 -24
  131. package/dist/src/components/user/user-avatar.js +0 -31
  132. package/dist/src/components/user/user-button.d.ts +0 -21
  133. package/dist/src/components/user/user-button.js +0 -24
  134. package/dist/src/components/user/user-view.d.ts +0 -21
  135. package/dist/src/components/user/user-view.js +0 -24
  136. package/dist/src/core.d.ts +0 -1
  137. package/dist/src/core.js +0 -1
  138. package/dist/src/index.d.ts +0 -31
  139. package/dist/src/index.js +0 -32
  140. package/dist/src/lib/utils.d.ts +0 -2
  141. package/dist/src/lib/utils.js +0 -5
  142. package/dist/src/react-exports.d.ts +0 -1
  143. package/dist/src/react-exports.js +0 -1
@@ -4,6 +4,7 @@ import { Button, Card, cn, Description, FieldError, Form, Input, Label, Link, Sp
4
4
  import { useState } from "react";
5
5
  import { FieldSeparator } from "./field-separator";
6
6
  import { MagicLinkButton } from "./magic-link-button";
7
+ import { PasskeyButton } from "./passkey-button";
7
8
  import { ProviderButtons } from "./provider-buttons";
8
9
  /**
9
10
  * Render a card-based sign-in form that sends an email magic link and optionally shows social provider buttons.
@@ -14,7 +15,7 @@ import { ProviderButtons } from "./provider-buttons";
14
15
  * @returns The magic-link sign-in UI as a JSX element
15
16
  */
16
17
  export function MagicLink({ className, socialLayout, socialPosition = "bottom", variant, ...props }) {
17
- const { basePaths, baseURL, localization, redirectTo, socialProviders, viewPaths } = useAuth();
18
+ const { basePaths, baseURL, localization, passkey, redirectTo, socialProviders, viewPaths } = useAuth();
18
19
  const [email, setEmail] = useState("");
19
20
  const { mutate: signInMagicLink, isPending: magicLinkPending } = useSignInMagicLink({
20
21
  onError: (error) => toast.danger(error.error?.message || error.message),
@@ -39,5 +40,5 @@ export function MagicLink({ className, socialLayout, socialPosition = "bottom",
39
40
  signInMagicLink({ email, callbackURL: `${baseURL}${redirectTo}` });
40
41
  };
41
42
  const showSeparator = !!socialProviders?.length;
42
- return (_jsxs(Card, { className: cn("w-full max-w-sm p-4 md:p-6", className), variant: variant, ...props, children: [_jsx(Card.Header, { children: _jsx(Card.Title, { className: "text-xl font-semibold mb-1", children: localization.auth.signIn }) }), _jsxs(Card.Content, { className: "gap-4", children: [socialPosition === "top" && (_jsxs(_Fragment, { children: [!!socialProviders?.length && (_jsx(ProviderButtons, { socialLayout: socialLayout, signInSocial: signInSocial, isPending: isPending })), showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or }))] })), _jsxs(Form, { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs(TextField, { name: "email", type: "email", autoComplete: "email", isDisabled: isPending, value: email, onChange: setEmail, children: [_jsx(Label, { children: localization.auth.email }), _jsx(Input, { placeholder: localization.auth.emailPlaceholder, required: true, variant: variant === "transparent" ? "primary" : "secondary" }), _jsx(FieldError, {})] }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs(Button, { type: "submit", className: "w-full", isPending: isPending, children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), localization.auth.sendMagicLink] }), _jsx(MagicLinkButton, { view: "magicLink", isPending: isPending })] })] }), socialPosition === "bottom" && (_jsxs(_Fragment, { children: [showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or })), !!socialProviders?.length && (_jsx(ProviderButtons, { socialLayout: socialLayout, signInSocial: signInSocial, isPending: isPending }))] }))] }), _jsx(Card.Footer, { className: "flex-col", children: _jsxs(Description, { className: "text-sm", children: [localization.auth.needToCreateAnAccount, " ", _jsx(Link, { href: `${basePaths.auth}/${viewPaths.auth.signUp}`, className: "text-accent decoration-accent no-underline hover:underline", children: localization.auth.signUp })] }) })] }));
43
+ return (_jsxs(Card, { className: cn("w-full max-w-sm p-4 md:p-6", className), variant: variant, ...props, children: [_jsx(Card.Header, { children: _jsx(Card.Title, { className: "text-xl font-semibold mb-1", children: localization.auth.signIn }) }), _jsxs(Card.Content, { className: "gap-4", children: [socialPosition === "top" && (_jsxs(_Fragment, { children: [!!socialProviders?.length && (_jsx(ProviderButtons, { socialLayout: socialLayout, signInSocial: signInSocial, isPending: isPending })), showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or }))] })), _jsxs(Form, { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs(TextField, { name: "email", type: "email", autoComplete: "email", isDisabled: isPending, value: email, onChange: setEmail, children: [_jsx(Label, { children: localization.auth.email }), _jsx(Input, { placeholder: localization.auth.emailPlaceholder, required: true, variant: variant === "transparent" ? "primary" : "secondary" }), _jsx(FieldError, {})] }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs(Button, { type: "submit", className: "w-full", isPending: isPending, children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), localization.auth.sendMagicLink] }), _jsx(MagicLinkButton, { view: "magicLink", isPending: isPending }), passkey && _jsx(PasskeyButton, { isPending: isPending })] })] }), socialPosition === "bottom" && (_jsxs(_Fragment, { children: [showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or })), !!socialProviders?.length && (_jsx(ProviderButtons, { socialLayout: socialLayout, signInSocial: signInSocial, isPending: isPending }))] }))] }), _jsx(Card.Footer, { className: "flex-col", children: _jsxs(Description, { className: "text-sm", children: [localization.auth.needToCreateAnAccount, " ", _jsx(Link, { href: `${basePaths.auth}/${viewPaths.auth.signUp}`, className: "text-accent decoration-accent no-underline hover:underline", children: localization.auth.signUp })] }) })] }));
43
44
  }
@@ -0,0 +1,4 @@
1
+ export type PasskeyButtonProps = {
2
+ isPending: boolean;
3
+ };
4
+ export declare function PasskeyButton({ isPending }: PasskeyButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAuth, useSignInPasskey } from "@better-auth-ui/react";
3
+ import { Fingerprint } from "@gravity-ui/icons";
4
+ import { Button, Spinner, toast } from "@heroui/react";
5
+ export function PasskeyButton({ isPending }) {
6
+ const { localization, redirectTo, navigate } = useAuth();
7
+ const { mutate: signInPasskey, isPending: passkeyPending } = useSignInPasskey({
8
+ onError: (error) => toast.danger(error.error?.message || error.message),
9
+ onSuccess: () => navigate({ to: redirectTo })
10
+ });
11
+ const isDisabled = isPending || passkeyPending;
12
+ return (_jsxs(Button, { className: "w-full", variant: "tertiary", isDisabled: isDisabled, isPending: passkeyPending, onPress: () => signInPasskey(), children: [passkeyPending ? _jsx(Spinner, { color: "current", size: "sm" }) : _jsx(Fingerprint, {}), localization.auth.continueWith.replace("{{provider}}", localization.auth.passkey)] }));
13
+ }
@@ -4,6 +4,7 @@ import { Button, Card, Checkbox, cn, Description, FieldError, Form, Input, Label
4
4
  import { useState } from "react";
5
5
  import { FieldSeparator } from "./field-separator";
6
6
  import { MagicLinkButton } from "./magic-link-button";
7
+ import { PasskeyButton } from "./passkey-button";
7
8
  import { ProviderButtons } from "./provider-buttons";
8
9
  /**
9
10
  * Render the sign-in UI using auth context for configuration and localization.
@@ -11,7 +12,7 @@ import { ProviderButtons } from "./provider-buttons";
11
12
  * @returns The sign-in JSX element containing email/password fields, optional magic-link button, and social provider buttons.
12
13
  */
13
14
  export function SignIn({ className, socialLayout, socialPosition = "bottom", variant, ...props }) {
14
- const { basePaths, baseURL, emailAndPassword, localization, magicLink, redirectTo, socialProviders, viewPaths, navigate } = useAuth();
15
+ const { basePaths, baseURL, emailAndPassword, localization, magicLink, passkey, redirectTo, socialProviders, viewPaths, navigate } = useAuth();
15
16
  const [password, setPassword] = useState("");
16
17
  const { mutate: sendVerificationEmail } = useSendVerificationEmail({
17
18
  onError: (error) => toast.danger(error.error?.message || error.message),
@@ -60,5 +61,5 @@ export function SignIn({ className, socialLayout, socialPosition = "bottom", var
60
61
  };
61
62
  const isPending = signInPending || socialPending || socialRedirecting;
62
63
  const showSeparator = emailAndPassword?.enabled && !!socialProviders?.length;
63
- return (_jsxs(Card, { className: cn("w-full max-w-sm gap-4 md:p-6", className), variant: variant, ...props, children: [_jsx(Card.Header, { children: _jsx(Card.Title, { className: "text-xl font-semibold mb-1", children: localization.auth.signIn }) }), _jsxs(Card.Content, { className: "gap-4", children: [socialPosition === "top" && (_jsxs(_Fragment, { children: [!!socialProviders?.length && (_jsx(ProviderButtons, { socialLayout: socialLayout, signInSocial: signInSocial, isPending: isPending })), showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or }))] })), emailAndPassword?.enabled && (_jsxs(Form, { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs(TextField, { name: "email", type: "email", autoComplete: "email", isDisabled: isPending, children: [_jsx(Label, { children: localization.auth.email }), _jsx(Input, { placeholder: localization.auth.emailPlaceholder, variant: variant === "transparent" ? "primary" : "secondary", required: true }), _jsx(FieldError, {})] }), _jsxs(TextField, { minLength: emailAndPassword?.minPasswordLength, maxLength: emailAndPassword?.maxPasswordLength, name: "password", type: "password", autoComplete: "current-password", isDisabled: isPending, value: password, onChange: setPassword, children: [_jsx(Label, { children: localization.auth.password }), _jsx(Input, { placeholder: localization.auth.passwordPlaceholder, variant: variant === "transparent" ? "primary" : "secondary", required: true }), _jsx(FieldError, {})] }), emailAndPassword?.rememberMe && (_jsxs(Checkbox, { name: "rememberMe", isDisabled: isPending, variant: variant === "transparent" ? "primary" : "secondary", children: [_jsx(Checkbox.Control, { children: _jsx(Checkbox.Indicator, {}) }), _jsx(Checkbox.Content, { children: _jsx(Label, { children: localization.auth.rememberMe }) })] })), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs(Button, { type: "submit", className: "w-full", isPending: isPending, children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), localization.auth.signIn] }), magicLink && (_jsx(MagicLinkButton, { view: "signIn", isPending: isPending }))] })] })), socialPosition === "bottom" && (_jsxs(_Fragment, { children: [showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or })), !!socialProviders?.length && (_jsx(ProviderButtons, { socialLayout: socialLayout, signInSocial: signInSocial, isPending: isPending }))] }))] }), _jsxs(Card.Footer, { className: "flex-col gap-3", children: [emailAndPassword?.forgotPassword && (_jsx(Link, { href: `${basePaths.auth}/${viewPaths.auth.forgotPassword}`, className: "no-underline hover:underline", children: localization.auth.forgotPasswordLink })), emailAndPassword?.enabled && (_jsxs(Description, { className: "text-sm", children: [localization.auth.needToCreateAnAccount, " ", _jsx(Link, { href: `${basePaths.auth}/${viewPaths.auth.signUp}`, className: "text-accent no-underline hover:underline decoration-accent-hover", children: localization.auth.signUp })] }))] })] }));
64
+ return (_jsxs(Card, { className: cn("w-full max-w-sm gap-4 md:p-6", className), variant: variant, ...props, children: [_jsx(Card.Header, { children: _jsx(Card.Title, { className: "text-xl font-semibold mb-1", children: localization.auth.signIn }) }), _jsxs(Card.Content, { className: "gap-4", children: [socialPosition === "top" && (_jsxs(_Fragment, { children: [!!socialProviders?.length && (_jsx(ProviderButtons, { socialLayout: socialLayout, signInSocial: signInSocial, isPending: isPending })), showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or }))] })), emailAndPassword?.enabled && (_jsxs(Form, { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs(TextField, { name: "email", type: "email", autoComplete: "email", isDisabled: isPending, children: [_jsx(Label, { children: localization.auth.email }), _jsx(Input, { placeholder: localization.auth.emailPlaceholder, variant: variant === "transparent" ? "primary" : "secondary", required: true }), _jsx(FieldError, {})] }), _jsxs(TextField, { minLength: emailAndPassword?.minPasswordLength, maxLength: emailAndPassword?.maxPasswordLength, name: "password", type: "password", autoComplete: "current-password", isDisabled: isPending, value: password, onChange: setPassword, children: [_jsx(Label, { children: localization.auth.password }), _jsx(Input, { placeholder: localization.auth.passwordPlaceholder, variant: variant === "transparent" ? "primary" : "secondary", required: true }), _jsx(FieldError, {})] }), emailAndPassword?.rememberMe && (_jsxs(Checkbox, { name: "rememberMe", isDisabled: isPending, variant: variant === "transparent" ? "primary" : "secondary", children: [_jsx(Checkbox.Control, { children: _jsx(Checkbox.Indicator, {}) }), _jsx(Checkbox.Content, { children: _jsx(Label, { children: localization.auth.rememberMe }) })] })), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs(Button, { type: "submit", className: "w-full", isPending: isPending, children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), localization.auth.signIn] }), magicLink && (_jsx(MagicLinkButton, { view: "signIn", isPending: isPending })), passkey && _jsx(PasskeyButton, { isPending: isPending })] })] })), socialPosition === "bottom" && (_jsxs(_Fragment, { children: [showSeparator && (_jsx(FieldSeparator, { children: localization.auth.or })), !!socialProviders?.length && (_jsx(ProviderButtons, { socialLayout: socialLayout, signInSocial: signInSocial, isPending: isPending }))] }))] }), _jsxs(Card.Footer, { className: "flex-col gap-3", children: [emailAndPassword?.forgotPassword && (_jsx(Link, { href: `${basePaths.auth}/${viewPaths.auth.forgotPassword}`, className: "no-underline hover:underline", children: localization.auth.forgotPasswordLink })), emailAndPassword?.enabled && (_jsxs(Description, { className: "text-sm", children: [localization.auth.needToCreateAnAccount, " ", _jsx(Link, { href: `${basePaths.auth}/${viewPaths.auth.signUp}`, className: "text-accent no-underline hover:underline decoration-accent-hover", children: localization.auth.signUp })] }))] })] }));
64
65
  }
@@ -0,0 +1,8 @@
1
+ export type PasskeyProps = {
2
+ passkey: {
3
+ id: string;
4
+ name?: string | null;
5
+ createdAt: Date;
6
+ };
7
+ };
8
+ export declare function Passkey({ passkey }: PasskeyProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAuth, useDeletePasskey } from "@better-auth-ui/react";
3
+ import { Fingerprint, Xmark } from "@gravity-ui/icons";
4
+ import { Button, Spinner, toast } from "@heroui/react";
5
+ export function Passkey({ passkey }) {
6
+ const { localization } = useAuth();
7
+ const { mutate: deletePasskey, isPending } = useDeletePasskey({
8
+ onError: (error) => toast.danger(error.error?.message || error.message)
9
+ });
10
+ return (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex size-10 shrink-0 items-center justify-center rounded-xl bg-surface-secondary", children: _jsx(Fingerprint, { className: "size-4.5" }) }), _jsxs("div", { className: "flex flex-col min-w-0", children: [_jsx("span", { className: "text-sm font-medium leading-tight", children: passkey.name || localization.auth.passkey }), _jsx("span", { className: "text-xs text-muted", children: new Date(passkey.createdAt).toLocaleString(undefined, {
11
+ dateStyle: "medium",
12
+ timeStyle: "short"
13
+ }) })] }), _jsxs(Button, { className: "ml-auto shrink-0", variant: "outline", size: "sm", isPending: isPending, onPress: () => deletePasskey({ id: passkey.id }), children: [isPending ? _jsx(Spinner, { color: "current", size: "sm" }) : _jsx(Xmark, {}), localization.settings.delete] })] }));
14
+ }
@@ -0,0 +1,6 @@
1
+ import { type CardProps } from "@heroui/react";
2
+ export type PasskeysProps = {
3
+ className?: string;
4
+ variant?: CardProps["variant"];
5
+ };
6
+ export declare function Passkeys({ className, variant, ...props }: PasskeysProps & CardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useAddPasskey, useAuth, useListUserPasskeys } from "@better-auth-ui/react";
3
+ import { Button, Card, cn, Skeleton, Spinner, toast } from "@heroui/react";
4
+ import { Passkey } from "./passkey";
5
+ export function Passkeys({ className, variant, ...props }) {
6
+ const { localization } = useAuth();
7
+ const { data: passkeys, isPending } = useListUserPasskeys({
8
+ throwOnError: (error) => {
9
+ if (error.error)
10
+ toast.danger(error.error.message);
11
+ return false;
12
+ }
13
+ });
14
+ const { mutate: addPasskey, isPending: isAdding } = useAddPasskey({
15
+ onError: (error) => toast.danger(error.error?.message || error.message)
16
+ });
17
+ return (_jsxs("div", { children: [_jsx("h2", { className: cn("text-sm font-semibold mb-3"), children: localization.settings.passkeys }), _jsx(Card, { className: cn(className), variant: variant, ...props, children: _jsxs(Card.Content, { className: "gap-0", children: [_jsxs("div", { 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.passkeysDescription }), _jsx("p", { className: "text-muted text-xs mt-0.5", children: localization.settings.passkeysInstructions })] }), _jsxs(Button, { className: "shrink-0", size: "sm", isPending: isAdding, isDisabled: isPending, onPress: () => addPasskey(), children: [isAdding && _jsx(Spinner, { color: "current", size: "sm" }), localization.settings.addPasskey] })] }), isPending ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "border-b border-dashed -mx-4 md:-mx-6 my-4" }), _jsx(PasskeySkeleton, {})] })) : (passkeys?.map((passkey) => (_jsxs("div", { children: [_jsx("div", { className: "border-b border-dashed -mx-4 md:-mx-6 my-4" }), _jsx(Passkey, { passkey: passkey })] }, passkey.id))))] }) })] }));
18
+ }
19
+ function PasskeySkeleton() {
20
+ 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-24 rounded-lg" }), _jsx(Skeleton, { className: "h-3 w-20 rounded-lg" })] })] }) }));
21
+ }
@@ -5,6 +5,7 @@ import { ActiveSessions } from "./active-sessions";
5
5
  import { ChangePassword } from "./change-password";
6
6
  import { DangerZone } from "./danger-zone";
7
7
  import { LinkedAccounts } from "./linked-accounts";
8
+ import { Passkeys } from "./passkeys";
8
9
  /**
9
10
  * Renders the security settings layout including password management, linked accounts, and active sessions.
10
11
  *
@@ -16,6 +17,6 @@ import { LinkedAccounts } from "./linked-accounts";
16
17
  * @returns The security settings container as a JSX element.
17
18
  */
18
19
  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 })] }));
20
+ const { deleteUser, emailAndPassword, passkey, socialProviders } = useAuth();
21
+ 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 }), passkey && _jsx(Passkeys, { variant: variant }), _jsx(ActiveSessions, { variant: variant }), deleteUser?.enabled && _jsx(DangerZone, { variant: variant })] }));
21
22
  }
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from "./components/auth/auth-provider";
3
3
  export * from "./components/auth/forgot-password";
4
4
  export * from "./components/auth/magic-link";
5
5
  export * from "./components/auth/magic-link-button";
6
+ export * from "./components/auth/passkey-button";
6
7
  export * from "./components/auth/provider-buttons";
7
8
  export * from "./components/auth/reset-password";
8
9
  export * from "./components/auth/sign-in";
@@ -26,6 +27,7 @@ export * from "./components/settings/security/change-password";
26
27
  export * from "./components/settings/security/danger-zone";
27
28
  export * from "./components/settings/security/delete-user";
28
29
  export * from "./components/settings/security/linked-accounts";
30
+ export * from "./components/settings/security/passkeys";
29
31
  export * from "./components/settings/security/security-settings";
30
32
  export * from "./components/settings/settings";
31
33
  export * from "./components/user/user-avatar";
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ export * from "./components/auth/auth-provider";
4
4
  export * from "./components/auth/forgot-password";
5
5
  export * from "./components/auth/magic-link";
6
6
  export * from "./components/auth/magic-link-button";
7
+ export * from "./components/auth/passkey-button";
7
8
  export * from "./components/auth/provider-buttons";
8
9
  export * from "./components/auth/reset-password";
9
10
  export * from "./components/auth/sign-in";
@@ -27,6 +28,7 @@ export * from "./components/settings/security/change-password";
27
28
  export * from "./components/settings/security/danger-zone";
28
29
  export * from "./components/settings/security/delete-user";
29
30
  export * from "./components/settings/security/linked-accounts";
31
+ export * from "./components/settings/security/passkeys";
30
32
  export * from "./components/settings/security/security-settings";
31
33
  export * from "./components/settings/settings";
32
34
  export * from "./components/user/user-avatar";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth-ui/heroui",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "tsc && bun styles",
@@ -57,6 +57,11 @@
57
57
  "react-dom": ">=19.2.5",
58
58
  "bowser": ">=2.11.0"
59
59
  },
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "https://github.com/better-auth-ui/better-auth-ui",
63
+ "directory": "packages/heroui"
64
+ },
60
65
  "publishConfig": {
61
66
  "access": "public"
62
67
  }
@@ -22,6 +22,7 @@ import { type SyntheticEvent, useState } from "react"
22
22
 
23
23
  import { FieldSeparator } from "./field-separator"
24
24
  import { MagicLinkButton } from "./magic-link-button"
25
+ import { PasskeyButton } from "./passkey-button"
25
26
  import { ProviderButtons, type SocialLayout } from "./provider-buttons"
26
27
 
27
28
  export type MagicLinkProps = {
@@ -50,6 +51,7 @@ export function MagicLink({
50
51
  basePaths,
51
52
  baseURL,
52
53
  localization,
54
+ passkey,
53
55
  redirectTo,
54
56
  socialProviders,
55
57
  viewPaths
@@ -145,6 +147,8 @@ export function MagicLink({
145
147
  </Button>
146
148
 
147
149
  <MagicLinkButton view="magicLink" isPending={isPending} />
150
+
151
+ {passkey && <PasskeyButton isPending={isPending} />}
148
152
  </div>
149
153
  </Form>
150
154
 
@@ -0,0 +1,36 @@
1
+ import { useAuth, useSignInPasskey } from "@better-auth-ui/react"
2
+ import { Fingerprint } from "@gravity-ui/icons"
3
+ import { Button, Spinner, toast } from "@heroui/react"
4
+
5
+ export type PasskeyButtonProps = {
6
+ isPending: boolean
7
+ }
8
+
9
+ export function PasskeyButton({ isPending }: PasskeyButtonProps) {
10
+ const { localization, redirectTo, navigate } = useAuth()
11
+
12
+ const { mutate: signInPasskey, isPending: passkeyPending } = useSignInPasskey(
13
+ {
14
+ onError: (error) => toast.danger(error.error?.message || error.message),
15
+ onSuccess: () => navigate({ to: redirectTo })
16
+ }
17
+ )
18
+
19
+ const isDisabled = isPending || passkeyPending
20
+
21
+ return (
22
+ <Button
23
+ className="w-full"
24
+ variant="tertiary"
25
+ isDisabled={isDisabled}
26
+ isPending={passkeyPending}
27
+ onPress={() => signInPasskey()}
28
+ >
29
+ {passkeyPending ? <Spinner color="current" size="sm" /> : <Fingerprint />}
30
+ {localization.auth.continueWith.replace(
31
+ "{{provider}}",
32
+ localization.auth.passkey
33
+ )}
34
+ </Button>
35
+ )
36
+ }
@@ -24,6 +24,7 @@ import { type SyntheticEvent, useState } from "react"
24
24
 
25
25
  import { FieldSeparator } from "./field-separator"
26
26
  import { MagicLinkButton } from "./magic-link-button"
27
+ import { PasskeyButton } from "./passkey-button"
27
28
  import { ProviderButtons, type SocialLayout } from "./provider-buttons"
28
29
 
29
30
  export interface SignInProps {
@@ -51,6 +52,7 @@ export function SignIn({
51
52
  emailAndPassword,
52
53
  localization,
53
54
  magicLink,
55
+ passkey,
54
56
  redirectTo,
55
57
  socialProviders,
56
58
  viewPaths,
@@ -212,6 +214,8 @@ export function SignIn({
212
214
  {magicLink && (
213
215
  <MagicLinkButton view="signIn" isPending={isPending} />
214
216
  )}
217
+
218
+ {passkey && <PasskeyButton isPending={isPending} />}
215
219
  </div>
216
220
  </Form>
217
221
  )}
@@ -0,0 +1,51 @@
1
+ import { useAuth, useDeletePasskey } from "@better-auth-ui/react"
2
+ import { Fingerprint, Xmark } from "@gravity-ui/icons"
3
+ import { Button, Spinner, toast } from "@heroui/react"
4
+
5
+ export type PasskeyProps = {
6
+ passkey: {
7
+ id: string
8
+ name?: string | null
9
+ createdAt: Date
10
+ }
11
+ }
12
+
13
+ export function Passkey({ passkey }: PasskeyProps) {
14
+ const { localization } = useAuth()
15
+
16
+ const { mutate: deletePasskey, isPending } = useDeletePasskey({
17
+ onError: (error) => toast.danger(error.error?.message || error.message)
18
+ })
19
+
20
+ return (
21
+ <div className="flex items-center gap-3">
22
+ <div className="flex size-10 shrink-0 items-center justify-center rounded-xl bg-surface-secondary">
23
+ <Fingerprint className="size-4.5" />
24
+ </div>
25
+
26
+ <div className="flex flex-col min-w-0">
27
+ <span className="text-sm font-medium leading-tight">
28
+ {passkey.name || localization.auth.passkey}
29
+ </span>
30
+
31
+ <span className="text-xs text-muted">
32
+ {new Date(passkey.createdAt).toLocaleString(undefined, {
33
+ dateStyle: "medium",
34
+ timeStyle: "short"
35
+ })}
36
+ </span>
37
+ </div>
38
+
39
+ <Button
40
+ className="ml-auto shrink-0"
41
+ variant="outline"
42
+ size="sm"
43
+ isPending={isPending}
44
+ onPress={() => deletePasskey({ id: passkey.id })}
45
+ >
46
+ {isPending ? <Spinner color="current" size="sm" /> : <Xmark />}
47
+ {localization.settings.delete}
48
+ </Button>
49
+ </div>
50
+ )
51
+ }
@@ -0,0 +1,104 @@
1
+ import {
2
+ useAddPasskey,
3
+ useAuth,
4
+ useListUserPasskeys
5
+ } from "@better-auth-ui/react"
6
+ import {
7
+ Button,
8
+ Card,
9
+ type CardProps,
10
+ cn,
11
+ Skeleton,
12
+ Spinner,
13
+ toast
14
+ } from "@heroui/react"
15
+
16
+ import { Passkey } from "./passkey"
17
+
18
+ export type PasskeysProps = {
19
+ className?: string
20
+ variant?: CardProps["variant"]
21
+ }
22
+
23
+ export function Passkeys({
24
+ className,
25
+ variant,
26
+ ...props
27
+ }: PasskeysProps & CardProps) {
28
+ const { localization } = useAuth()
29
+
30
+ const { data: passkeys, isPending } = useListUserPasskeys({
31
+ throwOnError: (error) => {
32
+ if (error.error) toast.danger(error.error.message)
33
+ return false
34
+ }
35
+ })
36
+
37
+ const { mutate: addPasskey, isPending: isAdding } = useAddPasskey({
38
+ onError: (error) => toast.danger(error.error?.message || error.message)
39
+ })
40
+
41
+ return (
42
+ <div>
43
+ <h2 className={cn("text-sm font-semibold mb-3")}>
44
+ {localization.settings.passkeys}
45
+ </h2>
46
+
47
+ <Card className={cn(className)} variant={variant} {...props}>
48
+ <Card.Content className="gap-0">
49
+ <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
50
+ <div>
51
+ <p className="text-sm font-medium leading-tight">
52
+ {localization.settings.passkeysDescription}
53
+ </p>
54
+
55
+ <p className="text-muted text-xs mt-0.5">
56
+ {localization.settings.passkeysInstructions}
57
+ </p>
58
+ </div>
59
+
60
+ <Button
61
+ className="shrink-0"
62
+ size="sm"
63
+ isPending={isAdding}
64
+ isDisabled={isPending}
65
+ onPress={() => addPasskey()}
66
+ >
67
+ {isAdding && <Spinner color="current" size="sm" />}
68
+ {localization.settings.addPasskey}
69
+ </Button>
70
+ </div>
71
+
72
+ {isPending ? (
73
+ <>
74
+ <div className="border-b border-dashed -mx-4 md:-mx-6 my-4" />
75
+ <PasskeySkeleton />
76
+ </>
77
+ ) : (
78
+ passkeys?.map((passkey) => (
79
+ <div key={passkey.id}>
80
+ <div className="border-b border-dashed -mx-4 md:-mx-6 my-4" />
81
+ <Passkey passkey={passkey} />
82
+ </div>
83
+ ))
84
+ )}
85
+ </Card.Content>
86
+ </Card>
87
+ </div>
88
+ )
89
+ }
90
+
91
+ function PasskeySkeleton() {
92
+ return (
93
+ <div className="flex items-center justify-between">
94
+ <div className="flex items-center gap-3">
95
+ <Skeleton className="size-10 rounded-xl" />
96
+
97
+ <div className="flex flex-col gap-1">
98
+ <Skeleton className="h-4 w-24 rounded-lg" />
99
+ <Skeleton className="h-3 w-20 rounded-lg" />
100
+ </div>
101
+ </div>
102
+ </div>
103
+ )
104
+ }
@@ -6,6 +6,7 @@ import { ActiveSessions } from "./active-sessions"
6
6
  import { ChangePassword } from "./change-password"
7
7
  import { DangerZone } from "./danger-zone"
8
8
  import { LinkedAccounts } from "./linked-accounts"
9
+ import { Passkeys } from "./passkeys"
9
10
 
10
11
  export type SecuritySettingsProps = {
11
12
  className?: string
@@ -27,7 +28,7 @@ export function SecuritySettings({
27
28
  variant,
28
29
  ...props
29
30
  }: SecuritySettingsProps & ComponentProps<"div">) {
30
- const { deleteUser, emailAndPassword, socialProviders } = useAuth()
31
+ const { deleteUser, emailAndPassword, passkey, socialProviders } = useAuth()
31
32
 
32
33
  return (
33
34
  <div
@@ -36,6 +37,7 @@ export function SecuritySettings({
36
37
  >
37
38
  {emailAndPassword?.enabled && <ChangePassword variant={variant} />}
38
39
  {!!socialProviders?.length && <LinkedAccounts variant={variant} />}
40
+ {passkey && <Passkeys variant={variant} />}
39
41
  <ActiveSessions variant={variant} />
40
42
  {deleteUser?.enabled && <DangerZone variant={variant} />}
41
43
  </div>
package/src/index.tsx CHANGED
@@ -5,6 +5,7 @@ export * from "./components/auth/auth-provider"
5
5
  export * from "./components/auth/forgot-password"
6
6
  export * from "./components/auth/magic-link"
7
7
  export * from "./components/auth/magic-link-button"
8
+ export * from "./components/auth/passkey-button"
8
9
  export * from "./components/auth/provider-buttons"
9
10
  export * from "./components/auth/reset-password"
10
11
  export * from "./components/auth/sign-in"
@@ -28,6 +29,7 @@ export * from "./components/settings/security/change-password"
28
29
  export * from "./components/settings/security/danger-zone"
29
30
  export * from "./components/settings/security/delete-user"
30
31
  export * from "./components/settings/security/linked-accounts"
32
+ export * from "./components/settings/security/passkeys"
31
33
  export * from "./components/settings/security/security-settings"
32
34
  export * from "./components/settings/settings"
33
35
  export * from "./components/user/user-avatar"
@@ -1,18 +0,0 @@
1
- import type { AnyAuthConfig } from "@better-auth-ui/react";
2
- import type { AccountView } from "@better-auth-ui/react/core";
3
- import { type TabsProps } from "@heroui/react";
4
- export type AccountProps = AnyAuthConfig & {
5
- className?: string;
6
- path?: string;
7
- view?: AccountView;
8
- hideNav?: boolean;
9
- };
10
- /**
11
- * Selects and renders the appropriate account view component.
12
- *
13
- * @param path - Route path used to resolve an account view when `view` is not provided
14
- * @param view - Explicit auth view to render (e.g., "userProfile")
15
- * @param hideNav - Hide the navigation tabs
16
- */
17
- export declare function Account({ className, view, path, hideNav, ...config }: AccountProps): import("react/jsx-runtime").JSX.Element;
18
- export declare function ResponsiveTabs({ className, ...props }: TabsProps): import("react/jsx-runtime").JSX.Element;
@@ -1,24 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { ShieldCheckIcon, UserCircleIcon } from "@heroicons/react/24/outline";
3
- import { cn, Tabs } from "@heroui/react";
4
- import { useAuth } from "../../hooks/use-auth";
5
- import { AccountSettings } from "./settings/account-settings";
6
- /**
7
- * Selects and renders the appropriate account view component.
8
- *
9
- * @param path - Route path used to resolve an account view when `view` is not provided
10
- * @param view - Explicit auth view to render (e.g., "userProfile")
11
- * @param hideNav - Hide the navigation tabs
12
- */
13
- export function Account({ className, view, path, hideNav, ...config }) {
14
- const { basePaths, viewPaths } = useAuth(config);
15
- if (!view && !path) {
16
- throw new Error("[Better Auth UI] Either `view` or `path` must be provided");
17
- }
18
- const accountPathViews = Object.fromEntries(Object.entries(viewPaths.account).map(([k, v]) => [v, k]));
19
- const currentView = view || (path ? accountPathViews[path] : undefined);
20
- return (_jsxs(ResponsiveTabs, { selectedKey: currentView, className: "w-full", children: [_jsx(Tabs.ListContainer, { children: _jsxs(Tabs.List, { "aria-label": "Account", className: cn("overflow-auto md:w-64 lg:w-72 xl:w-80", hideNav && "hidden"), children: [_jsxs(Tabs.Tab, { id: "settings", href: `${basePaths.account}/${viewPaths.account.settings}`, className: "gap-1.5", children: [_jsx(UserCircleIcon, { className: "size-4" }), "Account", _jsx(Tabs.Indicator, {})] }), _jsxs(Tabs.Tab, { id: "security", href: `${basePaths.account}/${viewPaths.account.security}`, className: "gap-1.5", children: [_jsx(ShieldCheckIcon, { className: "size-4" }), "Security", _jsx(Tabs.Indicator, {})] })] }) }), _jsx(Tabs.Panel, { id: "settings", className: "md:pt-0 px-0 md:px-2", children: _jsx(AccountSettings, {}) }), _jsx(Tabs.Panel, { id: "security", children: "Security" })] }));
21
- }
22
- export function ResponsiveTabs({ className, ...props }) {
23
- return (_jsxs(_Fragment, { children: [_jsx(Tabs, { className: cn("md:hidden", className), orientation: "horizontal", ...props }), _jsx(Tabs, { className: cn("hidden md:flex", className), orientation: "vertical", ...props })] }));
24
- }
@@ -1,5 +0,0 @@
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;
@@ -1,6 +0,0 @@
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
- }
@@ -1,5 +0,0 @@
1
- import type { AnyAuthConfig } from "@better-auth-ui/react";
2
- export type SettingsProps = AnyAuthConfig & {
3
- className?: string;
4
- };
5
- export declare function Settings({ className, ...config }: SettingsProps): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { UserProfile } from "./user-profile";
3
- export function Settings({ className, ...config }) {
4
- return (_jsx("div", { className: className, children: _jsx(UserProfile, { ...config }) }));
5
- }
@@ -1,5 +0,0 @@
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;
@@ -1,20 +0,0 @@
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.account.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.account.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
- }
@@ -1,14 +0,0 @@
1
- import { type CardProps } from "@heroui/react";
2
- export type AccountsProps = {
3
- className?: string;
4
- variant?: CardProps["variant"];
5
- };
6
- /**
7
- * Render a card that lists and manages all device sessions for the current user.
8
- *
9
- * Shows each session with user information and actions to switch to or revoke a session.
10
- * When device session data is loading, a pending placeholder row is displayed.
11
- *
12
- * @returns A JSX element containing the accounts management card
13
- */
14
- export declare function Accounts({ className, ...props }: AccountsProps & CardProps): import("react/jsx-runtime").JSX.Element;