@better-auth-ui/heroui 1.6.5 → 1.6.7
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/api-key/api-key-skeleton.d.ts +1 -0
- package/dist/components/auth/api-key/api-key-skeleton.js +21 -0
- package/dist/components/auth/api-key/api-key.d.ts +5 -0
- package/dist/components/auth/api-key/api-key.js +55 -0
- package/dist/components/auth/api-key/api-keys-empty.d.ts +4 -0
- package/dist/components/auth/api-key/api-keys-empty.js +35 -0
- package/dist/components/auth/api-key/api-keys.d.ts +6 -0
- package/dist/components/auth/api-key/api-keys.js +41 -0
- package/dist/components/auth/api-key/create-api-key-dialog.d.ts +5 -0
- package/dist/components/auth/api-key/create-api-key-dialog.js +74 -0
- package/dist/components/auth/api-key/delete-api-key-dialog.d.ts +7 -0
- package/dist/components/auth/api-key/delete-api-key-dialog.js +51 -0
- package/dist/components/auth/api-key/new-api-key-dialog.d.ts +7 -0
- package/dist/components/auth/api-key/new-api-key-dialog.js +60 -0
- package/dist/components/auth/delete-user/danger-zone.js +1 -1
- package/dist/components/auth/delete-user/delete-user.js +53 -53
- package/dist/components/auth/multi-session/switch-account-submenu-content.js +14 -15
- package/dist/components/auth/passkey/add-passkey-dialog.d.ts +0 -0
- package/dist/components/auth/passkey/delete-passkey-dialog.d.ts +0 -0
- package/dist/components/auth/passkey/passkey-skeleton.d.ts +0 -0
- package/dist/components/auth/passkey/passkeys-empty.d.ts +0 -0
- package/dist/components/auth/settings/security/linked-account.js +1 -1
- package/dist/components/auth/theme/theme-toggle-item.js +50 -46
- package/dist/components/auth/user/user-button.d.ts +27 -2
- package/dist/components/auth/user/user-button.js +48 -29
- package/dist/lib/auth/api-key-plugin.d.ts +23 -0
- package/dist/lib/auth/api-key-plugin.js +10 -0
- package/dist/plugins.d.ts +2 -0
- package/dist/plugins.js +22 -20
- package/package.json +14 -14
- package/src/components/auth/api-key/api-key-skeleton.tsx +17 -0
- package/src/components/auth/api-key/api-key.tsx +64 -0
- package/src/components/auth/api-key/api-keys-empty.tsx +33 -0
- package/src/components/auth/api-key/api-keys.tsx +71 -0
- package/src/components/auth/api-key/create-api-key-dialog.tsx +134 -0
- package/src/components/auth/api-key/delete-api-key-dialog.tsx +92 -0
- package/src/components/auth/api-key/new-api-key-dialog.tsx +94 -0
- package/src/components/auth/delete-user/danger-zone.tsx +1 -1
- package/src/components/auth/delete-user/delete-user.tsx +2 -7
- package/src/components/auth/multi-session/switch-account-submenu-content.tsx +1 -3
- package/src/components/auth/passkey/add-passkey-dialog.tsx +0 -0
- package/src/components/auth/passkey/delete-passkey-dialog.tsx +0 -0
- package/src/components/auth/passkey/passkey-skeleton.tsx +0 -0
- package/src/components/auth/passkey/passkeys-empty.tsx +0 -0
- package/src/components/auth/settings/security/linked-account.tsx +2 -4
- package/src/components/auth/theme/theme-toggle-item.tsx +2 -1
- package/src/components/auth/user/user-button.tsx +80 -13
- package/src/lib/auth/api-key-plugin.ts +15 -0
- package/src/plugins.ts +2 -0
|
@@ -1,58 +1,62 @@
|
|
|
1
1
|
import { themePlugin as e } from "../../../lib/auth/theme-plugin.js";
|
|
2
2
|
import { useAuthPlugin as t } from "@better-auth-ui/react";
|
|
3
|
-
import { Display as n, Moon as r,
|
|
4
|
-
import { Dropdown as
|
|
5
|
-
import { jsx as
|
|
3
|
+
import { Display as n, Moon as r, Palette as i, Sun as a } from "@gravity-ui/icons";
|
|
4
|
+
import { Dropdown as o, Label as s, Tabs as c } from "@heroui/react";
|
|
5
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
6
6
|
//#region src/components/auth/theme/theme-toggle-item.tsx
|
|
7
|
-
var
|
|
8
|
-
function
|
|
9
|
-
let { useTheme:
|
|
10
|
-
return /* @__PURE__ */
|
|
7
|
+
var d = "[role=\"tab\"][aria-selected=\"true\"]";
|
|
8
|
+
function f() {
|
|
9
|
+
let { useTheme: f, localization: p } = t(e), { theme: m, setTheme: h, themes: g = [] } = f();
|
|
10
|
+
return /* @__PURE__ */ u(o.Item, {
|
|
11
11
|
className: "py-1 pe-2",
|
|
12
12
|
onFocus: (e) => {
|
|
13
|
-
e.target === e.currentTarget && e.currentTarget.querySelector(
|
|
13
|
+
e.target === e.currentTarget && e.currentTarget.querySelector(d)?.focus({ preventScroll: !0 });
|
|
14
14
|
},
|
|
15
15
|
shouldCloseOnSelect: !1,
|
|
16
|
-
children: [
|
|
17
|
-
className: "
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
children:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
16
|
+
children: [
|
|
17
|
+
/* @__PURE__ */ l(i, { className: "text-muted" }),
|
|
18
|
+
/* @__PURE__ */ l(s, { children: p.theme }),
|
|
19
|
+
/* @__PURE__ */ l(c, {
|
|
20
|
+
className: "ml-auto",
|
|
21
|
+
selectedKey: m,
|
|
22
|
+
onSelectionChange: (e) => h(e),
|
|
23
|
+
children: /* @__PURE__ */ l(c.ListContainer, {
|
|
24
|
+
onKeyDown: (e) => {
|
|
25
|
+
if (e.key !== "ArrowUp" && e.key !== "ArrowDown") return;
|
|
26
|
+
let t = e.target;
|
|
27
|
+
if (t.getAttribute("role") !== "tab") return;
|
|
28
|
+
let n = t.closest("[role=\"menuitem\"]"), r = n?.closest("[role=\"menu\"]");
|
|
29
|
+
if (!n || !r) return;
|
|
30
|
+
let i = Array.from(r.querySelectorAll("[role=\"menuitem\"]:not([data-disabled])")), a = i.indexOf(n);
|
|
31
|
+
if (a === -1) return;
|
|
32
|
+
let o = i[e.key === "ArrowDown" ? a + 1 : a - 1];
|
|
33
|
+
o && (e.preventDefault(), o.focus());
|
|
34
|
+
},
|
|
35
|
+
children: /* @__PURE__ */ u(c.List, {
|
|
36
|
+
"aria-label": p.theme,
|
|
37
|
+
className: "*:h-5 *:w-5 *:p-0",
|
|
38
|
+
children: [
|
|
39
|
+
g.includes("system") && /* @__PURE__ */ u(c.Tab, {
|
|
40
|
+
id: "system",
|
|
41
|
+
"aria-label": p.system,
|
|
42
|
+
children: [/* @__PURE__ */ l(n, { className: "size-3" }), /* @__PURE__ */ l(c.Indicator, {})]
|
|
43
|
+
}),
|
|
44
|
+
g.includes("light") && /* @__PURE__ */ u(c.Tab, {
|
|
45
|
+
id: "light",
|
|
46
|
+
"aria-label": p.light,
|
|
47
|
+
children: [/* @__PURE__ */ l(a, { className: "size-3" }), /* @__PURE__ */ l(c.Indicator, {})]
|
|
48
|
+
}),
|
|
49
|
+
g.includes("dark") && /* @__PURE__ */ u(c.Tab, {
|
|
50
|
+
id: "dark",
|
|
51
|
+
"aria-label": p.dark,
|
|
52
|
+
children: [/* @__PURE__ */ l(r, { className: "size-3" }), /* @__PURE__ */ l(c.Indicator, {})]
|
|
53
|
+
})
|
|
54
|
+
]
|
|
55
|
+
})
|
|
52
56
|
})
|
|
53
57
|
})
|
|
54
|
-
|
|
58
|
+
]
|
|
55
59
|
});
|
|
56
60
|
}
|
|
57
61
|
//#endregion
|
|
58
|
-
export {
|
|
62
|
+
export { f as ThemeToggleItem };
|
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
import { ButtonProps, DropdownPopoverProps } from '@heroui/react';
|
|
1
|
+
import { ButtonProps, DropdownItemProps, DropdownPopoverProps } from '@heroui/react';
|
|
2
|
+
import { ReactElement, ReactNode } from 'react';
|
|
3
|
+
/** Auth states a `UserButton` link can be visible in. */
|
|
4
|
+
export type UserButtonLinkVisibility = "authenticated" | "unauthenticated" | "always";
|
|
5
|
+
/** A simple link entry rendered as a `Dropdown.Item` in the `UserButton` menu. */
|
|
6
|
+
export type UserButtonLink = {
|
|
7
|
+
/** Visible label. */
|
|
8
|
+
label: ReactNode;
|
|
9
|
+
/** Destination URL. */
|
|
10
|
+
href: string;
|
|
11
|
+
/** Optional leading icon. Sized/coloured to match built-in items. */
|
|
12
|
+
icon?: ReactNode;
|
|
13
|
+
/** Forwarded to the underlying `Dropdown.Item`. */
|
|
14
|
+
variant?: DropdownItemProps["variant"];
|
|
15
|
+
/**
|
|
16
|
+
* When this link is visible based on auth state.
|
|
17
|
+
* @default "always"
|
|
18
|
+
*/
|
|
19
|
+
visibility?: UserButtonLinkVisibility;
|
|
20
|
+
};
|
|
2
21
|
export type UserButtonProps = {
|
|
3
22
|
className?: string;
|
|
4
23
|
size?: "default" | "icon";
|
|
@@ -8,6 +27,10 @@ export type UserButtonProps = {
|
|
|
8
27
|
*/
|
|
9
28
|
placement?: DropdownPopoverProps["placement"];
|
|
10
29
|
variant?: ButtonProps["variant"];
|
|
30
|
+
/** Additional menu entries rendered above the built-in items. */
|
|
31
|
+
links?: (UserButtonLink | ReactElement)[];
|
|
32
|
+
/** Hide the built-in "Settings" link. Useful when replacing it via `links`. */
|
|
33
|
+
hideSettings?: boolean;
|
|
11
34
|
};
|
|
12
35
|
/**
|
|
13
36
|
* Render a user account dropdown button that shows account actions.
|
|
@@ -16,6 +39,8 @@ export type UserButtonProps = {
|
|
|
16
39
|
* @param placement - Dropdown popover placement (e.g., "bottom", "top-start", "bottom-end")
|
|
17
40
|
* @param size - "icon" renders an avatar-only trigger; "default" renders a button with label and chevron
|
|
18
41
|
* @param variant - Button visual variant passed to the underlying Button component
|
|
42
|
+
* @param links - Additional menu entries rendered above the built-in items
|
|
43
|
+
* @param hideSettings - Hide the built-in "Settings" link
|
|
19
44
|
* @returns The user button and its dropdown menu as a JSX element
|
|
20
45
|
*/
|
|
21
|
-
export declare function UserButton({ className, placement, size, variant }: UserButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
46
|
+
export declare function UserButton({ className, placement, size, variant, links, hideSettings }: UserButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,54 +2,73 @@ import { UserAvatar as e } from "./user-avatar.js";
|
|
|
2
2
|
import { UserView as t } from "./user-view.js";
|
|
3
3
|
import { useAuth as n, useSession as r } from "@better-auth-ui/react";
|
|
4
4
|
import { ArrowRightFromSquare as i, ArrowRightToSquare as a, ChevronsExpandVertical as o, Gear as s, PersonPlus as c } from "@gravity-ui/icons";
|
|
5
|
-
import { Button as l, Dropdown as u, Label as d,
|
|
5
|
+
import { Button as l, Dropdown as u, Label as d, cn as f } from "@heroui/react";
|
|
6
|
+
import { isValidElement as p } from "react";
|
|
6
7
|
import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
7
8
|
//#region src/components/auth/user/user-button.tsx
|
|
8
|
-
function _(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
function _(e, t) {
|
|
10
|
+
if (p(e)) return e;
|
|
11
|
+
let { label: n, href: r, icon: i, variant: a } = e;
|
|
12
|
+
return /* @__PURE__ */ g(u.Item, {
|
|
13
|
+
href: r,
|
|
14
|
+
variant: a,
|
|
15
|
+
textValue: typeof n == "string" ? n : void 0,
|
|
16
|
+
children: [i, /* @__PURE__ */ h(d, { children: n })]
|
|
17
|
+
}, t);
|
|
18
|
+
}
|
|
19
|
+
function v({ className: v, placement: y = "bottom", size: b = "default", variant: x = "ghost", links: S, hideSettings: C = !1 }) {
|
|
20
|
+
let { authClient: w, basePaths: T, viewPaths: E, localization: D, plugins: O } = n(), { data: k, isPending: A } = r(w), j = O.flatMap((e) => e.userMenuItems?.map((t, n) => /* @__PURE__ */ h(t, {}, `${e.id}-${n.toString()}`)) ?? []), M = S?.flatMap((e, t) => {
|
|
21
|
+
if (!p(e)) {
|
|
22
|
+
let t = e.visibility ?? "always";
|
|
23
|
+
if (t === "authenticated" && !k || t === "unauthenticated" && k) return [];
|
|
24
|
+
}
|
|
25
|
+
return [_(e, `user-button-link-${t.toString()}`)];
|
|
26
|
+
});
|
|
27
|
+
return /* @__PURE__ */ g(u, { children: [b === "icon" ? /* @__PURE__ */ h(u.Trigger, {
|
|
28
|
+
className: f("rounded-full", v),
|
|
12
29
|
children: /* @__PURE__ */ h(e, {})
|
|
13
30
|
}) : /* @__PURE__ */ g(l, {
|
|
14
|
-
variant:
|
|
15
|
-
className:
|
|
16
|
-
children: [
|
|
31
|
+
variant: x,
|
|
32
|
+
className: f("h-auto font-normal justify-start px-3 py-2 text-left", v),
|
|
33
|
+
children: [k || A ? /* @__PURE__ */ h(t, { isPending: A }) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(e, {}), /* @__PURE__ */ h("p", {
|
|
17
34
|
className: "text-sm font-medium",
|
|
18
|
-
children:
|
|
35
|
+
children: D.auth.account
|
|
19
36
|
})] }), /* @__PURE__ */ h(o, { className: "ml-auto size-3.5" })]
|
|
20
37
|
}), /* @__PURE__ */ g(u.Popover, {
|
|
21
|
-
placement:
|
|
38
|
+
placement: y,
|
|
22
39
|
className: "min-w-40 md:min-w-56 max-w-[48svw]",
|
|
23
|
-
children: [
|
|
40
|
+
children: [k && /* @__PURE__ */ h("div", {
|
|
24
41
|
className: "px-3 pt-3 pb-1",
|
|
25
42
|
children: /* @__PURE__ */ h(t, {})
|
|
26
|
-
}), /* @__PURE__ */ h(u.Menu, { children:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
43
|
+
}), /* @__PURE__ */ h(u.Menu, { children: k ? /* @__PURE__ */ g(m, { children: [
|
|
44
|
+
M,
|
|
45
|
+
!C && /* @__PURE__ */ g(u.Item, {
|
|
46
|
+
textValue: D.settings.settings,
|
|
47
|
+
href: `${T.settings}/${E.settings.account}`,
|
|
48
|
+
children: [/* @__PURE__ */ h(s, { className: "text-muted" }), /* @__PURE__ */ h(d, { children: D.settings.settings })]
|
|
31
49
|
}),
|
|
32
|
-
|
|
33
|
-
/* @__PURE__ */ h(f, {}),
|
|
50
|
+
j,
|
|
34
51
|
/* @__PURE__ */ g(u.Item, {
|
|
35
|
-
textValue:
|
|
36
|
-
href: `${
|
|
37
|
-
|
|
52
|
+
textValue: D.auth.signOut,
|
|
53
|
+
href: `${T.auth}/${E.auth.signOut}`,
|
|
54
|
+
variant: "danger",
|
|
55
|
+
children: [/* @__PURE__ */ h(i, { className: "text-danger" }), /* @__PURE__ */ h(d, { children: D.auth.signOut })]
|
|
38
56
|
})
|
|
39
57
|
] }) : /* @__PURE__ */ g(m, { children: [
|
|
58
|
+
M,
|
|
40
59
|
/* @__PURE__ */ g(u.Item, {
|
|
41
|
-
textValue:
|
|
42
|
-
href: `${
|
|
43
|
-
children: [/* @__PURE__ */ h(a, { className: "text-muted" }), /* @__PURE__ */ h(d, { children:
|
|
60
|
+
textValue: D.auth.signIn,
|
|
61
|
+
href: `${T.auth}/${E.auth.signIn}`,
|
|
62
|
+
children: [/* @__PURE__ */ h(a, { className: "text-muted" }), /* @__PURE__ */ h(d, { children: D.auth.signIn })]
|
|
44
63
|
}),
|
|
45
64
|
/* @__PURE__ */ g(u.Item, {
|
|
46
|
-
textValue:
|
|
47
|
-
href: `${
|
|
48
|
-
children: [/* @__PURE__ */ h(c, { className: "text-muted" }), /* @__PURE__ */ h(d, { children:
|
|
65
|
+
textValue: D.auth.signUp,
|
|
66
|
+
href: `${T.auth}/${E.auth.signUp}`,
|
|
67
|
+
children: [/* @__PURE__ */ h(c, { className: "text-muted" }), /* @__PURE__ */ h(d, { children: D.auth.signUp })]
|
|
49
68
|
}),
|
|
50
|
-
|
|
69
|
+
j
|
|
51
70
|
] }) })]
|
|
52
71
|
})] });
|
|
53
72
|
}
|
|
54
73
|
//#endregion
|
|
55
|
-
export {
|
|
74
|
+
export { v as UserButton };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ApiKeyPluginOptions } from '@better-auth-ui/core/plugins';
|
|
2
|
+
import { ApiKeys } from '../../components/auth/api-key/api-keys';
|
|
3
|
+
export declare const apiKeyPlugin: ((options?: ApiKeyPluginOptions | undefined) => Omit<{
|
|
4
|
+
securityCards: (typeof ApiKeys)[];
|
|
5
|
+
localization: {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
apiKeys: string;
|
|
8
|
+
apiKeysDescription: string;
|
|
9
|
+
createApiKey: string;
|
|
10
|
+
noApiKeys: string;
|
|
11
|
+
name: string;
|
|
12
|
+
newApiKey: string;
|
|
13
|
+
newApiKeyWarning: string;
|
|
14
|
+
deleteApiKey: string;
|
|
15
|
+
deleteApiKeyWarning: string;
|
|
16
|
+
dismissNewKey: string;
|
|
17
|
+
};
|
|
18
|
+
id: "apiKey";
|
|
19
|
+
}, "id"> & {
|
|
20
|
+
id: "apiKey";
|
|
21
|
+
}) & {
|
|
22
|
+
id: "apiKey";
|
|
23
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ApiKeys as e } from "../../components/auth/api-key/api-keys.js";
|
|
2
|
+
import { createAuthPlugin as t } from "@better-auth-ui/core";
|
|
3
|
+
import { apiKeyPlugin as n } from "@better-auth-ui/core/plugins";
|
|
4
|
+
//#region src/lib/auth/api-key-plugin.ts
|
|
5
|
+
var r = t(n.id, (t = {}) => ({
|
|
6
|
+
...n(t),
|
|
7
|
+
securityCards: [e]
|
|
8
|
+
}));
|
|
9
|
+
//#endregion
|
|
10
|
+
export { r as apiKeyPlugin };
|
package/dist/plugins.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from './components/auth/api-key/api-keys';
|
|
1
2
|
export * from './components/auth/delete-user/danger-zone';
|
|
2
3
|
export * from './components/auth/delete-user/delete-user';
|
|
3
4
|
export * from './components/auth/magic-link/magic-link';
|
|
@@ -11,6 +12,7 @@ export * from './components/auth/theme/appearance';
|
|
|
11
12
|
export * from './components/auth/theme/theme-toggle-item';
|
|
12
13
|
export * from './components/auth/username/sign-in-username';
|
|
13
14
|
export * from './components/auth/username/username-field';
|
|
15
|
+
export * from './lib/auth/api-key-plugin';
|
|
14
16
|
export * from './lib/auth/auth-plugin';
|
|
15
17
|
export * from './lib/auth/delete-user-plugin';
|
|
16
18
|
export * from './lib/auth/magic-link-plugin';
|
package/dist/plugins.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
|
|
2
|
+
import { apiKeyPlugin as e } from "./lib/auth/api-key-plugin.js";
|
|
3
|
+
import { ApiKeys as t } from "./components/auth/api-key/api-keys.js";
|
|
4
|
+
import { deleteUserPlugin as n } from "./lib/auth/delete-user-plugin.js";
|
|
5
|
+
import { DeleteUser as r } from "./components/auth/delete-user/delete-user.js";
|
|
6
|
+
import { DangerZone as i } from "./components/auth/delete-user/danger-zone.js";
|
|
7
|
+
import { magicLinkPlugin as a } from "./lib/auth/magic-link-plugin.js";
|
|
8
|
+
import { MagicLink as o } from "./components/auth/magic-link/magic-link.js";
|
|
9
|
+
import { ManageAccounts as s } from "./components/auth/multi-session/manage-accounts.js";
|
|
10
|
+
import { SwitchAccountSubmenuItem as c } from "./components/auth/multi-session/switch-account-submenu-item.js";
|
|
11
|
+
import { SwitchAccountSubmenuContent as l } from "./components/auth/multi-session/switch-account-submenu-content.js";
|
|
12
|
+
import { SwitchAccountSubmenu as u } from "./components/auth/multi-session/switch-account-submenu.js";
|
|
13
|
+
import { multiSessionPlugin as d } from "./lib/auth/multi-session-plugin.js";
|
|
14
|
+
import { ManageAccount as f } from "./components/auth/multi-session/manage-account.js";
|
|
15
|
+
import { passkeyPlugin as p } from "./lib/auth/passkey-plugin.js";
|
|
16
|
+
import { Passkeys as m } from "./components/auth/passkey/passkeys.js";
|
|
17
|
+
import { ThemeToggleItem as h } from "./components/auth/theme/theme-toggle-item.js";
|
|
18
|
+
import { themePlugin as g } from "./lib/auth/theme-plugin.js";
|
|
19
|
+
import { Appearance as _ } from "./components/auth/theme/appearance.js";
|
|
20
|
+
import { UsernameField as v } from "./components/auth/username/username-field.js";
|
|
21
|
+
import { usernamePlugin as y } from "./lib/auth/username-plugin.js";
|
|
22
|
+
import { SignInUsername as b } from "./components/auth/username/sign-in-username.js";
|
|
23
|
+
export { t as ApiKeys, _ as Appearance, i as DangerZone, r as DeleteUser, o as MagicLink, f as ManageAccount, s as ManageAccounts, m as Passkeys, b as SignInUsername, u as SwitchAccountSubmenu, l as SwitchAccountSubmenuContent, c as SwitchAccountSubmenuItem, h as ThemeToggleItem, v as UsernameField, e as apiKeyPlugin, n as deleteUserPlugin, a as magicLinkPlugin, d as multiSessionPlugin, p as passkeyPlugin, g as themePlugin, y as usernamePlugin };
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth-ui/heroui",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "vite build",
|
|
7
|
-
"dev": "
|
|
7
|
+
"dev": "tsc --watch",
|
|
8
8
|
"test": "vitest"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
@@ -28,35 +28,35 @@
|
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@gravity-ui/icons": "^2.18.0",
|
|
31
|
-
"@heroui/react": "^3.0.
|
|
32
|
-
"@heroui/styles": "^3.0.
|
|
31
|
+
"@heroui/react": "^3.0.4",
|
|
32
|
+
"@heroui/styles": "^3.0.4",
|
|
33
33
|
"@internationalized/date": "^3.12.1",
|
|
34
34
|
"@tanstack/react-pacer": "^0.22.0",
|
|
35
|
-
"@tanstack/react-query": "^5.100.
|
|
35
|
+
"@tanstack/react-query": "^5.100.9",
|
|
36
36
|
"@testing-library/react": "^16.3.2",
|
|
37
37
|
"@testing-library/user-event": "^14.5.2",
|
|
38
38
|
"@types/react": "^19.2.14",
|
|
39
39
|
"@vitejs/plugin-react": "^6.0.1",
|
|
40
40
|
"@vitest/browser-playwright": "^4.1.5",
|
|
41
|
-
"better-auth": "^1.6.
|
|
41
|
+
"better-auth": "^1.6.10",
|
|
42
42
|
"bowser": "^2.11.0",
|
|
43
43
|
"playwright": "^1.59.1",
|
|
44
|
-
"react": "^19.2.
|
|
45
|
-
"react-dom": "^19.2.
|
|
44
|
+
"react": "^19.2.6",
|
|
45
|
+
"react-dom": "^19.2.6",
|
|
46
46
|
"vitest": "^4.1.5"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"@better-auth-ui/core": "*",
|
|
50
50
|
"@better-auth-ui/react": "*",
|
|
51
51
|
"@gravity-ui/icons": ">=2.18.0",
|
|
52
|
-
"@heroui/react": ">=3.0.
|
|
53
|
-
"@heroui/styles": ">=3.0.
|
|
52
|
+
"@heroui/react": ">=3.0.4",
|
|
53
|
+
"@heroui/styles": ">=3.0.4",
|
|
54
54
|
"@internationalized/date": ">=3.12.1",
|
|
55
55
|
"@tanstack/react-pacer": ">=0.22.0",
|
|
56
|
-
"@tanstack/react-query": ">=5.100.
|
|
57
|
-
"better-auth": ">=1.6.
|
|
58
|
-
"react": ">=19.2.
|
|
59
|
-
"react-dom": ">=19.2.
|
|
56
|
+
"@tanstack/react-query": ">=5.100.9",
|
|
57
|
+
"better-auth": ">=1.6.10",
|
|
58
|
+
"react": ">=19.2.6",
|
|
59
|
+
"react-dom": ">=19.2.6",
|
|
60
60
|
"bowser": ">=2.11.0"
|
|
61
61
|
},
|
|
62
62
|
"repository": {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Skeleton } from "@heroui/react"
|
|
2
|
+
|
|
3
|
+
export function ApiKeySkeleton() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="flex items-center justify-between">
|
|
6
|
+
<div className="flex items-center gap-3">
|
|
7
|
+
<Skeleton className="size-10 rounded-xl" />
|
|
8
|
+
|
|
9
|
+
<div className="flex flex-col gap-1">
|
|
10
|
+
<Skeleton className="h-4 w-28 rounded-lg" />
|
|
11
|
+
<Skeleton className="h-3 w-36 rounded-lg" />
|
|
12
|
+
<Skeleton className="h-3 w-32 rounded-lg" />
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ListedApiKey,
|
|
3
|
+
useAuth,
|
|
4
|
+
useAuthPlugin
|
|
5
|
+
} from "@better-auth-ui/react"
|
|
6
|
+
import { Key, Xmark } from "@gravity-ui/icons"
|
|
7
|
+
import { Button } from "@heroui/react"
|
|
8
|
+
import { useState } from "react"
|
|
9
|
+
|
|
10
|
+
import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin"
|
|
11
|
+
import { DeleteApiKeyDialog } from "./delete-api-key-dialog"
|
|
12
|
+
|
|
13
|
+
export type ApiKeyProps = {
|
|
14
|
+
apiKey: ListedApiKey
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function ApiKey({ apiKey }: ApiKeyProps) {
|
|
18
|
+
const { localization } = useAuth()
|
|
19
|
+
const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin)
|
|
20
|
+
const [deleteOpen, setDeleteOpen] = useState(false)
|
|
21
|
+
|
|
22
|
+
const preview = `${apiKey.start}${"*".repeat(16)}`
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div className="flex items-center gap-3">
|
|
26
|
+
<div className="flex size-10 shrink-0 items-center justify-center rounded-xl bg-surface-secondary">
|
|
27
|
+
<Key className="size-4.5" />
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div className="flex flex-col min-w-0">
|
|
31
|
+
<span className="text-sm font-medium leading-tight truncate">
|
|
32
|
+
{apiKey.name || apiKeyLocalization.apiKey}
|
|
33
|
+
</span>
|
|
34
|
+
|
|
35
|
+
<span className="text-xs text-muted font-mono truncate">{preview}</span>
|
|
36
|
+
|
|
37
|
+
<span className="text-xs text-muted">
|
|
38
|
+
{new Date(apiKey.createdAt).toLocaleString(undefined, {
|
|
39
|
+
dateStyle: "medium",
|
|
40
|
+
timeStyle: "short"
|
|
41
|
+
})}
|
|
42
|
+
</span>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<Button
|
|
46
|
+
className="ml-auto shrink-0"
|
|
47
|
+
variant="outline"
|
|
48
|
+
size="sm"
|
|
49
|
+
onPress={() => setDeleteOpen(true)}
|
|
50
|
+
aria-label={apiKeyLocalization.deleteApiKey}
|
|
51
|
+
>
|
|
52
|
+
<Xmark />
|
|
53
|
+
|
|
54
|
+
{localization.settings.delete}
|
|
55
|
+
</Button>
|
|
56
|
+
|
|
57
|
+
<DeleteApiKeyDialog
|
|
58
|
+
isOpen={deleteOpen}
|
|
59
|
+
onOpenChange={setDeleteOpen}
|
|
60
|
+
apiKey={apiKey}
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useAuthPlugin } from "@better-auth-ui/react"
|
|
2
|
+
import { Key } from "@gravity-ui/icons"
|
|
3
|
+
import { Button } from "@heroui/react"
|
|
4
|
+
|
|
5
|
+
import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin"
|
|
6
|
+
|
|
7
|
+
export type ApiKeysEmptyProps = {
|
|
8
|
+
onCreatePress: () => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function ApiKeysEmpty({ onCreatePress }: ApiKeysEmptyProps) {
|
|
12
|
+
const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin)
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div className="flex flex-col items-center justify-center gap-4">
|
|
16
|
+
<div className="flex size-10 items-center justify-center rounded-xl bg-surface-secondary">
|
|
17
|
+
<Key className="size-4.5" />
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div className="flex flex-col items-center justify-center gap-1 text-center">
|
|
21
|
+
<p className="text-sm font-semibold">{apiKeyLocalization.noApiKeys}</p>
|
|
22
|
+
|
|
23
|
+
<p className="text-muted text-xs">
|
|
24
|
+
{apiKeyLocalization.apiKeysDescription}
|
|
25
|
+
</p>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<Button size="sm" onPress={onCreatePress}>
|
|
29
|
+
{apiKeyLocalization.createApiKey}
|
|
30
|
+
</Button>
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ApiKeyAuthClient,
|
|
3
|
+
useAuth,
|
|
4
|
+
useAuthPlugin,
|
|
5
|
+
useListApiKeys
|
|
6
|
+
} from "@better-auth-ui/react"
|
|
7
|
+
import { Button, Card, type CardProps, cn } from "@heroui/react"
|
|
8
|
+
import { useState } from "react"
|
|
9
|
+
|
|
10
|
+
import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin"
|
|
11
|
+
import { ApiKey } from "./api-key"
|
|
12
|
+
import { ApiKeySkeleton } from "./api-key-skeleton"
|
|
13
|
+
import { ApiKeysEmpty } from "./api-keys-empty"
|
|
14
|
+
import { CreateApiKeyDialog } from "./create-api-key-dialog"
|
|
15
|
+
|
|
16
|
+
export type ApiKeysProps = {
|
|
17
|
+
className?: string
|
|
18
|
+
variant?: CardProps["variant"]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function ApiKeys({ className, variant }: ApiKeysProps) {
|
|
22
|
+
const { authClient } = useAuth()
|
|
23
|
+
const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin)
|
|
24
|
+
|
|
25
|
+
const { data: listData, isPending } = useListApiKeys(
|
|
26
|
+
authClient as ApiKeyAuthClient
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
const [createOpen, setCreateOpen] = useState(false)
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div className={cn("flex flex-col gap-3", className)}>
|
|
33
|
+
<div className="flex items-end justify-between gap-3">
|
|
34
|
+
<h2 className="text-sm font-semibold truncate">
|
|
35
|
+
{apiKeyLocalization.apiKeys}
|
|
36
|
+
</h2>
|
|
37
|
+
|
|
38
|
+
<Button
|
|
39
|
+
className="shrink-0"
|
|
40
|
+
size="sm"
|
|
41
|
+
isDisabled={isPending}
|
|
42
|
+
onPress={() => setCreateOpen(true)}
|
|
43
|
+
>
|
|
44
|
+
{apiKeyLocalization.createApiKey}
|
|
45
|
+
</Button>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<Card variant={variant}>
|
|
49
|
+
<Card.Content>
|
|
50
|
+
{isPending ? (
|
|
51
|
+
<ApiKeySkeleton />
|
|
52
|
+
) : !listData?.apiKeys.length ? (
|
|
53
|
+
<ApiKeysEmpty onCreatePress={() => setCreateOpen(true)} />
|
|
54
|
+
) : (
|
|
55
|
+
listData?.apiKeys.map((key, index) => (
|
|
56
|
+
<div key={key.id}>
|
|
57
|
+
{index > 0 && (
|
|
58
|
+
<div className="border-b border-dashed -mx-4 my-4" />
|
|
59
|
+
)}
|
|
60
|
+
|
|
61
|
+
<ApiKey apiKey={key} />
|
|
62
|
+
</div>
|
|
63
|
+
))
|
|
64
|
+
)}
|
|
65
|
+
</Card.Content>
|
|
66
|
+
</Card>
|
|
67
|
+
|
|
68
|
+
<CreateApiKeyDialog isOpen={createOpen} onOpenChange={setCreateOpen} />
|
|
69
|
+
</div>
|
|
70
|
+
)
|
|
71
|
+
}
|