@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.
- package/dist/components/auth/magic-link.js +3 -2
- package/dist/components/auth/passkey-button.d.ts +4 -0
- package/dist/components/auth/passkey-button.js +13 -0
- package/dist/components/auth/sign-in.js +3 -2
- package/dist/components/settings/security/passkey.d.ts +8 -0
- package/dist/components/settings/security/passkey.js +14 -0
- package/dist/components/settings/security/passkeys.d.ts +6 -0
- package/dist/components/settings/security/passkeys.js +21 -0
- package/dist/components/settings/security/security-settings.js +3 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/package.json +6 -1
- package/src/components/auth/magic-link.tsx +4 -0
- package/src/components/auth/passkey-button.tsx +36 -0
- package/src/components/auth/sign-in.tsx +4 -0
- package/src/components/settings/security/passkey.tsx +51 -0
- package/src/components/settings/security/passkeys.tsx +104 -0
- package/src/components/settings/security/security-settings.tsx +3 -1
- package/src/index.tsx +2 -0
- package/dist/components/account/account.d.ts +0 -18
- package/dist/components/account/account.js +0 -24
- package/dist/components/account/settings/account-settings.d.ts +0 -5
- package/dist/components/account/settings/account-settings.js +0 -6
- package/dist/components/account/settings/settings.d.ts +0 -5
- package/dist/components/account/settings/settings.js +0 -5
- package/dist/components/account/settings/user-profile.d.ts +0 -5
- package/dist/components/account/settings/user-profile.js +0 -20
- package/dist/components/settings/account/accounts.d.ts +0 -14
- package/dist/components/settings/account/accounts.js +0 -26
- package/dist/components/settings/account/theme-selector.d.ts +0 -16
- package/dist/components/settings/account/theme-selector.js +0 -33
- package/dist/components/settings/account/theme-settings.d.ts +0 -16
- package/dist/components/settings/account/theme-settings.js +0 -31
- package/dist/components/settings/account-settings.d.ts +0 -5
- package/dist/components/settings/account-settings.js +0 -6
- package/dist/components/settings/account.d.ts +0 -18
- package/dist/components/settings/account.js +0 -24
- package/dist/components/settings/security/connected-account.d.ts +0 -16
- package/dist/components/settings/security/connected-account.js +0 -46
- package/dist/components/settings/security/connected-accounts.d.ts +0 -15
- package/dist/components/settings/security/connected-accounts.js +0 -31
- package/dist/components/settings/security/sessions.d.ts +0 -14
- package/dist/components/settings/security/sessions.js +0 -40
- package/dist/components/settings/settings/account-settings.d.ts +0 -5
- package/dist/components/settings/settings/account-settings.js +0 -6
- package/dist/components/settings/settings/user-profile.d.ts +0 -5
- package/dist/components/settings/settings/user-profile.js +0 -20
- package/dist/components/settings/user-profile.d.ts +0 -5
- package/dist/components/settings/user-profile.js +0 -20
- package/dist/components/user/switch-account-popover.d.ts +0 -10
- package/dist/components/user/switch-account-popover.js +0 -25
- package/dist/components/user/switch-account-submenu.d.ts +0 -10
- package/dist/components/user/switch-account-submenu.js +0 -25
- package/dist/hooks/use-auth.d.ts +0 -2
- package/dist/hooks/use-auth.js +0 -8
- package/dist/hooks/use-redirect-to.d.ts +0 -8
- package/dist/hooks/use-redirect-to.js +0 -19
- package/dist/hooks/use-sign-in.d.ts +0 -8
- package/dist/hooks/use-sign-in.js +0 -53
- package/dist/lib/utils.d.ts +0 -2
- package/dist/lib/utils.js +0 -5
- package/dist/server.d.ts +0 -1
- package/dist/server.js +0 -1
- package/dist/src/components/auth/auth-provider.d.ts +0 -8
- package/dist/src/components/auth/auth-provider.js +0 -13
- package/dist/src/components/auth/auth.d.ts +0 -22
- package/dist/src/components/auth/auth.js +0 -42
- package/dist/src/components/auth/field-separator.d.ts +0 -4
- package/dist/src/components/auth/field-separator.js +0 -5
- package/dist/src/components/auth/forgot-password.d.ts +0 -15
- package/dist/src/components/auth/forgot-password.js +0 -29
- package/dist/src/components/auth/magic-link-button.d.ts +0 -13
- package/dist/src/components/auth/magic-link-button.js +0 -20
- package/dist/src/components/auth/magic-link.d.ts +0 -17
- package/dist/src/components/auth/magic-link.js +0 -37
- package/dist/src/components/auth/provider-buttons.d.ts +0 -19
- package/dist/src/components/auth/provider-buttons.js +0 -35
- package/dist/src/components/auth/reset-password.d.ts +0 -11
- package/dist/src/components/auth/reset-password.js +0 -59
- package/dist/src/components/auth/sign-in.d.ts +0 -14
- package/dist/src/components/auth/sign-in.js +0 -58
- package/dist/src/components/auth/sign-out.d.ts +0 -11
- package/dist/src/components/auth/sign-out.js +0 -34
- package/dist/src/components/auth/sign-up.d.ts +0 -19
- package/dist/src/components/auth/sign-up.js +0 -65
- package/dist/src/components/email/email-changed-email.d.ts +0 -3
- package/dist/src/components/email/email-changed-email.js +0 -23
- package/dist/src/components/email/email-verification-email.d.ts +0 -3
- package/dist/src/components/email/email-verification-email.js +0 -23
- package/dist/src/components/email/magic-link-email.d.ts +0 -3
- package/dist/src/components/email/magic-link-email.js +0 -23
- package/dist/src/components/email/new-device-email.d.ts +0 -3
- package/dist/src/components/email/new-device-email.js +0 -23
- package/dist/src/components/email/otp-email.d.ts +0 -3
- package/dist/src/components/email/otp-email.js +0 -22
- package/dist/src/components/email/password-changed-email.d.ts +0 -3
- package/dist/src/components/email/password-changed-email.js +0 -23
- package/dist/src/components/email/reset-password-email.d.ts +0 -3
- package/dist/src/components/email/reset-password-email.js +0 -23
- package/dist/src/components/settings/account/account-settings.d.ts +0 -13
- package/dist/src/components/settings/account/account-settings.js +0 -19
- package/dist/src/components/settings/account/appearance.d.ts +0 -16
- package/dist/src/components/settings/account/appearance.js +0 -28
- package/dist/src/components/settings/account/change-email.d.ts +0 -15
- package/dist/src/components/settings/account/change-email.js +0 -35
- package/dist/src/components/settings/account/manage-account.d.ts +0 -19
- package/dist/src/components/settings/account/manage-account.js +0 -27
- package/dist/src/components/settings/account/manage-accounts.d.ts +0 -14
- package/dist/src/components/settings/account/manage-accounts.js +0 -27
- package/dist/src/components/settings/account/user-profile.d.ts +0 -13
- package/dist/src/components/settings/account/user-profile.js +0 -29
- package/dist/src/components/settings/security/active-session.d.ts +0 -14
- package/dist/src/components/settings/security/active-session.js +0 -35
- package/dist/src/components/settings/security/active-sessions.d.ts +0 -14
- package/dist/src/components/settings/security/active-sessions.js +0 -29
- package/dist/src/components/settings/security/change-password.d.ts +0 -15
- package/dist/src/components/settings/security/change-password.js +0 -57
- package/dist/src/components/settings/security/linked-account.d.ts +0 -16
- package/dist/src/components/settings/security/linked-account.js +0 -46
- package/dist/src/components/settings/security/linked-accounts.d.ts +0 -15
- package/dist/src/components/settings/security/linked-accounts.js +0 -31
- package/dist/src/components/settings/security/security-settings.d.ts +0 -15
- package/dist/src/components/settings/security/security-settings.js +0 -18
- package/dist/src/components/settings/settings.d.ts +0 -29
- package/dist/src/components/settings/settings.js +0 -39
- package/dist/src/components/user/switch-account-item.d.ts +0 -16
- package/dist/src/components/user/switch-account-item.js +0 -14
- package/dist/src/components/user/switch-account-menu.d.ts +0 -10
- package/dist/src/components/user/switch-account-menu.js +0 -23
- package/dist/src/components/user/user-avatar.d.ts +0 -24
- package/dist/src/components/user/user-avatar.js +0 -31
- package/dist/src/components/user/user-button.d.ts +0 -21
- package/dist/src/components/user/user-button.js +0 -24
- package/dist/src/components/user/user-view.d.ts +0 -21
- package/dist/src/components/user/user-view.js +0 -24
- package/dist/src/core.d.ts +0 -1
- package/dist/src/core.js +0 -1
- package/dist/src/index.d.ts +0 -31
- package/dist/src/index.js +0 -32
- package/dist/src/lib/utils.d.ts +0 -2
- package/dist/src/lib/utils.js +0 -5
- package/dist/src/react-exports.d.ts +0 -1
- package/dist/src/react-exports.js +0 -1
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useRevokeSession, useSession } from "@better-auth-ui/react";
|
|
3
|
-
import { ArrowRightFromSquare, Display, Smartphone } from "@gravity-ui/icons";
|
|
4
|
-
import { Button, Card, Chip, Spinner, toast } from "@heroui/react";
|
|
5
|
-
import { UAParser } from "ua-parser-js";
|
|
6
|
-
/**
|
|
7
|
-
* Render a single active session card with device info and revoke control.
|
|
8
|
-
*
|
|
9
|
-
* Shows the session's browser, OS, IP address, and creation time. The current session is marked
|
|
10
|
-
* and navigates to sign-out on click, while other sessions can be revoked individually.
|
|
11
|
-
*
|
|
12
|
-
* @param session - The session object containing id, token, userAgent, ipAddress, and createdAt
|
|
13
|
-
* @returns A JSX element containing the active session card
|
|
14
|
-
*/
|
|
15
|
-
export function ActiveSession({ session }) {
|
|
16
|
-
const { basePaths, localization, viewPaths, navigate } = useAuth();
|
|
17
|
-
const { data: sessionData } = useSession();
|
|
18
|
-
const { mutate: revokeSession, isPending: isRevoking } = useRevokeSession({
|
|
19
|
-
onError: (error) => toast.danger(error.error?.message || error.message),
|
|
20
|
-
onSuccess: () => toast.success(localization.settings.revokeSessionSuccess)
|
|
21
|
-
});
|
|
22
|
-
const isCurrentSession = session.token === sessionData?.session.token;
|
|
23
|
-
const ua = new UAParser(session.userAgent || "").getResult();
|
|
24
|
-
const isMobile = ua.device.type === "mobile" ||
|
|
25
|
-
ua.device.type === "tablet" ||
|
|
26
|
-
ua.device.type === "wearable";
|
|
27
|
-
return (_jsxs(Card, { className: "flex-row border items-center p-3 shadow-none", children: [_jsx("div", { className: "flex size-10 items-center justify-center rounded-xl bg-surface-secondary", children: isMobile ? (_jsx(Smartphone, { className: "size-5" })) : (_jsx(Display, { className: "size-5" })) }), _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs("span", { className: "text-sm font-medium truncate", children: [ua.browser.name || "Unknown Browser", ua.os.name ? `, ${ua.os.name}` : ""] }), isCurrentSession && (_jsx(Chip, { color: "accent", size: "sm", className: "px-1.5", children: localization.settings.currentSession }))] }), _jsxs("div", { className: "flex items-center gap-1.5 text-xs text-muted", children: [session.ipAddress && _jsx("span", { children: session.ipAddress }), session.createdAt && (_jsxs(_Fragment, { children: [session.ipAddress && _jsx("span", { children: "\u2022" }), _jsx("span", { children: session.createdAt.toLocaleString([], {
|
|
28
|
-
dateStyle: "short",
|
|
29
|
-
timeStyle: "short"
|
|
30
|
-
}) })] }))] })] }), _jsx(Button, { isIconOnly: true, className: "ml-auto", variant: "ghost", size: "sm", onPress: () => isCurrentSession
|
|
31
|
-
? navigate({
|
|
32
|
-
to: `${basePaths.auth}/${viewPaths.auth.signOut}`
|
|
33
|
-
})
|
|
34
|
-
: revokeSession({ token: session.token }), isPending: isRevoking, "aria-label": localization.settings.revokeSession, children: isRevoking ? (_jsx(Spinner, { color: "current", size: "sm" })) : (_jsx(ArrowRightFromSquare, {})) })] }));
|
|
35
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { type CardProps } from "@heroui/react";
|
|
2
|
-
export type ActiveSessionsProps = {
|
|
3
|
-
className?: string;
|
|
4
|
-
variant?: CardProps["variant"];
|
|
5
|
-
};
|
|
6
|
-
/**
|
|
7
|
-
* Render a card listing all active sessions for the current user with revoke controls.
|
|
8
|
-
*
|
|
9
|
-
* Shows each session's browser, OS, IP address, and creation time. The current session is marked
|
|
10
|
-
* and navigates to sign-out on click, while other sessions can be revoked individually.
|
|
11
|
-
*
|
|
12
|
-
* @returns A JSX element containing the sessions card
|
|
13
|
-
*/
|
|
14
|
-
export declare function ActiveSessions({ className, ...props }: ActiveSessionsProps & CardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useListSessions, useSession } from "@better-auth-ui/react";
|
|
3
|
-
import { Card, cn, Skeleton, toast } from "@heroui/react";
|
|
4
|
-
import { ActiveSession } from "./active-session";
|
|
5
|
-
/**
|
|
6
|
-
* Render a card listing all active sessions for the current user with revoke controls.
|
|
7
|
-
*
|
|
8
|
-
* Shows each session's browser, OS, IP address, and creation time. The current session is marked
|
|
9
|
-
* and navigates to sign-out on click, while other sessions can be revoked individually.
|
|
10
|
-
*
|
|
11
|
-
* @returns A JSX element containing the sessions card
|
|
12
|
-
*/
|
|
13
|
-
export function ActiveSessions({ className, ...props }) {
|
|
14
|
-
const { localization } = useAuth();
|
|
15
|
-
const { data: sessionData } = useSession();
|
|
16
|
-
const { data: sessions, isPending } = useListSessions({
|
|
17
|
-
throwOnError: (error) => {
|
|
18
|
-
if (error.error)
|
|
19
|
-
toast.danger(error.error.message);
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
return (_jsxs(Card, { className: cn("p-4 md:p-6 gap-4", className), ...props, children: [_jsx(Card.Header, { children: _jsx(Card.Title, { className: "text-xl", children: localization.settings.activeSessions }) }), _jsx(Card.Content, { className: "gap-3", children: isPending ? (_jsx(SessionRowSkeleton, {})) : (sessions
|
|
24
|
-
?.toSorted((session) => session.id === sessionData?.session.id ? -1 : 1)
|
|
25
|
-
.map((session) => (_jsx(ActiveSession, { session: session }, session.id)))) })] }));
|
|
26
|
-
}
|
|
27
|
-
function SessionRowSkeleton() {
|
|
28
|
-
return (_jsx("div", { className: "flex items-center rounded-3xl border p-3 justify-between", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Skeleton, { className: "size-10 rounded-xl" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Skeleton, { className: "h-4 w-32 rounded-lg" }), _jsx(Skeleton, { className: "h-3 w-24 rounded-lg" })] })] }) }));
|
|
29
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { type CardProps } from "@heroui/react";
|
|
2
|
-
export type ChangePasswordProps = {
|
|
3
|
-
className?: string;
|
|
4
|
-
variant?: CardProps["variant"];
|
|
5
|
-
};
|
|
6
|
-
/**
|
|
7
|
-
* Render a card form for changing the authenticated user's password.
|
|
8
|
-
*
|
|
9
|
-
* Displays a card with fields for current password, new password, and optionally
|
|
10
|
-
* confirm password (based on `emailAndPassword.confirmPassword`). All other sessions
|
|
11
|
-
* are revoked upon successful password change.
|
|
12
|
-
*
|
|
13
|
-
* @returns A JSX element containing the change-password card and form
|
|
14
|
-
*/
|
|
15
|
-
export declare function ChangePassword({ className, variant, ...props }: ChangePasswordProps & CardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useChangePassword, useSession } from "@better-auth-ui/react";
|
|
3
|
-
import { Check, Eye, EyeSlash } from "@gravity-ui/icons";
|
|
4
|
-
import { Button, Card, cn, FieldError, Fieldset, Form, Input, InputGroup, Label, Skeleton, Spinner, TextField, toast } from "@heroui/react";
|
|
5
|
-
import { useState } from "react";
|
|
6
|
-
/**
|
|
7
|
-
* Render a card form for changing the authenticated user's password.
|
|
8
|
-
*
|
|
9
|
-
* Displays a card with fields for current password, new password, and optionally
|
|
10
|
-
* confirm password (based on `emailAndPassword.confirmPassword`). All other sessions
|
|
11
|
-
* are revoked upon successful password change.
|
|
12
|
-
*
|
|
13
|
-
* @returns A JSX element containing the change-password card and form
|
|
14
|
-
*/
|
|
15
|
-
export function ChangePassword({ className, variant, ...props }) {
|
|
16
|
-
const { emailAndPassword, localization } = useAuth();
|
|
17
|
-
const { data: sessionData } = useSession();
|
|
18
|
-
const [currentPassword, setCurrentPassword] = useState("");
|
|
19
|
-
const [newPassword, setNewPassword] = useState("");
|
|
20
|
-
const [confirmPassword, setConfirmPassword] = useState("");
|
|
21
|
-
const { mutate: changePassword, isPending } = useChangePassword({
|
|
22
|
-
onError: (error) => {
|
|
23
|
-
setCurrentPassword("");
|
|
24
|
-
setNewPassword("");
|
|
25
|
-
setConfirmPassword("");
|
|
26
|
-
toast.danger(error.error?.message || error.message);
|
|
27
|
-
},
|
|
28
|
-
onSuccess: () => {
|
|
29
|
-
setCurrentPassword("");
|
|
30
|
-
setNewPassword("");
|
|
31
|
-
setConfirmPassword("");
|
|
32
|
-
toast.success(localization.settings.changePasswordSuccess);
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
const [isNewPasswordVisible, setIsNewPasswordVisible] = useState(false);
|
|
36
|
-
const [isConfirmPasswordVisible, setIsConfirmPasswordVisible] = useState(false);
|
|
37
|
-
const handleSubmit = (e) => {
|
|
38
|
-
e.preventDefault();
|
|
39
|
-
if (emailAndPassword?.confirmPassword && newPassword !== confirmPassword) {
|
|
40
|
-
setCurrentPassword("");
|
|
41
|
-
setNewPassword("");
|
|
42
|
-
setConfirmPassword("");
|
|
43
|
-
toast.danger(localization.auth.passwordsDoNotMatch);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
changePassword({
|
|
47
|
-
currentPassword,
|
|
48
|
-
newPassword,
|
|
49
|
-
revokeOtherSessions: true
|
|
50
|
-
});
|
|
51
|
-
};
|
|
52
|
-
return (_jsxs(Card, { className: cn("p-4 md:p-6 gap-4", className), variant: variant, ...props, children: [_jsx(Card.Header, { children: _jsx(Card.Title, { className: "text-xl", children: localization.settings.changePassword }) }), _jsx(Card.Content, { children: _jsx(Form, { onSubmit: handleSubmit, children: _jsxs(Fieldset, { className: "w-full gap-4", children: [_jsxs(Fieldset.Group, { children: [_jsxs(TextField, { name: "currentPassword", type: "password", isDisabled: isPending || !sessionData, value: currentPassword, onChange: setCurrentPassword, children: [_jsx(Label, { children: localization.settings.currentPassword }), sessionData ? (_jsx(Input, { autoComplete: "current-password", placeholder: localization.settings.currentPasswordPlaceholder, required: true, variant: variant === "transparent" ? "primary" : "secondary" })) : (_jsx(Skeleton, { className: "h-10 md:h-9 w-full rounded-xl" })), _jsx(FieldError, {})] }), _jsxs(TextField, { minLength: emailAndPassword?.minPasswordLength, maxLength: emailAndPassword?.maxPasswordLength, isDisabled: isPending || !sessionData, value: newPassword, onChange: setNewPassword, children: [_jsx(Label, { children: localization.auth.newPassword }), sessionData ? (_jsxs(InputGroup, { variant: variant === "transparent" ? "primary" : "secondary", children: [_jsx(InputGroup.Input, { name: "newPassword", type: isNewPasswordVisible ? "text" : "password", autoComplete: "new-password", placeholder: localization.auth.newPasswordPlaceholder, required: true }), _jsx(InputGroup.Suffix, { className: "px-0", children: _jsx(Button, { isIconOnly: true, "aria-label": isNewPasswordVisible
|
|
53
|
-
? localization.auth.hidePassword
|
|
54
|
-
: localization.auth.showPassword, size: "sm", variant: "ghost", onPress: () => setIsNewPasswordVisible(!isNewPasswordVisible), isDisabled: isPending, children: isNewPasswordVisible ? _jsx(EyeSlash, {}) : _jsx(Eye, {}) }) })] })) : (_jsx(Skeleton, { className: "h-10 md:h-9 w-full rounded-xl" })), _jsx(FieldError, {})] }), emailAndPassword?.confirmPassword && (_jsxs(TextField, { minLength: emailAndPassword?.minPasswordLength, maxLength: emailAndPassword?.maxPasswordLength, isDisabled: isPending || !sessionData, isRequired: true, value: confirmPassword, onChange: setConfirmPassword, children: [_jsx(Label, { children: localization.auth.confirmPassword }), sessionData ? (_jsxs(InputGroup, { variant: variant === "transparent" ? "primary" : "secondary", children: [_jsx(InputGroup.Input, { name: "confirmPassword", type: isConfirmPasswordVisible ? "text" : "password", autoComplete: "new-password", placeholder: localization.auth.confirmPasswordPlaceholder, required: true }), _jsx(InputGroup.Suffix, { className: "px-0", children: _jsx(Button, { isIconOnly: true, "aria-label": isConfirmPasswordVisible
|
|
55
|
-
? localization.auth.hidePassword
|
|
56
|
-
: localization.auth.showPassword, size: "sm", variant: "ghost", onPress: () => setIsConfirmPasswordVisible(!isConfirmPasswordVisible), isDisabled: isPending, children: isConfirmPasswordVisible ? _jsx(EyeSlash, {}) : _jsx(Eye, {}) }) })] })) : (_jsx(Skeleton, { className: "h-10 md:h-9 w-full rounded-xl" })), _jsx(FieldError, {})] }))] }), _jsx(Fieldset.Actions, { children: _jsxs(Button, { type: "submit", isPending: isPending, isDisabled: !sessionData, children: [isPending ? _jsx(Spinner, { color: "current", size: "sm" }) : _jsx(Check, {}), localization.settings.updatePassword] }) })] }) }) })] }));
|
|
57
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { Account, SocialProvider } from "better-auth";
|
|
2
|
-
export type LinkedAccountProps = {
|
|
3
|
-
account?: Account;
|
|
4
|
-
provider: SocialProvider;
|
|
5
|
-
};
|
|
6
|
-
/**
|
|
7
|
-
* Render a single linked social account card with provider info and unlink control.
|
|
8
|
-
*
|
|
9
|
-
* Fetches additional account information from the provider using the accountInfo API
|
|
10
|
-
* and displays the provider name, account details, and an unlink button.
|
|
11
|
-
*
|
|
12
|
-
* @param account - The account object containing id, accountId, and providerId
|
|
13
|
-
* @param provider - The provider id
|
|
14
|
-
* @returns A JSX element containing the linked account card
|
|
15
|
-
*/
|
|
16
|
-
export declare function LinkedAccount({ account, provider }: LinkedAccountProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { getProviderName } from "@better-auth-ui/core";
|
|
3
|
-
import { providerIcons, useAccountInfo, useAuth, useLinkSocial, useUnlinkAccount } from "@better-auth-ui/react";
|
|
4
|
-
import { Link, PlugConnection, Xmark } from "@gravity-ui/icons";
|
|
5
|
-
import { Button, Card, cn, Skeleton, Spinner, toast } from "@heroui/react";
|
|
6
|
-
/**
|
|
7
|
-
* Render a single linked social account card with provider info and unlink control.
|
|
8
|
-
*
|
|
9
|
-
* Fetches additional account information from the provider using the accountInfo API
|
|
10
|
-
* and displays the provider name, account details, and an unlink button.
|
|
11
|
-
*
|
|
12
|
-
* @param account - The account object containing id, accountId, and providerId
|
|
13
|
-
* @param provider - The provider id
|
|
14
|
-
* @returns A JSX element containing the linked account card
|
|
15
|
-
*/
|
|
16
|
-
export function LinkedAccount({ account, provider }) {
|
|
17
|
-
const { baseURL, localization } = useAuth();
|
|
18
|
-
const { data: accountInfo, isPending: isLoadingInfo } = useAccountInfo(account?.accountId, {
|
|
19
|
-
enabled: !!account,
|
|
20
|
-
throwOnError: (error) => {
|
|
21
|
-
if (error.error)
|
|
22
|
-
toast.danger(error.error.message);
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
const { mutate: linkSocial, isPending: isLinking } = useLinkSocial({
|
|
27
|
-
onError: (error) => toast.danger(error.error?.message || error.message)
|
|
28
|
-
});
|
|
29
|
-
const { mutate: unlinkAccount, isPending: isUnlinking } = useUnlinkAccount({
|
|
30
|
-
onError: (error) => toast.danger(error.error?.message || error.message),
|
|
31
|
-
onSuccess: () => toast.success(localization.settings.accountUnlinked)
|
|
32
|
-
});
|
|
33
|
-
const ProviderIcon = providerIcons[provider];
|
|
34
|
-
const providerName = getProviderName(provider);
|
|
35
|
-
const displayName = accountInfo?.data?.login ||
|
|
36
|
-
accountInfo?.data?.username ||
|
|
37
|
-
accountInfo?.user?.email ||
|
|
38
|
-
accountInfo?.user?.name ||
|
|
39
|
-
account?.accountId;
|
|
40
|
-
return (_jsxs(Card, { className: cn("flex-row items-center border p-3 shadow-none", !account && "border-dashed"), children: [_jsx("div", { className: "flex size-10 items-center justify-center rounded-xl bg-surface-secondary", children: ProviderIcon ? (_jsx(ProviderIcon, { className: cn("size-5", !account && "opacity-50") })) : (_jsx(PlugConnection, { className: cn("size-5", !account && "opacity-50") })) }), _jsxs("div", { className: "flex flex-col", children: [_jsx("span", { className: "text-sm font-medium leading-tight", children: providerName }), account && isLoadingInfo ? (_jsx(Skeleton, { className: "h-3 w-24 my-0.5 rounded-lg" })) : (_jsx("span", { className: "text-xs text-muted", children: account
|
|
41
|
-
? displayName
|
|
42
|
-
: localization.settings.linkProvider.replace("{{provider}}", providerName) }))] }), account ? (_jsx(Button, { className: "ml-auto", isIconOnly: true, variant: "ghost", size: "sm", onPress: () => unlinkAccount({ providerId: account.providerId }), isPending: isUnlinking, "aria-label": localization.settings.unlinkProvider.replace("{{provider}}", providerName), children: isUnlinking ? _jsx(Spinner, { color: "current", size: "sm" }) : _jsx(Xmark, {}) })) : (_jsxs(Button, { className: "ml-auto", variant: "secondary", size: "sm", onPress: () => linkSocial({
|
|
43
|
-
provider,
|
|
44
|
-
callbackURL: `${baseURL}${window.location.pathname}`
|
|
45
|
-
}), isPending: isLinking, "aria-label": localization.settings.linkProvider.replace("{{provider}}", providerName), children: [isLinking ? _jsx(Spinner, { color: "current", size: "sm" }) : _jsx(Link, {}), localization.settings.link] }))] }));
|
|
46
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { type CardProps } from "@heroui/react";
|
|
2
|
-
export type LinkedAccountsProps = {
|
|
3
|
-
className?: string;
|
|
4
|
-
variant?: CardProps["variant"];
|
|
5
|
-
};
|
|
6
|
-
/**
|
|
7
|
-
* Render a card showing linked social accounts and available social providers to link.
|
|
8
|
-
*
|
|
9
|
-
* Linked accounts (excluding the "credential" provider) are shown with an unlink control;
|
|
10
|
-
* available providers are shown with a link control. Button states and labels reflect
|
|
11
|
-
* ongoing link/unlink activity and use localization for provider-specific text.
|
|
12
|
-
*
|
|
13
|
-
* @returns A JSX element containing the linked accounts card
|
|
14
|
-
*/
|
|
15
|
-
export declare function LinkedAccounts({ className, ...props }: LinkedAccountsProps & CardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useListAccounts } from "@better-auth-ui/react";
|
|
3
|
-
import { Card, cn, Skeleton, toast } from "@heroui/react";
|
|
4
|
-
import { LinkedAccount } from "./linked-account";
|
|
5
|
-
/**
|
|
6
|
-
* Render a card showing linked social accounts and available social providers to link.
|
|
7
|
-
*
|
|
8
|
-
* Linked accounts (excluding the "credential" provider) are shown with an unlink control;
|
|
9
|
-
* available providers are shown with a link control. Button states and labels reflect
|
|
10
|
-
* ongoing link/unlink activity and use localization for provider-specific text.
|
|
11
|
-
*
|
|
12
|
-
* @returns A JSX element containing the linked accounts card
|
|
13
|
-
*/
|
|
14
|
-
export function LinkedAccounts({ className, ...props }) {
|
|
15
|
-
const { localization, socialProviders } = useAuth();
|
|
16
|
-
const { data: accounts, isPending } = useListAccounts({
|
|
17
|
-
throwOnError: (error) => {
|
|
18
|
-
if (error.error)
|
|
19
|
-
toast.danger(error.error.message);
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
return (_jsxs(Card, { className: cn("p-4 md:p-6 gap-4", className), ...props, children: [_jsx(Card.Header, { children: _jsx(Card.Title, { className: "text-xl", children: localization.settings.linkedAccounts }) }), _jsx(Card.Content, { className: "gap-3", children: isPending ? (_jsx(AccountRowSkeleton, {})) : (_jsxs(_Fragment, { children: [accounts
|
|
24
|
-
?.filter((account) => account.providerId !== "credential")
|
|
25
|
-
.map((account) => (_jsx(LinkedAccount, { account: account, provider: account.providerId }, account.id))), socialProviders?.map((provider) => {
|
|
26
|
-
return _jsx(LinkedAccount, { provider: provider }, provider);
|
|
27
|
-
})] })) })] }));
|
|
28
|
-
}
|
|
29
|
-
function AccountRowSkeleton() {
|
|
30
|
-
return (_jsx("div", { className: "flex items-center rounded-3xl border p-3 justify-between", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Skeleton, { className: "size-10 rounded-xl" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Skeleton, { className: "h-4 w-20 rounded-lg" }), _jsx(Skeleton, { className: "h-3 w-32 rounded-lg" })] })] }) }));
|
|
31
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { CardProps } from "@heroui/react";
|
|
2
|
-
import type { ComponentProps } from "react";
|
|
3
|
-
export type SecuritySettingsProps = {
|
|
4
|
-
className?: string;
|
|
5
|
-
variant?: CardProps["variant"];
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* Renders the security settings layout including password management, linked accounts, and active sessions.
|
|
9
|
-
*
|
|
10
|
-
* ChangePassword is rendered when password authentication is enabled; LinkedAccounts is rendered when social providers are present.
|
|
11
|
-
*
|
|
12
|
-
* @param className - Optional additional CSS class names for the outer container.
|
|
13
|
-
* @returns The security settings container as a JSX element.
|
|
14
|
-
*/
|
|
15
|
-
export declare function SecuritySettings({ className, ...props }: SecuritySettingsProps & ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth } from "@better-auth-ui/react";
|
|
3
|
-
import { cn } from "../../../lib/utils";
|
|
4
|
-
import { ActiveSessions } from "./active-sessions";
|
|
5
|
-
import { ChangePassword } from "./change-password";
|
|
6
|
-
import { LinkedAccounts } from "./linked-accounts";
|
|
7
|
-
/**
|
|
8
|
-
* Renders the security settings layout including password management, linked accounts, and active sessions.
|
|
9
|
-
*
|
|
10
|
-
* ChangePassword is rendered when password authentication is enabled; LinkedAccounts is rendered when social providers are present.
|
|
11
|
-
*
|
|
12
|
-
* @param className - Optional additional CSS class names for the outer container.
|
|
13
|
-
* @returns The security settings container as a JSX element.
|
|
14
|
-
*/
|
|
15
|
-
export function SecuritySettings({ className, ...props }) {
|
|
16
|
-
const { emailAndPassword, socialProviders } = useAuth();
|
|
17
|
-
return (_jsxs("div", { className: cn("flex w-full flex-col gap-4 md:gap-6", className), ...props, children: [emailAndPassword?.enabled && _jsx(ChangePassword, {}), socialProviders?.length && _jsx(LinkedAccounts, {}), _jsx(ActiveSessions, {})] }));
|
|
18
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { SettingsView } from "@better-auth-ui/react/core";
|
|
2
|
-
import { type TabsProps } from "@heroui/react";
|
|
3
|
-
import { type ComponentProps } from "react";
|
|
4
|
-
export type SettingsProps = {
|
|
5
|
-
className?: string;
|
|
6
|
-
hideNav?: boolean;
|
|
7
|
-
path?: string;
|
|
8
|
-
view?: SettingsView;
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Renders the settings UI and activates the appropriate settings view based on `view` or `path`.
|
|
12
|
-
*
|
|
13
|
-
* @param className - Additional CSS class names applied to the root container
|
|
14
|
-
* @param path - Route path used to resolve which settings view to activate when `view` is not provided
|
|
15
|
-
* @param view - Explicit settings view to activate, e.g. `"account"` or `"security"`
|
|
16
|
-
* @param hideNav - When `true`, hide the navigation tabs
|
|
17
|
-
* @returns A DOM tree containing the responsive settings tabs and the currently selected settings panel
|
|
18
|
-
*
|
|
19
|
-
* @throws Error if neither `view` nor `path` is provided
|
|
20
|
-
*/
|
|
21
|
-
export declare function Settings({ className, hideNav, path, view, ...props }: SettingsProps & ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
22
|
-
/**
|
|
23
|
-
* Renders a responsive pair of Tabs components: horizontal on small screens and vertical on medium-and-up screens.
|
|
24
|
-
*
|
|
25
|
-
* @param className - Additional CSS classes applied to both responsive tab containers.
|
|
26
|
-
* @param props - All other props are forwarded to each underlying Tabs component.
|
|
27
|
-
* @returns A JSX element containing the responsive Tabs pair.
|
|
28
|
-
*/
|
|
29
|
-
export declare function ResponsiveTabs({ className, ...props }: TabsProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useAuthenticate } from "@better-auth-ui/react";
|
|
3
|
-
import { Person, Shield } from "@gravity-ui/icons";
|
|
4
|
-
import { cn, Tabs, useIsHydrated } from "@heroui/react";
|
|
5
|
-
import { useMemo } from "react";
|
|
6
|
-
import { AccountSettings } from "./account/account-settings";
|
|
7
|
-
import { SecuritySettings } from "./security/security-settings";
|
|
8
|
-
/**
|
|
9
|
-
* Renders the settings UI and activates the appropriate settings view based on `view` or `path`.
|
|
10
|
-
*
|
|
11
|
-
* @param className - Additional CSS class names applied to the root container
|
|
12
|
-
* @param path - Route path used to resolve which settings view to activate when `view` is not provided
|
|
13
|
-
* @param view - Explicit settings view to activate, e.g. `"account"` or `"security"`
|
|
14
|
-
* @param hideNav - When `true`, hide the navigation tabs
|
|
15
|
-
* @returns A DOM tree containing the responsive settings tabs and the currently selected settings panel
|
|
16
|
-
*
|
|
17
|
-
* @throws Error if neither `view` nor `path` is provided
|
|
18
|
-
*/
|
|
19
|
-
export function Settings({ className, hideNav, path, view, ...props }) {
|
|
20
|
-
const { basePaths, localization, viewPaths } = useAuth();
|
|
21
|
-
useAuthenticate();
|
|
22
|
-
if (!view && !path) {
|
|
23
|
-
throw new Error("[Better Auth UI] Either `view` or `path` must be provided");
|
|
24
|
-
}
|
|
25
|
-
const settingsPathViews = useMemo(() => Object.fromEntries(Object.entries(viewPaths.settings).map(([k, v]) => [v, k])), [viewPaths.settings]);
|
|
26
|
-
const currentView = view || (path ? settingsPathViews[path] : undefined);
|
|
27
|
-
const isHydrated = useIsHydrated();
|
|
28
|
-
return (_jsxs("div", { className: cn("w-full flex flex-col md:flex-row gap-4 md:gap-6", className), ...props, children: [_jsx(ResponsiveTabs, { selectedKey: currentView, className: cn(hideNav && "hidden"), children: _jsx(Tabs.ListContainer, { children: _jsxs(Tabs.List, { "aria-label": localization.settings.settings, className: "overflow-auto md:w-64 lg:w-72 xl:w-80", children: [_jsxs(Tabs.Tab, { id: "account", href: `${basePaths.settings}/${viewPaths.settings.account}`, className: "gap-2", children: [_jsx(Person, {}), localization.settings.account, _jsx(Tabs.Indicator, {})] }), _jsxs(Tabs.Tab, { id: "security", href: `${basePaths.settings}/${viewPaths.settings.security}`, className: "gap-2", children: [_jsx(Shield, {}), localization.settings.security, _jsx(Tabs.Indicator, {})] })] }) }) }), currentView === "account" && _jsx(AccountSettings, {}), currentView === "security" && _jsx(SecuritySettings, {})] }, `settings-${isHydrated}`));
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Renders a responsive pair of Tabs components: horizontal on small screens and vertical on medium-and-up screens.
|
|
32
|
-
*
|
|
33
|
-
* @param className - Additional CSS classes applied to both responsive tab containers.
|
|
34
|
-
* @param props - All other props are forwarded to each underlying Tabs component.
|
|
35
|
-
* @returns A JSX element containing the responsive Tabs pair.
|
|
36
|
-
*/
|
|
37
|
-
export function ResponsiveTabs({ className, ...props }) {
|
|
38
|
-
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 })] }));
|
|
39
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { Session, User } from "better-auth";
|
|
2
|
-
type DeviceSession = {
|
|
3
|
-
session: Session;
|
|
4
|
-
user: User;
|
|
5
|
-
};
|
|
6
|
-
export type SwitchAccountItemProps = {
|
|
7
|
-
deviceSession: DeviceSession;
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* Render a dropdown item for switching to a different authenticated session.
|
|
11
|
-
*
|
|
12
|
-
* @param deviceSession - The device session to display and switch to when pressed
|
|
13
|
-
* @returns The switch account dropdown item as a JSX element
|
|
14
|
-
*/
|
|
15
|
-
export declare function SwitchAccountItem({ deviceSession }: SwitchAccountItemProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
-
export {};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useSetActiveSession } from "@better-auth-ui/react";
|
|
3
|
-
import { Dropdown, Spinner } from "@heroui/react";
|
|
4
|
-
import { UserView } from "./user-view";
|
|
5
|
-
/**
|
|
6
|
-
* Render a dropdown item for switching to a different authenticated session.
|
|
7
|
-
*
|
|
8
|
-
* @param deviceSession - The device session to display and switch to when pressed
|
|
9
|
-
* @returns The switch account dropdown item as a JSX element
|
|
10
|
-
*/
|
|
11
|
-
export function SwitchAccountItem({ deviceSession }) {
|
|
12
|
-
const { mutate: setActiveSession, isPending } = useSetActiveSession();
|
|
13
|
-
return (_jsxs(Dropdown.Item, { className: "px-2", isDisabled: isPending, onPress: () => setActiveSession({ sessionToken: deviceSession.session.token }), children: [_jsx(UserView, { user: deviceSession.user }), isPending && _jsx(Spinner, { color: "current", size: "sm", className: "ml-auto" })] }));
|
|
14
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Render the menu content for switching between multiple authenticated sessions.
|
|
3
|
-
*
|
|
4
|
-
* Shows the current session with a checkmark, lists other device sessions that can be activated,
|
|
5
|
-
* and provides an option to add a new account. This component should be rendered inside a
|
|
6
|
-
* Dropdown.SubmenuTrigger to defer the useListDeviceSessions query until the submenu is opened.
|
|
7
|
-
*
|
|
8
|
-
* @returns The switch account menu content as a JSX element
|
|
9
|
-
*/
|
|
10
|
-
export declare function SwitchAccountMenu(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useListDeviceSessions, useSession } from "@better-auth-ui/react";
|
|
3
|
-
import { Check, CirclePlus } from "@gravity-ui/icons";
|
|
4
|
-
import { Dropdown, Label, Separator } from "@heroui/react";
|
|
5
|
-
import { SwitchAccountItem } from "./switch-account-item";
|
|
6
|
-
import { UserView } from "./user-view";
|
|
7
|
-
/**
|
|
8
|
-
* Render the menu content for switching between multiple authenticated sessions.
|
|
9
|
-
*
|
|
10
|
-
* Shows the current session with a checkmark, lists other device sessions that can be activated,
|
|
11
|
-
* and provides an option to add a new account. This component should be rendered inside a
|
|
12
|
-
* Dropdown.SubmenuTrigger to defer the useListDeviceSessions query until the submenu is opened.
|
|
13
|
-
*
|
|
14
|
-
* @returns The switch account menu content as a JSX element
|
|
15
|
-
*/
|
|
16
|
-
export function SwitchAccountMenu() {
|
|
17
|
-
const { basePaths, viewPaths, localization } = useAuth();
|
|
18
|
-
const { data: sessionData } = useSession();
|
|
19
|
-
const { data: deviceSessions, isPending } = useListDeviceSessions();
|
|
20
|
-
return (_jsx(Dropdown.Popover, { className: "min-w-40 md:min-w-56 max-w-[48svw]", children: _jsxs(Dropdown.Menu, { children: [_jsxs(Dropdown.Item, { className: "px-2", children: [_jsx(UserView, { isPending: isPending }), !isPending && _jsx(Check, { className: "ml-auto" })] }), deviceSessions
|
|
21
|
-
?.filter((deviceSession) => deviceSession.session.id !== sessionData?.session?.id)
|
|
22
|
-
.map((deviceSession) => (_jsx(SwitchAccountItem, { deviceSession: deviceSession }, deviceSession.session.id))), _jsx(Separator, {}), _jsxs(Dropdown.Item, { textValue: localization.auth.addAccount, href: `${basePaths.auth}/${viewPaths.auth.signIn}`, children: [_jsx(CirclePlus, { className: "text-muted" }), _jsx(Label, { children: localization.auth.addAccount })] })] }) }));
|
|
23
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { type AvatarProps } from "@heroui/react";
|
|
2
|
-
import type { User } from "better-auth";
|
|
3
|
-
import type { ReactNode } from "react";
|
|
4
|
-
export type UserAvatarProps = {
|
|
5
|
-
className?: string;
|
|
6
|
-
fallback?: ReactNode;
|
|
7
|
-
isPending?: boolean;
|
|
8
|
-
user?: User & {
|
|
9
|
-
username?: string | null;
|
|
10
|
-
displayUsername?: string | null;
|
|
11
|
-
};
|
|
12
|
-
size?: AvatarProps["size"];
|
|
13
|
-
};
|
|
14
|
-
/**
|
|
15
|
-
* Render a user avatar that shows the user's image, initials, or a custom fallback; displays a circular skeleton while the session (or explicit pending flag) is pending.
|
|
16
|
-
*
|
|
17
|
-
* @param className - Additional CSS classes applied to the outer avatar container
|
|
18
|
-
* @param fallback - Custom fallback content to render when no image or initials are available
|
|
19
|
-
* @param isPending - When true, force rendering of the loading skeleton (unless an explicit `user` prop is provided)
|
|
20
|
-
* @param user - Optional user object to display; when omitted the current session user is used if available
|
|
21
|
-
* @param size - Visual size of the avatar; one of `"sm"`, `"md"`, or `"lg"` (default: `"sm"`)
|
|
22
|
-
* @returns A React element that displays the user's avatar image, initials, or the provided fallback; renders a circular skeleton while loading
|
|
23
|
-
*/
|
|
24
|
-
export declare function UserAvatar({ className, fallback, isPending, user, size, style, ...props }: UserAvatarProps & AvatarProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useSession } from "@better-auth-ui/react";
|
|
3
|
-
import { Person } from "@gravity-ui/icons";
|
|
4
|
-
import { Avatar, cn, Skeleton } from "@heroui/react";
|
|
5
|
-
/**
|
|
6
|
-
* Render a user avatar that shows the user's image, initials, or a custom fallback; displays a circular skeleton while the session (or explicit pending flag) is pending.
|
|
7
|
-
*
|
|
8
|
-
* @param className - Additional CSS classes applied to the outer avatar container
|
|
9
|
-
* @param fallback - Custom fallback content to render when no image or initials are available
|
|
10
|
-
* @param isPending - When true, force rendering of the loading skeleton (unless an explicit `user` prop is provided)
|
|
11
|
-
* @param user - Optional user object to display; when omitted the current session user is used if available
|
|
12
|
-
* @param size - Visual size of the avatar; one of `"sm"`, `"md"`, or `"lg"` (default: `"sm"`)
|
|
13
|
-
* @returns A React element that displays the user's avatar image, initials, or the provided fallback; renders a circular skeleton while loading
|
|
14
|
-
*/
|
|
15
|
-
export function UserAvatar({ className, fallback, isPending, user, size = "sm", style, ...props }) {
|
|
16
|
-
const { data: sessionData, isPending: sessionPending } = useSession({
|
|
17
|
-
enabled: !user && !isPending
|
|
18
|
-
});
|
|
19
|
-
if ((isPending || sessionPending) && !user) {
|
|
20
|
-
return (_jsx(Skeleton, { className: cn("rounded-full", size === "sm" ? "size-8" : size === "md" ? "size-10" : "size-12", className), style: style }));
|
|
21
|
-
}
|
|
22
|
-
const resolvedUser = user ?? sessionData?.user;
|
|
23
|
-
const initials = (resolvedUser?.username ||
|
|
24
|
-
resolvedUser?.name ||
|
|
25
|
-
resolvedUser?.email)
|
|
26
|
-
?.slice(0, 2)
|
|
27
|
-
.toUpperCase();
|
|
28
|
-
return (_jsxs(Avatar, { size: size, className: cn("rounded-full", className), style: style, ...props, children: [_jsx(Avatar.Image, { alt: resolvedUser?.displayUsername ||
|
|
29
|
-
resolvedUser?.name ||
|
|
30
|
-
resolvedUser?.email, src: resolvedUser?.image ?? undefined }), _jsx(Avatar.Fallback, { className: cn(size === "lg" ? "text-xl" : size === "md" ? "text-base" : "text-sm"), delayMs: resolvedUser?.image ? 600 : undefined, children: fallback || initials || _jsx(Person, { className: "size-4" }) })] }));
|
|
31
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { type ButtonProps, type DropdownPopoverProps } from "@heroui/react";
|
|
2
|
-
export type UserButtonProps = {
|
|
3
|
-
className?: string;
|
|
4
|
-
size?: "default" | "icon";
|
|
5
|
-
placement?: DropdownPopoverProps["placement"];
|
|
6
|
-
themeToggle?: boolean;
|
|
7
|
-
variant?: ButtonProps["variant"];
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* Render a user account dropdown button that shows account actions, session switching, and theme controls.
|
|
11
|
-
*
|
|
12
|
-
* Renders either an icon-only trigger or a full button showing the current user state; its dropdown contains account settings, multi-session switching (when enabled), theme selection (when enabled), and sign-in/sign-out flows depending on authentication state.
|
|
13
|
-
*
|
|
14
|
-
* @param className - Additional CSS classes applied to the trigger element
|
|
15
|
-
* @param placement - Dropdown popover placement (e.g., "bottom", "top-start", "bottom-end")
|
|
16
|
-
* @param size - "icon" renders an avatar-only trigger; "default" renders a button with label and chevron
|
|
17
|
-
* @param variant - Button visual variant passed to the underlying Button component
|
|
18
|
-
* @param themeToggle - When true and theming is available, show theme selection controls in the menu
|
|
19
|
-
* @returns The user button and its dropdown menu as a JSX element
|
|
20
|
-
*/
|
|
21
|
-
export declare function UserButton({ className, placement, size, variant, themeToggle }: UserButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth, useSession } from "@better-auth-ui/react";
|
|
3
|
-
import { ArrowRightFromSquare, ArrowRightToSquare, ChevronsExpandVertical, Display, Gear, Moon, PersonPlus, Persons, Sun } from "@gravity-ui/icons";
|
|
4
|
-
import { Button, cn, Dropdown, Label, Separator, Tabs } from "@heroui/react";
|
|
5
|
-
import { SwitchAccountMenu } from "./switch-account-menu";
|
|
6
|
-
import { UserAvatar } from "./user-avatar";
|
|
7
|
-
import { UserView } from "./user-view";
|
|
8
|
-
/**
|
|
9
|
-
* Render a user account dropdown button that shows account actions, session switching, and theme controls.
|
|
10
|
-
*
|
|
11
|
-
* Renders either an icon-only trigger or a full button showing the current user state; its dropdown contains account settings, multi-session switching (when enabled), theme selection (when enabled), and sign-in/sign-out flows depending on authentication state.
|
|
12
|
-
*
|
|
13
|
-
* @param className - Additional CSS classes applied to the trigger element
|
|
14
|
-
* @param placement - Dropdown popover placement (e.g., "bottom", "top-start", "bottom-end")
|
|
15
|
-
* @param size - "icon" renders an avatar-only trigger; "default" renders a button with label and chevron
|
|
16
|
-
* @param variant - Button visual variant passed to the underlying Button component
|
|
17
|
-
* @param themeToggle - When true and theming is available, show theme selection controls in the menu
|
|
18
|
-
* @returns The user button and its dropdown menu as a JSX element
|
|
19
|
-
*/
|
|
20
|
-
export function UserButton({ className, placement = "bottom", size = "default", variant = "ghost", themeToggle = true }) {
|
|
21
|
-
const { basePaths, viewPaths, localization, multiSession, settings: { theme, setTheme, themes } } = useAuth();
|
|
22
|
-
const { data: sessionData, isPending: sessionPending } = useSession();
|
|
23
|
-
return (_jsxs(Dropdown, { children: [size === "icon" ? (_jsx(Dropdown.Trigger, { className: cn("rounded-full", className), children: _jsx(UserAvatar, {}) })) : (_jsxs(Button, { variant: variant, className: cn("h-auto font-normal justify-start px-3 py-2 text-left", className), children: [sessionData || sessionPending ? (_jsx(UserView, { isPending: sessionPending })) : (_jsxs(_Fragment, { children: [_jsx(UserAvatar, {}), _jsx("p", { className: "text-sm font-medium", children: localization.auth.account })] })), _jsx(ChevronsExpandVertical, { className: "ml-auto size-3.5" })] })), _jsxs(Dropdown.Popover, { placement: placement, className: "min-w-40 md:min-w-56 max-w-[48svw]", children: [sessionData && (_jsx("div", { className: "px-3 pt-3 pb-1", children: _jsx(UserView, {}) })), _jsx(Dropdown.Menu, { children: sessionData ? (_jsxs(_Fragment, { children: [_jsxs(Dropdown.Item, { textValue: localization.settings.settings, href: `${basePaths.settings}/${viewPaths.settings.account}`, children: [_jsx(Gear, { className: "text-muted" }), _jsx(Label, { children: localization.settings.settings })] }), multiSession && (_jsxs(Dropdown.SubmenuTrigger, { children: [_jsxs(Dropdown.Item, { textValue: localization.auth.switchAccount, children: [_jsx(Persons, { className: "text-muted" }), _jsx(Label, { children: localization.auth.switchAccount }), _jsx(Dropdown.SubmenuIndicator, {})] }), _jsx(Dropdown.Popover, { className: "min-w-40 md:min-w-56 max-w-[48svw]", children: _jsx(SwitchAccountMenu, {}) })] })), themeToggle && theme && setTheme && themes?.length && (_jsxs(Dropdown.Item, { className: "py-1 pe-2", children: [_jsx(Label, { children: localization.settings.theme }), _jsx(Tabs, { className: "ml-auto", selectedKey: theme, onSelectionChange: (key) => setTheme(key), children: _jsx(Tabs.ListContainer, { children: _jsxs(Tabs.List, { "aria-label": localization.settings.theme, className: "*:h-5 *:w-5 *:p-0", children: [themes.includes("system") && (_jsxs(Tabs.Tab, { id: "system", "aria-label": localization.settings.system, children: [_jsx(Display, { className: "size-3" }), _jsx(Tabs.Indicator, {})] })), themes.includes("light") && (_jsxs(Tabs.Tab, { id: "light", "aria-label": localization.settings.light, children: [_jsx(Sun, { className: "size-3" }), _jsx(Tabs.Indicator, {})] })), themes.includes("dark") && (_jsxs(Tabs.Tab, { id: "dark", "aria-label": localization.settings.dark, children: [_jsx(Moon, { className: "size-3" }), _jsx(Tabs.Indicator, {})] }))] }) }) })] })), _jsx(Separator, {}), _jsxs(Dropdown.Item, { textValue: localization.auth.signOut, href: `${basePaths.auth}/${viewPaths.auth.signOut}`, children: [_jsx(ArrowRightFromSquare, { className: "text-muted" }), _jsx(Label, { children: localization.auth.signOut })] })] })) : (_jsxs(_Fragment, { children: [_jsxs(Dropdown.Item, { textValue: localization.auth.signIn, href: `${basePaths.auth}/${viewPaths.auth.signIn}`, children: [_jsx(ArrowRightToSquare, { className: "text-muted" }), _jsx(Label, { children: localization.auth.signIn })] }), _jsxs(Dropdown.Item, { textValue: localization.auth.signUp, href: `${basePaths.auth}/${viewPaths.auth.signUp}`, children: [_jsx(PersonPlus, { className: "text-muted" }), _jsx(Label, { children: localization.auth.signUp })] })] })) })] })] }));
|
|
24
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { type AvatarProps } from "@heroui/react";
|
|
2
|
-
import type { User } from "better-auth";
|
|
3
|
-
import type { ComponentProps } from "react";
|
|
4
|
-
export type UserViewProps = {
|
|
5
|
-
className?: string;
|
|
6
|
-
isPending?: boolean;
|
|
7
|
-
size?: AvatarProps["size"];
|
|
8
|
-
user?: User & {
|
|
9
|
-
username?: string | null;
|
|
10
|
-
displayUsername?: string | null;
|
|
11
|
-
};
|
|
12
|
-
};
|
|
13
|
-
/**
|
|
14
|
-
* Render a compact user item with an avatar, a primary label (display username, name, or email), and an optional secondary email line.
|
|
15
|
-
*
|
|
16
|
-
* @param isPending - If true and no `user` prop is provided, renders a loading skeleton instead of user details
|
|
17
|
-
* @param size - Avatar size variant; defaults to `"sm"`
|
|
18
|
-
* @param user - Optional user to display; when omitted the current session user is used if available
|
|
19
|
-
* @returns A React element containing the user's avatar and text labels
|
|
20
|
-
*/
|
|
21
|
-
export declare function UserView({ className, isPending, size, user, ...props }: UserViewProps & ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useSession } from "@better-auth-ui/react";
|
|
3
|
-
import { cn, Skeleton } from "@heroui/react";
|
|
4
|
-
import { UserAvatar } from "./user-avatar";
|
|
5
|
-
/**
|
|
6
|
-
* Render a compact user item with an avatar, a primary label (display username, name, or email), and an optional secondary email line.
|
|
7
|
-
*
|
|
8
|
-
* @param isPending - If true and no `user` prop is provided, renders a loading skeleton instead of user details
|
|
9
|
-
* @param size - Avatar size variant; defaults to `"sm"`
|
|
10
|
-
* @param user - Optional user to display; when omitted the current session user is used if available
|
|
11
|
-
* @returns A React element containing the user's avatar and text labels
|
|
12
|
-
*/
|
|
13
|
-
export function UserView({ className, isPending, size = "sm", user, ...props }) {
|
|
14
|
-
const { data: sessionData, isPending: sessionPending } = useSession({
|
|
15
|
-
enabled: !user && !isPending
|
|
16
|
-
});
|
|
17
|
-
const resolvedUser = user ?? sessionData?.user;
|
|
18
|
-
if ((isPending || sessionPending) && !user) {
|
|
19
|
-
return (_jsxs("div", { className: cn("flex items-center gap-2 min-w-0", className), ...props, children: [_jsx(UserAvatar, { isPending: true, size: size }), _jsxs("div", { className: "flex flex-col gap-1 min-w-0", children: [_jsx(Skeleton, { className: "h-3.5 w-24 rounded-lg" }), _jsx(Skeleton, { className: "h-3 w-32 rounded-lg" })] })] }));
|
|
20
|
-
}
|
|
21
|
-
return (_jsxs("div", { className: cn("flex items-center gap-2 min-w-0", className), ...props, children: [_jsx(UserAvatar, { user: resolvedUser, size: size }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium truncate leading-tight", children: resolvedUser?.displayUsername ||
|
|
22
|
-
resolvedUser?.name ||
|
|
23
|
-
resolvedUser?.email }), (resolvedUser?.displayUsername || resolvedUser?.name) && (_jsx("p", { className: "text-muted text-xs mb-0.5 truncate overflow-x-hidden", children: resolvedUser?.email }))] })] }));
|
|
24
|
-
}
|
package/dist/src/core.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "@better-auth-ui/react/core";
|