@better-auth-ui/heroui 1.6.9 → 1.6.11

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 (191) hide show
  1. package/dist/components/auth/additional-field.d.ts +2 -2
  2. package/dist/components/auth/api-key/api-key.d.ts +1 -1
  3. package/dist/components/auth/api-key/api-keys.d.ts +1 -1
  4. package/dist/components/auth/api-key/delete-api-key-dialog.d.ts +1 -1
  5. package/dist/components/auth/api-key/organization-api-keys.d.ts +1 -1
  6. package/dist/components/auth/auth-provider.d.ts +1 -1
  7. package/dist/components/auth/auth.d.ts +3 -3
  8. package/dist/components/auth/delete-user/danger-zone.d.ts +2 -2
  9. package/dist/components/auth/delete-user/delete-account.d.ts +1 -1
  10. package/dist/components/auth/email/email-changed-email.d.ts +2 -2
  11. package/dist/components/auth/email/email-verification-email.d.ts +2 -2
  12. package/dist/components/auth/email/magic-link-email.d.ts +2 -2
  13. package/dist/components/auth/email/new-device-email.d.ts +2 -2
  14. package/dist/components/auth/email/organization-invitation-email.d.ts +2 -2
  15. package/dist/components/auth/email/otp-email.d.ts +2 -2
  16. package/dist/components/auth/email/password-changed-email.d.ts +2 -2
  17. package/dist/components/auth/email/reset-password-email.d.ts +2 -2
  18. package/dist/components/auth/field-separator.d.ts +1 -1
  19. package/dist/components/auth/forgot-password.d.ts +1 -1
  20. package/dist/components/auth/magic-link/magic-link-button.d.ts +1 -1
  21. package/dist/components/auth/magic-link/magic-link.d.ts +2 -2
  22. package/dist/components/auth/multi-session/manage-account.d.ts +1 -1
  23. package/dist/components/auth/multi-session/manage-accounts.d.ts +1 -1
  24. package/dist/components/auth/multi-session/switch-account-submenu-item.d.ts +1 -1
  25. package/dist/components/auth/organization/delete-organization-dialog.d.ts +1 -1
  26. package/dist/components/auth/organization/leave-organization-dialog.d.ts +1 -1
  27. package/dist/components/auth/organization/organization-danger-zone.d.ts +2 -2
  28. package/dist/components/auth/organization/organization-invitation-row.d.ts +1 -1
  29. package/dist/components/auth/organization/organization-invitations.d.ts +1 -1
  30. package/dist/components/auth/organization/organization-logo.d.ts +3 -3
  31. package/dist/components/auth/organization/organization-member-row.d.ts +1 -1
  32. package/dist/components/auth/organization/organization-members.d.ts +1 -1
  33. package/dist/components/auth/organization/organization-people.d.ts +1 -1
  34. package/dist/components/auth/organization/organization-profile.d.ts +1 -1
  35. package/dist/components/auth/organization/organization-row.d.ts +1 -1
  36. package/dist/components/auth/organization/organization-settings.d.ts +2 -2
  37. package/dist/components/auth/organization/organization-switcher.d.ts +3 -3
  38. package/dist/components/auth/organization/organization-view-skeleton.d.ts +2 -2
  39. package/dist/components/auth/organization/organization-view.d.ts +3 -3
  40. package/dist/components/auth/organization/organization.d.ts +3 -3
  41. package/dist/components/auth/organization/organizations-settings.d.ts +2 -2
  42. package/dist/components/auth/organization/organizations.d.ts +1 -1
  43. package/dist/components/auth/organization/remove-member-dialog.d.ts +1 -1
  44. package/dist/components/auth/organization/slug-field.d.ts +1 -1
  45. package/dist/components/auth/organization/user-invitation-row.d.ts +1 -1
  46. package/dist/components/auth/organization/user-invitations.d.ts +1 -1
  47. package/dist/components/auth/passkey/passkey-button.d.ts +1 -1
  48. package/dist/components/auth/passkey/passkey.d.ts +1 -1
  49. package/dist/components/auth/passkey/passkeys.d.ts +1 -1
  50. package/dist/components/auth/provider-button.d.ts +2 -2
  51. package/dist/components/auth/reset-password.d.ts +1 -1
  52. package/dist/components/auth/settings/account/account-settings.d.ts +2 -2
  53. package/dist/components/auth/settings/account/change-email.d.ts +1 -1
  54. package/dist/components/auth/settings/account/user-profile.d.ts +1 -1
  55. package/dist/components/auth/settings/security/active-session.d.ts +1 -1
  56. package/dist/components/auth/settings/security/active-sessions.d.ts +1 -1
  57. package/dist/components/auth/settings/security/change-password.d.ts +1 -1
  58. package/dist/components/auth/settings/security/linked-account.d.ts +1 -1
  59. package/dist/components/auth/settings/security/linked-accounts.d.ts +1 -1
  60. package/dist/components/auth/settings/security/security-settings.d.ts +2 -2
  61. package/dist/components/auth/settings/settings.d.ts +3 -3
  62. package/dist/components/auth/sign-in.d.ts +2 -2
  63. package/dist/components/auth/sign-up.d.ts +2 -2
  64. package/dist/components/auth/theme/appearance.d.ts +1 -1
  65. package/dist/components/auth/user/user-avatar.d.ts +3 -3
  66. package/dist/components/auth/user/user-button.d.ts +2 -2
  67. package/dist/components/auth/user/user-view.d.ts +3 -3
  68. package/dist/components/auth/username/sign-in-username.d.ts +2 -2
  69. package/dist/components/auth/username/username-field.d.ts +1 -1
  70. package/dist/email.d.ts +8 -8
  71. package/dist/email.js +211 -8
  72. package/dist/index.d.ts +21 -21
  73. package/dist/index.js +3393 -21
  74. package/dist/lib/auth/api-key-plugin.d.ts +3 -3
  75. package/dist/lib/auth/auth-plugin.d.ts +5 -5
  76. package/dist/lib/auth/delete-user-plugin.d.ts +2 -2
  77. package/dist/lib/auth/magic-link-plugin.d.ts +3 -3
  78. package/dist/lib/auth/multi-session-plugin.d.ts +3 -3
  79. package/dist/lib/auth/organization-plugin.d.ts +2 -2
  80. package/dist/lib/auth/passkey-plugin.d.ts +3 -3
  81. package/dist/lib/auth/theme-plugin.d.ts +3 -3
  82. package/dist/lib/auth/username-plugin.d.ts +3 -3
  83. package/dist/plugins.d.ts +46 -46
  84. package/dist/plugins.js +2824 -47
  85. package/dist/user-view--47tVtJ3.js +113 -0
  86. package/package.json +3 -5
  87. package/dist/components/auth/additional-field.js +0 -137
  88. package/dist/components/auth/api-key/api-key-skeleton.js +0 -5
  89. package/dist/components/auth/api-key/api-key.js +0 -17
  90. package/dist/components/auth/api-key/api-keys-empty.js +0 -9
  91. package/dist/components/auth/api-key/api-keys.js +0 -22
  92. package/dist/components/auth/api-key/create-api-key-dialog.js +0 -44
  93. package/dist/components/auth/api-key/delete-api-key-dialog.js +0 -17
  94. package/dist/components/auth/api-key/new-api-key-dialog.js +0 -24
  95. package/dist/components/auth/api-key/organization-api-keys.js +0 -22
  96. package/dist/components/auth/auth-provider.js +0 -11
  97. package/dist/components/auth/auth.js +0 -88
  98. package/dist/components/auth/delete-user/danger-zone.js +0 -12
  99. package/dist/components/auth/delete-user/delete-account.js +0 -50
  100. package/dist/components/auth/email/email-changed-email.js +0 -23
  101. package/dist/components/auth/email/email-verification-email.js +0 -23
  102. package/dist/components/auth/email/magic-link-email.js +0 -23
  103. package/dist/components/auth/email/new-device-email.js +0 -23
  104. package/dist/components/auth/email/organization-invitation-email.js +0 -23
  105. package/dist/components/auth/email/otp-email.js +0 -22
  106. package/dist/components/auth/email/password-changed-email.js +0 -23
  107. package/dist/components/auth/email/reset-password-email.js +0 -23
  108. package/dist/components/auth/error-toaster.js +0 -33
  109. package/dist/components/auth/field-separator.js +0 -5
  110. package/dist/components/auth/forgot-password.js +0 -37
  111. package/dist/components/auth/magic-link/magic-link-button.js +0 -34
  112. package/dist/components/auth/magic-link/magic-link.js +0 -40
  113. package/dist/components/auth/multi-session/manage-account.js +0 -33
  114. package/dist/components/auth/multi-session/manage-accounts.js +0 -33
  115. package/dist/components/auth/multi-session/switch-account-submenu-content.js +0 -25
  116. package/dist/components/auth/multi-session/switch-account-submenu-item.js +0 -17
  117. package/dist/components/auth/multi-session/switch-account-submenu.js +0 -24
  118. package/dist/components/auth/organization/change-organization-logo.js +0 -69
  119. package/dist/components/auth/organization/create-organization-dialog.js +0 -37
  120. package/dist/components/auth/organization/delete-organization-dialog.js +0 -25
  121. package/dist/components/auth/organization/delete-organization-skeleton.js +0 -8
  122. package/dist/components/auth/organization/delete-organization.js +0 -27
  123. package/dist/components/auth/organization/invite-member-dialog.js +0 -47
  124. package/dist/components/auth/organization/leave-organization-dialog.js +0 -21
  125. package/dist/components/auth/organization/leave-organization.js +0 -16
  126. package/dist/components/auth/organization/organization-danger-zone.js +0 -23
  127. package/dist/components/auth/organization/organization-invitation-row-skeleton.js +0 -9
  128. package/dist/components/auth/organization/organization-invitation-row.js +0 -31
  129. package/dist/components/auth/organization/organization-invitations-empty.js +0 -13
  130. package/dist/components/auth/organization/organization-invitations.js +0 -66
  131. package/dist/components/auth/organization/organization-logo.js +0 -14
  132. package/dist/components/auth/organization/organization-member-row-skeleton.js +0 -9
  133. package/dist/components/auth/organization/organization-member-row.js +0 -34
  134. package/dist/components/auth/organization/organization-members.js +0 -67
  135. package/dist/components/auth/organization/organization-people.js +0 -11
  136. package/dist/components/auth/organization/organization-profile.js +0 -34
  137. package/dist/components/auth/organization/organization-row.js +0 -31
  138. package/dist/components/auth/organization/organization-settings.js +0 -13
  139. package/dist/components/auth/organization/organization-switcher.js +0 -48
  140. package/dist/components/auth/organization/organization-view-skeleton.js +0 -9
  141. package/dist/components/auth/organization/organization-view.js +0 -31
  142. package/dist/components/auth/organization/organization.js +0 -60
  143. package/dist/components/auth/organization/organizations-empty.js +0 -9
  144. package/dist/components/auth/organization/organizations-settings.js +0 -17
  145. package/dist/components/auth/organization/organizations.js +0 -21
  146. package/dist/components/auth/organization/remove-member-dialog.js +0 -20
  147. package/dist/components/auth/organization/slug-field.js +0 -38
  148. package/dist/components/auth/organization/user-invitation-row-skeleton.js +0 -8
  149. package/dist/components/auth/organization/user-invitation-row.js +0 -22
  150. package/dist/components/auth/organization/user-invitations-empty.js +0 -12
  151. package/dist/components/auth/organization/user-invitations.js +0 -18
  152. package/dist/components/auth/passkey/add-passkey-dialog.js +0 -22
  153. package/dist/components/auth/passkey/delete-passkey-dialog.js +0 -14
  154. package/dist/components/auth/passkey/passkey-button.js +0 -25
  155. package/dist/components/auth/passkey/passkey-skeleton.js +0 -5
  156. package/dist/components/auth/passkey/passkey.js +0 -17
  157. package/dist/components/auth/passkey/passkeys-empty.js +0 -9
  158. package/dist/components/auth/passkey/passkeys.js +0 -16
  159. package/dist/components/auth/provider-button.js +0 -29
  160. package/dist/components/auth/provider-buttons.js +0 -29
  161. package/dist/components/auth/reset-password.js +0 -57
  162. package/dist/components/auth/settings/account/account-settings.js +0 -22
  163. package/dist/components/auth/settings/account/change-avatar.js +0 -54
  164. package/dist/components/auth/settings/account/change-email.js +0 -28
  165. package/dist/components/auth/settings/account/user-profile.js +0 -65
  166. package/dist/components/auth/settings/security/active-session.js +0 -52
  167. package/dist/components/auth/settings/security/active-sessions.js +0 -23
  168. package/dist/components/auth/settings/security/change-password.js +0 -79
  169. package/dist/components/auth/settings/security/linked-account.js +0 -38
  170. package/dist/components/auth/settings/security/linked-accounts.js +0 -36
  171. package/dist/components/auth/settings/security/security-settings.js +0 -20
  172. package/dist/components/auth/settings/settings.js +0 -53
  173. package/dist/components/auth/sign-in.js +0 -64
  174. package/dist/components/auth/sign-out.js +0 -33
  175. package/dist/components/auth/sign-up.js +0 -98
  176. package/dist/components/auth/theme/appearance.js +0 -24
  177. package/dist/components/auth/theme/theme-toggle-item.js +0 -57
  178. package/dist/components/auth/user/user-avatar.js +0 -32
  179. package/dist/components/auth/user/user-button.js +0 -40
  180. package/dist/components/auth/user/user-view.js +0 -27
  181. package/dist/components/auth/username/sign-in-username.js +0 -88
  182. package/dist/components/auth/username/username-field.js +0 -45
  183. package/dist/lib/auth/api-key-plugin.js +0 -12
  184. package/dist/lib/auth/auth-plugin.js +0 -1
  185. package/dist/lib/auth/delete-user-plugin.js +0 -7
  186. package/dist/lib/auth/magic-link-plugin.js +0 -18
  187. package/dist/lib/auth/multi-session-plugin.js +0 -9
  188. package/dist/lib/auth/organization-plugin.js +0 -19
  189. package/dist/lib/auth/passkey-plugin.js +0 -9
  190. package/dist/lib/auth/theme-plugin.js +0 -26
  191. package/dist/lib/auth/username-plugin.js +0 -19
@@ -0,0 +1,113 @@
1
+ import { authMutationKeys as e, getProviderName as t } from "@better-auth-ui/core";
2
+ import { providerIcons as n, useAuth as r, useSession as i, useSignInSocial as a } from "@better-auth-ui/react";
3
+ import { Person as o } from "@gravity-ui/icons";
4
+ import { Avatar as s, Button as c, Separator as l, Skeleton as u, Spinner as d, cn as f } from "@heroui/react";
5
+ import { useMemo as p } from "react";
6
+ import { jsx as m, jsxs as h } from "react/jsx-runtime";
7
+ import { useIsMutating as g } from "@tanstack/react-query";
8
+ //#region src/components/auth/field-separator.tsx
9
+ function _({ children: e }) {
10
+ return /* @__PURE__ */ h("div", {
11
+ className: "flex items-center gap-4",
12
+ children: [
13
+ /* @__PURE__ */ m(l, { className: "flex-1" }),
14
+ /* @__PURE__ */ m("p", {
15
+ className: "text-xs text-muted shrink-0",
16
+ children: e
17
+ }),
18
+ /* @__PURE__ */ m(l, { className: "flex-1" })
19
+ ]
20
+ });
21
+ }
22
+ //#endregion
23
+ //#region src/components/auth/provider-button.tsx
24
+ function v({ provider: i, display: o = "full", variant: s = "tertiary", ...l }) {
25
+ let { authClient: u, baseURL: f, localization: p, redirectTo: _ } = r(), v = `${f}${_}`, { mutate: y, isPending: b } = a(u), x = n[i];
26
+ return /* @__PURE__ */ h(c, {
27
+ variant: s,
28
+ isPending: g({ mutationKey: e.signIn.all }) + g({ mutationKey: e.signUp.all }) > 0,
29
+ onPress: () => y({
30
+ provider: i,
31
+ callbackURL: v
32
+ }),
33
+ ...l,
34
+ "aria-label": t(i),
35
+ children: [b ? /* @__PURE__ */ m(d, {
36
+ color: "current",
37
+ size: "sm"
38
+ }) : /* @__PURE__ */ m(x, {}), o === "full" ? p.auth.continueWith.replace("{{provider}}", t(i)) : o === "name" ? t(i) : null]
39
+ });
40
+ }
41
+ //#endregion
42
+ //#region src/components/auth/provider-buttons.tsx
43
+ function y({ socialLayout: e = "auto" }) {
44
+ let { socialProviders: t } = r(), n = p(() => e === "auto" ? t?.length && t.length >= 4 ? "horizontal" : "vertical" : e, [e, t?.length]);
45
+ return /* @__PURE__ */ m("div", {
46
+ className: f("gap-3", n === "grid" && "grid grid-cols-2", n === "vertical" && "flex flex-col", n === "horizontal" && "flex flex-wrap"),
47
+ children: t?.map((e) => /* @__PURE__ */ m(v, {
48
+ provider: e,
49
+ display: n === "vertical" ? "full" : n === "grid" ? "name" : "icon",
50
+ className: f("w-full", n === "horizontal" && "flex-1")
51
+ }, e))
52
+ });
53
+ }
54
+ //#endregion
55
+ //#region src/components/auth/user/user-avatar.tsx
56
+ function b({ className: e, fallback: t, isPending: n, user: a, size: c = "sm", style: l, ...d }) {
57
+ let { authClient: p } = r(), { data: g, isPending: _ } = i(p, { enabled: !a && !n });
58
+ if ((n || _) && !a) return /* @__PURE__ */ m(u, {
59
+ className: f("rounded-full", c === "sm" ? "size-8" : c === "md" ? "size-10" : "size-12", e),
60
+ style: l
61
+ });
62
+ let v = a ?? g?.user, y = (v?.username || v?.name || v?.email)?.slice(0, 2).toUpperCase();
63
+ return /* @__PURE__ */ h(s, {
64
+ size: c,
65
+ className: f("rounded-full", e),
66
+ style: l,
67
+ ...d,
68
+ children: [/* @__PURE__ */ m(s.Image, {
69
+ alt: v?.displayUsername || v?.name || v?.email,
70
+ src: v?.image ?? void 0
71
+ }), /* @__PURE__ */ m(s.Fallback, {
72
+ className: f(c === "lg" ? "text-xl" : c === "md" ? "text-base" : "text-sm"),
73
+ delayMs: v?.image ? 600 : void 0,
74
+ children: t || y || /* @__PURE__ */ m(o, { className: "size-4" })
75
+ })]
76
+ });
77
+ }
78
+ //#endregion
79
+ //#region src/components/auth/user/user-view.tsx
80
+ function x({ className: e, isPending: t, size: n = "md", hideSubtitle: a = !1, user: o, ...s }) {
81
+ let { authClient: c } = r(), { data: l, isPending: d } = i(c, { enabled: !o && !t }), p = o ?? l?.user;
82
+ return (t || d) && !o ? /* @__PURE__ */ h("div", {
83
+ className: f("flex items-center gap-2 min-w-0", e),
84
+ ...s,
85
+ children: [/* @__PURE__ */ m(b, {
86
+ isPending: !0,
87
+ className: n === "sm" ? "size-5 [&>span]:text-xs" : void 0,
88
+ size: n === "lg" ? "md" : "sm"
89
+ }), /* @__PURE__ */ h("div", {
90
+ className: "flex flex-col gap-1 min-w-0",
91
+ children: [/* @__PURE__ */ m(u, { className: "h-3.5 w-24 rounded-lg" }), a ? null : /* @__PURE__ */ m(u, { className: "h-3 w-32 rounded-lg" })]
92
+ })]
93
+ }) : /* @__PURE__ */ h("div", {
94
+ className: f("flex items-center gap-2 min-w-0", e),
95
+ ...s,
96
+ children: [/* @__PURE__ */ m(b, {
97
+ className: n === "sm" ? "size-5 [&>span]:text-xs" : void 0,
98
+ user: p,
99
+ size: n === "lg" ? "md" : "sm"
100
+ }), /* @__PURE__ */ h("div", {
101
+ className: "flex flex-col min-w-0",
102
+ children: [/* @__PURE__ */ m("p", {
103
+ className: "text-foreground text-sm font-medium leading-tight truncate",
104
+ children: p?.displayUsername || p?.name || p?.email
105
+ }), !a && (p?.displayUsername || p?.name) ? /* @__PURE__ */ m("p", {
106
+ className: "text-muted text-xs leading-tight truncate overflow-x-hidden",
107
+ children: p?.email
108
+ }) : null]
109
+ })]
110
+ });
111
+ }
112
+ //#endregion
113
+ export { _ as a, v as i, b as n, y as r, x as t };
package/package.json CHANGED
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "name": "@better-auth-ui/heroui",
3
- "version": "1.6.9",
3
+ "version": "1.6.11",
4
4
  "type": "module",
5
5
  "scripts": {
6
- "build": "tsc && bun run styles",
7
- "styles": "mkdir -p dist && cp src/styles.css dist/styles.css",
6
+ "build": "vite build",
8
7
  "test": "vitest"
9
8
  },
10
9
  "files": [
@@ -62,8 +61,7 @@
62
61
  "@tanstack/react-query": ">=5.100.14",
63
62
  "better-auth": ">=1.6.11",
64
63
  "react": ">=19.2.6",
65
- "react-dom": ">=19.2.6",
66
- "bowser": ">=2.11.0"
64
+ "react-dom": ">=19.2.6"
67
65
  },
68
66
  "repository": {
69
67
  "type": "git",
@@ -1,137 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { resolveInputType } from "@better-auth-ui/core";
3
- import { useAuth } from "@better-auth-ui/react";
4
- import { Check, Copy } from "@gravity-ui/icons";
5
- import { Button, Calendar, Checkbox, ComboBox, DateField, DatePicker, FieldError, Input, InputGroup, Label, ListBox, NumberField, Select, Slider, Switch, TextArea, TextField, TimeField, toast } from "@heroui/react";
6
- import { fromDate, getLocalTimeZone, parseDate, parseDateTime, toCalendarDate, toCalendarDateTime } from "@internationalized/date";
7
- import { useRef, useState } from "react";
8
- /** Convert a `defaultValue` into a `CalendarDate` for HeroUI date inputs. */
9
- function toDateValue(value) {
10
- if (value instanceof Date) {
11
- return toCalendarDate(fromDate(value, getLocalTimeZone()));
12
- }
13
- if (typeof value === "string") {
14
- try {
15
- return parseDate(value.slice(0, 10));
16
- }
17
- catch {
18
- return undefined;
19
- }
20
- }
21
- return undefined;
22
- }
23
- /** Convert a `defaultValue` into a `CalendarDateTime` for datetime inputs. */
24
- function toDateTimeValue(value) {
25
- if (value instanceof Date) {
26
- return toCalendarDateTime(fromDate(value, getLocalTimeZone()));
27
- }
28
- if (typeof value === "string") {
29
- try {
30
- // Strip trailing `Z` or timezone offset for `parseDateTime`.
31
- return parseDateTime(value.replace(/(Z|[+-]\d{2}:?\d{2})$/, ""));
32
- }
33
- catch {
34
- return undefined;
35
- }
36
- }
37
- return undefined;
38
- }
39
- /**
40
- * Icon-only copy button used as an `InputGroup.Suffix`. `getValue` is invoked
41
- * lazily on click so the button copies the input's *live* value rather than a
42
- * stale snapshot — important when paired with editable inputs.
43
- */
44
- function CopyButton({ getValue, isDisabled }) {
45
- const { localization } = useAuth();
46
- const [copied, setCopied] = useState(false);
47
- async function handleCopy() {
48
- const value = getValue();
49
- if (!value)
50
- return;
51
- try {
52
- await navigator.clipboard.writeText(value);
53
- setCopied(true);
54
- setTimeout(() => setCopied(false), 1500);
55
- }
56
- catch (error) {
57
- toast.danger(error instanceof Error ? error.message : String(error));
58
- }
59
- }
60
- return (_jsx(Button, { isIconOnly: true, "aria-label": localization.settings.copyToClipboard, size: "sm", variant: "ghost", isDisabled: isDisabled, onPress: handleCopy, children: copied ? _jsx(Check, { className: "size-4" }) : _jsx(Copy, { className: "size-4" }) }));
61
- }
62
- /** Renders a single additional user field via HeroUI v3 components. */
63
- export function AdditionalField({ name, field, isPending, variant }) {
64
- const { localization } = useAuth();
65
- const inputType = resolveInputType(field);
66
- const inputVariant = variant === "transparent" ? "primary" : "secondary";
67
- // Used by `inputType: "input"` with `copyable: true` so the copy button
68
- // reads the input's *live* value rather than a stale `defaultValue`.
69
- const inputRef = useRef(null);
70
- if (field.render) {
71
- return _jsx(_Fragment, { children: field.render({ name, field, isPending, variant }) });
72
- }
73
- if (inputType === "hidden") {
74
- return (_jsx("input", { type: "hidden", name: name, value: field.defaultValue == null
75
- ? ""
76
- : field.defaultValue instanceof Date
77
- ? field.defaultValue.toISOString()
78
- : String(field.defaultValue) }));
79
- }
80
- if (inputType === "textarea") {
81
- return (_jsxs(TextField, { name: name, defaultValue: field.defaultValue == null ? undefined : String(field.defaultValue), isDisabled: isPending, isReadOnly: field.readOnly, children: [_jsx(Label, { children: field.label }), _jsx(TextArea, { placeholder: field.placeholder, required: field.required, variant: inputVariant }), _jsx(FieldError, {})] }));
82
- }
83
- if (inputType === "number") {
84
- const maxFractionDigits = field.formatOptions?.maximumFractionDigits;
85
- return (_jsxs(NumberField, { name: name, defaultValue: typeof field.defaultValue === "number"
86
- ? field.defaultValue
87
- : field.defaultValue != null && field.defaultValue !== ""
88
- ? Number(field.defaultValue)
89
- : undefined, minValue: field.min, maxValue: field.max, step: field.step ?? (maxFractionDigits ? 1 / 10 ** maxFractionDigits : 1), formatOptions: field.formatOptions, isDisabled: isPending, isReadOnly: field.readOnly, variant: inputVariant, children: [_jsx(Label, { children: field.label }), _jsxs(NumberField.Group, { children: [_jsx(NumberField.DecrementButton, {}), _jsx(NumberField.Input, { placeholder: field.placeholder, required: field.required }), _jsx(NumberField.IncrementButton, {})] }), _jsx(FieldError, {})] }));
90
- }
91
- if (inputType === "slider") {
92
- const maxFractionDigits = field.formatOptions?.maximumFractionDigits;
93
- return (_jsxs(Slider, { defaultValue: typeof field.defaultValue === "number"
94
- ? field.defaultValue
95
- : field.defaultValue != null
96
- ? Number(field.defaultValue)
97
- : undefined, minValue: field.min ?? 0, maxValue: field.max ?? 100, step: field.step ?? (maxFractionDigits ? 1 / 10 ** maxFractionDigits : 1), formatOptions: field.formatOptions, isDisabled: isPending || field.readOnly, className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx(Label, { children: field.label }), _jsx(Slider.Output, { className: "text-sm text-muted" })] }), _jsxs(Slider.Track, { children: [_jsx(Slider.Fill, {}), _jsx(Slider.Thumb, { name: name })] })] }));
98
- }
99
- if (inputType === "switch") {
100
- return (_jsxs(Switch, { name: name, defaultSelected: field.defaultValue === true || field.defaultValue === "true", isDisabled: isPending, isReadOnly: field.readOnly, children: [_jsx(Switch.Control, { children: _jsx(Switch.Thumb, {}) }), _jsx(Label, { children: field.label })] }));
101
- }
102
- if (inputType === "checkbox") {
103
- return (_jsxs(Checkbox, { name: name, defaultSelected: field.defaultValue === true || field.defaultValue === "true", isDisabled: isPending, isReadOnly: field.readOnly, isRequired: field.required, variant: inputVariant, children: [_jsx(Checkbox.Control, { children: _jsx(Checkbox.Indicator, {}) }), _jsx(Checkbox.Content, { children: _jsx(Label, { children: field.label }) })] }));
104
- }
105
- if (inputType === "select") {
106
- return (_jsxs(Select, { className: "[&[data-required=true]>.label]:after:content-none", name: name, defaultValue: field.defaultValue != null ? String(field.defaultValue) : undefined, placeholder: field.placeholder, isDisabled: isPending || field.readOnly, isRequired: field.required, variant: inputVariant, fullWidth: true, children: [_jsx(Label, { children: field.label }), _jsxs(Select.Trigger, { children: [_jsx(Select.Value, {}), _jsx(Select.Indicator, {})] }), _jsx(Select.Popover, { children: _jsx(ListBox, { children: field.options?.map((option) => (_jsxs(ListBox.Item, { id: option.value, textValue: typeof option.label === "string" ? option.label : option.value, children: [option.label, _jsx(ListBox.ItemIndicator, {})] }, option.value))) }) }), _jsx(FieldError, {})] }));
107
- }
108
- if (inputType === "combobox") {
109
- return (_jsxs(ComboBox, { className: "[&[data-required=true]>.label]:after:content-none", name: name, defaultSelectedKey: field.defaultValue != null ? String(field.defaultValue) : undefined, isDisabled: isPending, isReadOnly: field.readOnly, isRequired: field.required, variant: inputVariant, fullWidth: true, children: [_jsx(Label, { children: field.label }), _jsxs(ComboBox.InputGroup, { children: [_jsx(Input, { placeholder: field.placeholder }), _jsx(ComboBox.Trigger, {})] }), _jsx(ComboBox.Popover, { children: _jsx(ListBox, { children: field.options?.map((option) => (_jsxs(ListBox.Item, { id: option.value, textValue: typeof option.label === "string" ? option.label : option.value, children: [option.label, _jsx(ListBox.ItemIndicator, {})] }, option.value))) }) }), _jsx(FieldError, {})] }));
110
- }
111
- if (inputType === "date" || inputType === "datetime") {
112
- const isDateTime = inputType === "datetime";
113
- const defaultValue = isDateTime
114
- ? toDateTimeValue(field.defaultValue)
115
- : toDateValue(field.defaultValue);
116
- return (_jsx(DatePicker, { className: "w-full [&[data-required=true]>.label]:after:content-none", name: name, defaultValue: defaultValue, granularity: isDateTime ? "minute" : "day", isDisabled: isPending, isReadOnly: field.readOnly, isRequired: field.required, children: ({ state }) => (_jsxs(_Fragment, { children: [_jsx(Label, { children: field.label }), _jsxs(DateField.Group, { variant: inputVariant, fullWidth: true, children: [_jsx(DateField.Input, { children: (segment) => _jsx(DateField.Segment, { segment: segment }) }), _jsx(DateField.Suffix, { children: _jsx(DatePicker.Trigger, { children: _jsx(DatePicker.TriggerIndicator, {}) }) })] }), _jsx(FieldError, {}), _jsxs(DatePicker.Popover, { className: "flex flex-col gap-3", children: [_jsxs(Calendar, { "aria-label": typeof field.label === "string" ? field.label : name, children: [_jsxs(Calendar.Header, { children: [_jsxs(Calendar.YearPickerTrigger, { children: [_jsx(Calendar.YearPickerTriggerHeading, {}), _jsx(Calendar.YearPickerTriggerIndicator, {})] }), _jsx(Calendar.NavButton, { slot: "previous" }), _jsx(Calendar.NavButton, { slot: "next" })] }), _jsxs(Calendar.Grid, { children: [_jsx(Calendar.GridHeader, { children: (day) => _jsx(Calendar.HeaderCell, { children: day }) }), _jsx(Calendar.GridBody, { children: (date) => _jsx(Calendar.Cell, { date: date }) })] }), _jsx(Calendar.YearPickerGrid, { children: _jsx(Calendar.YearPickerGridBody, { children: ({ year }) => _jsx(Calendar.YearPickerCell, { year: year }) }) })] }), isDateTime && (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { children: localization.settings.time }), _jsx(TimeField, { "aria-label": localization.settings.time, granularity: "minute", value: state.timeValue, onChange: (v) => state.setTimeValue(v), children: _jsx(TimeField.Group, { variant: "secondary", children: _jsx(TimeField.Input, { children: (segment) => _jsx(TimeField.Segment, { segment: segment }) }) }) })] }))] })] })) }));
117
- }
118
- // inputType === "input"
119
- const hasPrefix = field.prefix != null;
120
- const hasSuffix = field.suffix != null || field.copyable;
121
- // When `inputType: "input"` is paired with `type: "number"`, restrict the
122
- // native input to numbers. `formatOptions.maximumFractionDigits` enables
123
- // fractional input via `step`.
124
- const isNumeric = field.type === "number";
125
- const maxFractionDigits = field.formatOptions?.maximumFractionDigits;
126
- const nativeInputType = isNumeric ? "number" : undefined;
127
- const nativeInputMode = isNumeric
128
- ? maxFractionDigits
129
- ? "decimal"
130
- : "numeric"
131
- : undefined;
132
- const nativeStep = maxFractionDigits ? 1 / 10 ** maxFractionDigits : undefined;
133
- if (hasPrefix || hasSuffix) {
134
- return (_jsxs(TextField, { name: name, defaultValue: field.defaultValue == null ? undefined : String(field.defaultValue), isDisabled: isPending, isReadOnly: field.readOnly, children: [_jsx(Label, { children: field.label }), _jsxs(InputGroup, { variant: inputVariant, children: [hasPrefix && _jsx(InputGroup.Prefix, { children: field.prefix }), _jsx(InputGroup.Input, { ref: inputRef, placeholder: field.placeholder, required: field.required, type: nativeInputType, inputMode: nativeInputMode, step: nativeStep }), field.copyable ? (_jsx(InputGroup.Suffix, { className: "px-0", children: _jsx(CopyButton, { getValue: () => inputRef.current?.value, isDisabled: isPending }) })) : (field.suffix != null && (_jsx(InputGroup.Suffix, { children: field.suffix })))] }), _jsx(FieldError, {})] }));
135
- }
136
- return (_jsxs(TextField, { name: name, defaultValue: field.defaultValue == null ? undefined : String(field.defaultValue), isDisabled: isPending, isReadOnly: field.readOnly, children: [_jsx(Label, { children: field.label }), _jsx(Input, { placeholder: field.placeholder, required: field.required, variant: inputVariant, type: nativeInputType, inputMode: nativeInputMode, step: nativeStep }), _jsx(FieldError, {})] }));
137
- }
@@ -1,5 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Skeleton } from "@heroui/react";
3
- export function ApiKeySkeleton() {
4
- 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-28 rounded-lg" }), _jsx(Skeleton, { className: "h-3 w-36 rounded-lg" }), _jsx(Skeleton, { className: "h-3 w-32 rounded-lg" })] })] }) }));
5
- }
@@ -1,17 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useAuth, useAuthPlugin } from "@better-auth-ui/react";
3
- import { Key, Xmark } from "@gravity-ui/icons";
4
- import { Button } from "@heroui/react";
5
- import { useState } from "react";
6
- import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin";
7
- import { DeleteApiKeyDialog } from "./delete-api-key-dialog";
8
- export function ApiKey({ apiKey, hideDelete, organizationId }) {
9
- const { localization } = useAuth();
10
- const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin);
11
- const [deleteOpen, setDeleteOpen] = useState(false);
12
- const preview = `${apiKey.start}${"*".repeat(16)}`;
13
- 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(Key, { className: "size-4.5" }) }), _jsxs("div", { className: "flex flex-col min-w-0", children: [_jsx("span", { className: "text-sm font-medium leading-tight truncate", children: apiKey.name || apiKeyLocalization.apiKey }), _jsx("span", { className: "text-xs text-muted font-mono truncate", children: preview }), _jsx("span", { className: "text-xs text-muted", children: new Date(apiKey.createdAt).toLocaleString(undefined, {
14
- dateStyle: "medium",
15
- timeStyle: "short"
16
- }) })] }), !hideDelete && (_jsxs(_Fragment, { children: [_jsxs(Button, { className: "ml-auto shrink-0", variant: "outline", size: "sm", onPress: () => setDeleteOpen(true), "aria-label": apiKeyLocalization.deleteApiKey, children: [_jsx(Xmark, {}), localization.settings.delete] }), _jsx(DeleteApiKeyDialog, { isOpen: deleteOpen, onOpenChange: setDeleteOpen, apiKey: apiKey, organizationId: organizationId })] }))] }));
17
- }
@@ -1,9 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useAuthPlugin } from "@better-auth-ui/react";
3
- import { Key } from "@gravity-ui/icons";
4
- import { Button } from "@heroui/react";
5
- import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin";
6
- export function ApiKeysEmpty({ onCreatePress, hideCreate }) {
7
- const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin);
8
- return (_jsxs("div", { className: "flex flex-col items-center justify-center gap-4", children: [_jsx("div", { className: "flex size-10 items-center justify-center rounded-xl bg-surface-secondary", children: _jsx(Key, { className: "size-4.5" }) }), _jsxs("div", { className: "flex flex-col items-center justify-center gap-1 text-center", children: [_jsx("p", { className: "text-sm font-semibold", children: apiKeyLocalization.noApiKeys }), _jsx("p", { className: "text-muted text-xs", children: apiKeyLocalization.apiKeysDescription })] }), !hideCreate && (_jsx(Button, { size: "sm", onPress: onCreatePress, children: apiKeyLocalization.createApiKey }))] }));
9
- }
@@ -1,22 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useAuth, useAuthPlugin, useListApiKeys } from "@better-auth-ui/react";
3
- import { Button, Card, cn } from "@heroui/react";
4
- import { useState } from "react";
5
- import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin";
6
- import { ApiKey } from "./api-key";
7
- import { ApiKeySkeleton } from "./api-key-skeleton";
8
- import { ApiKeysEmpty } from "./api-keys-empty";
9
- import { CreateApiKeyDialog } from "./create-api-key-dialog";
10
- export function ApiKeys({ className, variant, organizationId, isPending: isPendingProp, hideCreate, hideDelete }) {
11
- const { authClient } = useAuth();
12
- const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin);
13
- const { data: listData, isPending: isListPending } = useListApiKeys(authClient, {
14
- enabled: !isPendingProp,
15
- ...(organizationId
16
- ? { query: { organizationId, configId: "organization" } }
17
- : {})
18
- });
19
- const isPending = isPendingProp || isListPending;
20
- const [createOpen, setCreateOpen] = useState(false);
21
- return (_jsxs("div", { className: cn("flex flex-col gap-3", className), children: [_jsxs("div", { className: "flex items-end justify-between gap-3", children: [_jsx("h2", { className: "text-sm font-semibold truncate", children: apiKeyLocalization.apiKeys }), !hideCreate && (_jsx(Button, { className: "shrink-0", size: "sm", isDisabled: isPending, onPress: () => setCreateOpen(true), children: apiKeyLocalization.createApiKey }))] }), _jsx(Card, { variant: variant, children: _jsx(Card.Content, { children: isPending ? (_jsx(ApiKeySkeleton, {})) : !listData?.apiKeys.length ? (_jsx(ApiKeysEmpty, { onCreatePress: () => setCreateOpen(true), hideCreate: hideCreate })) : (listData?.apiKeys.map((key, index) => (_jsxs("div", { children: [index > 0 && (_jsx("div", { className: "border-b border-dashed -mx-4 my-4" })), _jsx(ApiKey, { apiKey: key, hideDelete: hideDelete, organizationId: organizationId })] }, key.id)))) }) }), !hideCreate && (_jsx(CreateApiKeyDialog, { isOpen: createOpen, onOpenChange: setCreateOpen, organizationId: organizationId }))] }));
22
- }
@@ -1,44 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useAuth, useAuthPlugin, useCreateApiKey } from "@better-auth-ui/react";
3
- import { Key } from "@gravity-ui/icons";
4
- import { AlertDialog, Button, FieldError, Form, Input, Label, Spinner, TextField } from "@heroui/react";
5
- import { useState } from "react";
6
- import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin";
7
- import { NewApiKeyDialog } from "./new-api-key-dialog";
8
- export function CreateApiKeyDialog({ isOpen, onOpenChange, organizationId }) {
9
- const { authClient, localization } = useAuth();
10
- const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin);
11
- const { mutate: createApiKey, isPending: isCreating } = useCreateApiKey(authClient);
12
- const [isNewKeyDialogOpen, setIsNewKeyDialogOpen] = useState(false);
13
- const [keyName, setKeyName] = useState(null);
14
- const [secretKey, setSecretKey] = useState(null);
15
- const handleOpenChange = (open) => {
16
- if (!open) {
17
- setKeyName(null);
18
- setSecretKey(null);
19
- }
20
- onOpenChange(open);
21
- };
22
- const handleSubmit = (e) => {
23
- e.preventDefault();
24
- const formData = new FormData(e.target);
25
- const name = formData.get("name")?.trim();
26
- const payload = name || organizationId
27
- ? {
28
- ...(name ? { name } : {}),
29
- ...(organizationId
30
- ? { organizationId, configId: "organization" }
31
- : {})
32
- }
33
- : undefined;
34
- createApiKey(payload, {
35
- onSuccess: (result) => {
36
- handleOpenChange(false);
37
- setKeyName(name);
38
- setSecretKey(result.key);
39
- setIsNewKeyDialogOpen(true);
40
- }
41
- });
42
- };
43
- return (_jsxs(_Fragment, { children: [_jsx(AlertDialog.Backdrop, { isOpen: isOpen, onOpenChange: handleOpenChange, children: _jsx(AlertDialog.Container, { children: _jsx(AlertDialog.Dialog, { children: _jsxs(Form, { onSubmit: handleSubmit, children: [_jsx(AlertDialog.CloseTrigger, {}), _jsxs(AlertDialog.Header, { children: [_jsx(AlertDialog.Icon, { status: "default", children: _jsx(Key, {}) }), _jsx(AlertDialog.Heading, { children: apiKeyLocalization.createApiKey })] }), _jsxs(AlertDialog.Body, { className: "overflow-visible", children: [_jsx("p", { className: "text-muted text-sm", children: apiKeyLocalization.apiKeysDescription }), _jsxs(TextField, { className: "mt-4", id: "name", name: "name", isDisabled: isCreating, children: [_jsx(Label, { children: apiKeyLocalization.name }), _jsx(Input, { autoFocus: true, placeholder: localization.settings.optional, variant: "secondary" }), _jsx(FieldError, {})] })] }), _jsxs(AlertDialog.Footer, { children: [_jsx(Button, { slot: "close", variant: "tertiary", isDisabled: isCreating, children: localization.settings.cancel }), _jsxs(Button, { type: "submit", isPending: isCreating, children: [isCreating && _jsx(Spinner, { color: "current", size: "sm" }), apiKeyLocalization.createApiKey] })] })] }) }) }) }), _jsx(NewApiKeyDialog, { isOpen: isNewKeyDialogOpen, onOpenChange: setIsNewKeyDialogOpen, secretKey: secretKey, name: keyName })] }));
44
- }
@@ -1,17 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useAuth, useAuthPlugin, useDeleteApiKey } from "@better-auth-ui/react";
3
- import { Key } from "@gravity-ui/icons";
4
- import { AlertDialog, Button, Input, Label, Spinner, TextField } from "@heroui/react";
5
- import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin";
6
- export function DeleteApiKeyDialog({ isOpen, onOpenChange, apiKey, organizationId }) {
7
- const { authClient, localization } = useAuth();
8
- const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin);
9
- const preview = `${apiKey.start}${"*".repeat(16)}`;
10
- const { mutate: deleteApiKey, isPending: isDeleting } = useDeleteApiKey(authClient, {
11
- onSuccess: () => onOpenChange(false)
12
- });
13
- return (_jsx(AlertDialog.Backdrop, { isOpen: isOpen, onOpenChange: onOpenChange, children: _jsx(AlertDialog.Container, { children: _jsxs(AlertDialog.Dialog, { children: [_jsx(AlertDialog.CloseTrigger, {}), _jsxs(AlertDialog.Header, { children: [_jsx(AlertDialog.Icon, { status: "danger", children: _jsx(Key, {}) }), _jsx(AlertDialog.Heading, { children: apiKeyLocalization.deleteApiKey })] }), _jsxs(AlertDialog.Body, { className: "flex flex-col gap-4 overflow-visible", children: [_jsx("p", { className: "text-muted text-sm", children: apiKeyLocalization.deleteApiKeyWarning }), _jsxs(TextField, { value: preview, className: "font-mono text-xs", variant: "secondary", children: [_jsx(Label, { children: apiKey.name || apiKeyLocalization.apiKey }), _jsx(Input, { readOnly: true, className: "font-mono text-xs" })] })] }), _jsxs(AlertDialog.Footer, { children: [_jsx(Button, { slot: "close", variant: "tertiary", isDisabled: isDeleting, children: localization.settings.cancel }), _jsxs(Button, { variant: "danger", onPress: () => deleteApiKey({
14
- keyId: apiKey.id,
15
- ...(organizationId ? { configId: "organization" } : {})
16
- }), isPending: isDeleting, children: [isDeleting && _jsx(Spinner, { color: "current", size: "sm" }), apiKeyLocalization.deleteApiKey] })] })] }) }) }));
17
- }
@@ -1,24 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useAuth, useAuthPlugin } from "@better-auth-ui/react";
3
- import { Check, Copy, Key } from "@gravity-ui/icons";
4
- import { AlertDialog, Button, InputGroup, Label, TextField, toast } from "@heroui/react";
5
- import { useState } from "react";
6
- import { apiKeyPlugin } from "../../../lib/auth/api-key-plugin";
7
- export function NewApiKeyDialog({ isOpen, onOpenChange, name, secretKey }) {
8
- const { localization } = useAuth();
9
- const { localization: apiKeyLocalization } = useAuthPlugin(apiKeyPlugin);
10
- const [copied, setCopied] = useState(false);
11
- const copySecretKey = async () => {
12
- if (!secretKey)
13
- return;
14
- try {
15
- await navigator.clipboard.writeText(secretKey);
16
- setCopied(true);
17
- setTimeout(() => setCopied(false), 1500);
18
- }
19
- catch (error) {
20
- toast.danger(error instanceof Error ? error.message : String(error));
21
- }
22
- };
23
- return (_jsx(AlertDialog.Backdrop, { isOpen: isOpen, onOpenChange: onOpenChange, children: _jsx(AlertDialog.Container, { children: _jsxs(AlertDialog.Dialog, { children: [_jsx(AlertDialog.CloseTrigger, {}), _jsxs(AlertDialog.Header, { children: [_jsx(AlertDialog.Icon, { status: "warning", children: _jsx(Key, {}) }), _jsx(AlertDialog.Heading, { children: apiKeyLocalization.newApiKey })] }), _jsxs(AlertDialog.Body, { className: "flex flex-col gap-4 overflow-visible", children: [_jsx("p", { className: "text-muted text-sm", children: apiKeyLocalization.newApiKeyWarning }), _jsxs(TextField, { value: secretKey ?? "", className: "font-mono text-xs", children: [_jsx(Label, { children: name || apiKeyLocalization.apiKey }), _jsxs(InputGroup, { variant: "secondary", children: [_jsx(InputGroup.Input, { readOnly: true, className: "font-mono text-xs" }), _jsx(InputGroup.Suffix, { className: "px-0", children: _jsx(Button, { isIconOnly: true, "aria-label": localization.settings.copyToClipboard, size: "sm", variant: "ghost", onPress: copySecretKey, children: copied ? _jsx(Check, {}) : _jsx(Copy, {}) }) })] })] })] }), _jsx(AlertDialog.Footer, { children: _jsx(Button, { slot: "close", children: apiKeyLocalization.dismissNewKey }) })] }) }) }));
24
- }
@@ -1,22 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useActiveOrganization, useAuth, useListOrganizationMembers, useSession } from "@better-auth-ui/react";
3
- import { ApiKeys } from "./api-keys";
4
- /**
5
- * {@link ApiKeys} scoped to the active organization.
6
- *
7
- * Hidden for members whose role isn't `owner`. Better Auth's
8
- * `/organization/has-permission` endpoint isn't usable for `apiKey:*` checks
9
- * (it doesn't pass `allowCreatorAllPermissions` and the default org AC has no
10
- * `apiKey` statements), so we gate on role directly.
11
- */
12
- export function OrganizationApiKeys({ className, variant }) {
13
- const { authClient } = useAuth();
14
- const { data: session } = useSession(authClient);
15
- const { data: activeOrganization, isPending: activeOrganizationPending } = useActiveOrganization(authClient);
16
- const { data: membersData } = useListOrganizationMembers(authClient);
17
- const canManageApiKeys = membersData?.members.some((member) => member.role === "owner" && member.userId === session?.user.id);
18
- if (!canManageApiKeys) {
19
- return null;
20
- }
21
- return (_jsx(ApiKeys, { className: className, variant: variant, organizationId: activeOrganization?.id, isPending: activeOrganizationPending }));
22
- }
@@ -1,11 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { AuthProvider as AuthProviderPrimitive } from "@better-auth-ui/react";
3
- import { RouterProvider } from "@heroui/react";
4
- import { ErrorToaster } from "./error-toaster";
5
- /**
6
- * Heroui-flavored `AuthProvider`. Wraps the primitive provider with a
7
- * heroui `RouterProvider` and the heroui `ErrorToaster`.
8
- */
9
- export function AuthProvider({ children, navigate, ...config }) {
10
- return (_jsx(AuthProviderPrimitive, { navigate: navigate, ...config, children: _jsxs(RouterProvider, { navigate: (path) => navigate({ to: path }), children: [children, _jsx(ErrorToaster, {})] }) }));
11
- }
@@ -1,88 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useAuth } from "@better-auth-ui/react";
3
- import { useEffect } from "react";
4
- import { ForgotPassword } from "./forgot-password";
5
- import { ResetPassword } from "./reset-password";
6
- import { SignIn } from "./sign-in";
7
- import { SignOut } from "./sign-out";
8
- import { SignUp } from "./sign-up";
9
- /**
10
- * Built-in views that only make sense when email + password auth is enabled.
11
- * When it's disabled, the `<Auth>` router redirects these to `signIn` so a
12
- * plugin's `fallbackViews.auth.signIn` (e.g. magic link) takes over.
13
- */
14
- const PASSWORD_ONLY_VIEWS = ["signUp", "forgotPassword", "resetPassword"];
15
- const AUTH_VIEWS = {
16
- signIn: SignIn,
17
- signOut: SignOut,
18
- signUp: SignUp,
19
- forgotPassword: ForgotPassword,
20
- resetPassword: ResetPassword
21
- };
22
- /**
23
- * Render the appropriate authentication view based on the provided `view` or `path`.
24
- *
25
- * @param path - Route path used to resolve an auth view when `view` is not provided
26
- * @param socialLayout - Social layout to apply to sign-in/sign-up/magic-link views
27
- * @param socialPosition - Position for social buttons ("top" or "bottom")
28
- * @param variant - Variant to apply to the card
29
- * @param view - Explicit auth view to render (e.g., "signIn", "signUp")
30
- * @returns The React element for the resolved authentication view
31
- */
32
- export function Auth({ path, socialLayout, socialPosition, view, ...props }) {
33
- const { basePaths, emailAndPassword, plugins, viewPaths, navigate } = useAuth();
34
- if (!view && !path) {
35
- throw new Error("[Better Auth UI] Either `view` or `path` must be provided");
36
- }
37
- const authView = view ||
38
- Object.keys(viewPaths.auth).find((key) => viewPaths.auth[key] === path);
39
- // When email + password auth is disabled, password-only views (signUp,
40
- // forgotPassword, resetPassword) have no meaning. Redirect them to signIn,
41
- // where a plugin's `fallbackViews.auth.signIn` (e.g. magic link) takes
42
- // over as the primary entry point.
43
- const shouldRedirectToSignIn = !emailAndPassword?.enabled &&
44
- authView &&
45
- PASSWORD_ONLY_VIEWS.includes(authView);
46
- useEffect(() => {
47
- if (shouldRedirectToSignIn) {
48
- navigate({
49
- to: `${basePaths.auth}/${viewPaths.auth.signIn}`,
50
- replace: true
51
- });
52
- }
53
- }, [shouldRedirectToSignIn, navigate, basePaths.auth, viewPaths.auth.signIn]);
54
- if (shouldRedirectToSignIn) {
55
- return null;
56
- }
57
- // 1. Plugin overrides (`views.auth[currentView]`) — first plugin wins,
58
- // including over built-in views. Resolves the view key from `view`,
59
- // then `authView` (built-in path match), then plugin-introduced paths
60
- // (e.g. `magicLink` → `/auth/magic-link`).
61
- for (const plugin of plugins) {
62
- const pluginAuthPaths = plugin.viewPaths?.auth;
63
- const pluginView = view ??
64
- authView ??
65
- (pluginAuthPaths &&
66
- Object.keys(pluginAuthPaths).find((key) => pluginAuthPaths[key] === path));
67
- if (!pluginView)
68
- continue;
69
- const PluginView = plugin.views?.auth?.[pluginView];
70
- if (!PluginView)
71
- continue;
72
- return (_jsx(PluginView, { socialLayout: socialLayout, socialPosition: socialPosition, ...props }));
73
- }
74
- // 2. Plugin fallbacks — only when the built-in `signIn` isn't viable
75
- // (password auth is off). Used by `magicLinkPlugin` to render the
76
- // magic-link form as the primary passwordless sign-in surface.
77
- if (authView === "signIn" && !emailAndPassword?.enabled) {
78
- const Fallback = plugins.find((plugin) => plugin.fallbackViews?.auth?.signIn)?.fallbackViews?.auth?.signIn;
79
- if (Fallback) {
80
- return (_jsx(Fallback, { socialLayout: socialLayout, socialPosition: socialPosition, ...props }));
81
- }
82
- }
83
- const AuthView = authView ? AUTH_VIEWS[authView] : undefined;
84
- if (!AuthView) {
85
- throw new Error(`[Better Auth UI] Unknown view "${authView}". Valid views are: ${Object.keys(AUTH_VIEWS).join(", ")}`);
86
- }
87
- return (_jsx(AuthView, { socialLayout: socialLayout, socialPosition: socialPosition, ...props }));
88
- }
@@ -1,12 +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 "@heroui/react";
4
- import { DeleteAccount } from "./delete-account";
5
- /**
6
- * Renders the danger zone heading and {@link DeleteAccount}.
7
- * Registered as a `securityCard` by `deleteUserPlugin()`; gate by registering the plugin.
8
- */
9
- export function DangerZone({ className, variant, ...props }) {
10
- const { localization } = useAuth();
11
- return (_jsxs("div", { className: cn("flex w-full flex-col", className), ...props, children: [_jsx("h2", { className: cn("text-sm font-semibold mb-3 text-danger"), children: localization.settings.dangerZone }), _jsx(DeleteAccount, { variant: variant })] }));
12
- }
@@ -1,50 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { authQueryKeys } from "@better-auth-ui/core";
3
- import { useAuth, useAuthPlugin, useDeleteUser, useListAccounts } from "@better-auth-ui/react";
4
- import { TriangleExclamation } from "@gravity-ui/icons";
5
- import { AlertDialog, Button, Card, FieldError, Form, Input, Label, Spinner, TextField, toast } from "@heroui/react";
6
- import { useQueryClient } from "@tanstack/react-query";
7
- import { useState } from "react";
8
- import { deleteUserPlugin } from "../../../lib/auth/delete-user-plugin";
9
- /**
10
- * Danger-zone card to delete the authenticated account, with a confirmation dialog and toasts.
11
- */
12
- export function DeleteAccount({ className, variant, ...props }) {
13
- const { authClient, basePaths, localization, navigate, viewPaths } = useAuth();
14
- const { localization: deleteUserLocalization, sendDeleteAccountVerification } = useAuthPlugin(deleteUserPlugin);
15
- const { data: accounts } = useListAccounts(authClient);
16
- const queryClient = useQueryClient();
17
- const [confirmOpen, setConfirmOpen] = useState(false);
18
- const [password, setPassword] = useState("");
19
- const hasCredentialAccount = accounts?.some((account) => account.providerId === "credential");
20
- const needsPassword = !sendDeleteAccountVerification && hasCredentialAccount;
21
- const { mutate: deleteUser, isPending } = useDeleteUser(authClient);
22
- const handleDialogOpenChange = (open) => {
23
- setConfirmOpen(open);
24
- setPassword("");
25
- };
26
- const handleSubmit = async (e) => {
27
- e.preventDefault();
28
- const params = {
29
- ...(needsPassword ? { password } : {})
30
- };
31
- deleteUser(params, {
32
- onSuccess: () => {
33
- setConfirmOpen(false);
34
- setPassword("");
35
- if (sendDeleteAccountVerification) {
36
- toast.success(deleteUserLocalization.deleteUserVerificationSent);
37
- }
38
- else {
39
- toast.success(deleteUserLocalization.deleteUserSuccess);
40
- queryClient.removeQueries({ queryKey: authQueryKeys.all });
41
- navigate({
42
- to: `${basePaths.auth}/${viewPaths.auth.signIn}`,
43
- replace: true
44
- });
45
- }
46
- }
47
- });
48
- };
49
- return (_jsx(Card, { className: className, variant: variant, ...props, children: _jsxs(Card.Content, { 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: deleteUserLocalization.deleteAccount }), _jsx("p", { className: "text-muted text-xs mt-0.5", children: deleteUserLocalization.deleteAccountDescription })] }), _jsxs(AlertDialog, { children: [_jsx(Button, { isDisabled: !accounts, size: "sm", variant: "danger-soft", onPress: () => setConfirmOpen(true), children: deleteUserLocalization.deleteAccount }), _jsx(AlertDialog.Backdrop, { isOpen: confirmOpen, onOpenChange: handleDialogOpenChange, children: _jsx(AlertDialog.Container, { children: _jsx(AlertDialog.Dialog, { children: _jsxs(Form, { onSubmit: handleSubmit, children: [_jsx(AlertDialog.CloseTrigger, {}), _jsxs(AlertDialog.Header, { children: [_jsx(AlertDialog.Icon, { status: "danger", children: _jsx(TriangleExclamation, {}) }), _jsx(AlertDialog.Heading, { children: deleteUserLocalization.deleteAccount })] }), _jsxs(AlertDialog.Body, { className: "overflow-visible", children: [_jsx("p", { className: "text-muted text-sm", children: deleteUserLocalization.deleteAccountDescription }), needsPassword && (_jsxs(TextField, { className: "mt-4", name: "password", type: "password", isDisabled: isPending, value: password, onChange: setPassword, children: [_jsx(Label, { children: localization.auth.password }), _jsx(Input, { autoComplete: "current-password", placeholder: localization.auth.passwordPlaceholder, required: true, variant: "secondary" }), _jsx(FieldError, {})] }))] }), _jsxs(AlertDialog.Footer, { children: [_jsx(Button, { slot: "close", variant: "tertiary", isDisabled: isPending, children: localization.settings.cancel }), _jsxs(Button, { type: "submit", variant: "danger", isPending: isPending, children: [isPending && _jsx(Spinner, { color: "current", size: "sm" }), deleteUserLocalization.deleteAccount] })] })] }) }) }) })] })] }) }));
50
- }