@better-auth-ui/heroui 1.6.6 → 1.6.8

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 (50) hide show
  1. package/dist/components/auth/api-key/api-key-skeleton.d.ts +1 -0
  2. package/dist/components/auth/api-key/api-key-skeleton.js +21 -0
  3. package/dist/components/auth/api-key/api-key.d.ts +5 -0
  4. package/dist/components/auth/api-key/api-key.js +55 -0
  5. package/dist/components/auth/api-key/api-keys-empty.d.ts +4 -0
  6. package/dist/components/auth/api-key/api-keys-empty.js +35 -0
  7. package/dist/components/auth/api-key/api-keys.d.ts +6 -0
  8. package/dist/components/auth/api-key/api-keys.js +41 -0
  9. package/dist/components/auth/api-key/create-api-key-dialog.d.ts +5 -0
  10. package/dist/components/auth/api-key/create-api-key-dialog.js +74 -0
  11. package/dist/components/auth/api-key/delete-api-key-dialog.d.ts +7 -0
  12. package/dist/components/auth/api-key/delete-api-key-dialog.js +51 -0
  13. package/dist/components/auth/api-key/new-api-key-dialog.d.ts +7 -0
  14. package/dist/components/auth/api-key/new-api-key-dialog.js +60 -0
  15. package/dist/components/auth/multi-session/switch-account-submenu-content.js +14 -15
  16. package/dist/components/auth/passkey/add-passkey-dialog.d.ts +5 -0
  17. package/dist/components/auth/passkey/add-passkey-dialog.js +65 -0
  18. package/dist/components/auth/passkey/delete-passkey-dialog.d.ts +11 -0
  19. package/dist/components/auth/passkey/delete-passkey-dialog.js +47 -0
  20. package/dist/components/auth/passkey/passkey-skeleton.d.ts +1 -0
  21. package/dist/components/auth/passkey/passkey-skeleton.js +17 -0
  22. package/dist/components/auth/passkey/passkey.d.ts +2 -5
  23. package/dist/components/auth/passkey/passkey.js +16 -13
  24. package/dist/components/auth/passkey/passkeys-empty.d.ts +4 -0
  25. package/dist/components/auth/passkey/passkeys-empty.js +35 -0
  26. package/dist/components/auth/passkey/passkeys.js +35 -99
  27. package/dist/components/auth/settings/security/linked-account.js +1 -1
  28. package/dist/lib/auth/api-key-plugin.d.ts +23 -0
  29. package/dist/lib/auth/api-key-plugin.js +10 -0
  30. package/dist/lib/auth/passkey-plugin.d.ts +4 -1
  31. package/dist/plugins.d.ts +2 -0
  32. package/dist/plugins.js +22 -20
  33. package/package.json +3 -3
  34. package/src/components/auth/api-key/api-key-skeleton.tsx +17 -0
  35. package/src/components/auth/api-key/api-key.tsx +64 -0
  36. package/src/components/auth/api-key/api-keys-empty.tsx +33 -0
  37. package/src/components/auth/api-key/api-keys.tsx +71 -0
  38. package/src/components/auth/api-key/create-api-key-dialog.tsx +134 -0
  39. package/src/components/auth/api-key/delete-api-key-dialog.tsx +92 -0
  40. package/src/components/auth/api-key/new-api-key-dialog.tsx +94 -0
  41. package/src/components/auth/multi-session/switch-account-submenu-content.tsx +1 -3
  42. package/src/components/auth/passkey/add-passkey-dialog.tsx +109 -0
  43. package/src/components/auth/passkey/delete-passkey-dialog.tsx +95 -0
  44. package/src/components/auth/passkey/passkey-skeleton.tsx +16 -0
  45. package/src/components/auth/passkey/passkey.tsx +23 -22
  46. package/src/components/auth/passkey/passkeys-empty.tsx +35 -0
  47. package/src/components/auth/passkey/passkeys.tsx +33 -154
  48. package/src/components/auth/settings/security/linked-account.tsx +2 -4
  49. package/src/lib/auth/api-key-plugin.ts +15 -0
  50. package/src/plugins.ts +2 -0
@@ -1,29 +1,17 @@
1
1
  import {
2
2
  type PasskeyAuthClient,
3
- useAddPasskey,
4
3
  useAuth,
5
4
  useAuthPlugin,
6
5
  useListPasskeys
7
6
  } from "@better-auth-ui/react"
8
- import { Fingerprint } from "@gravity-ui/icons"
9
- import {
10
- AlertDialog,
11
- Button,
12
- Card,
13
- type CardProps,
14
- cn,
15
- FieldError,
16
- Form,
17
- Input,
18
- Label,
19
- Skeleton,
20
- Spinner,
21
- TextField
22
- } from "@heroui/react"
23
- import { type SyntheticEvent, useState } from "react"
7
+ import { Button, Card, type CardProps, cn } from "@heroui/react"
8
+ import { useState } from "react"
24
9
 
25
10
  import { passkeyPlugin } from "../../../lib/auth/passkey-plugin"
11
+ import { AddPasskeyDialog } from "./add-passkey-dialog"
26
12
  import { Passkey } from "./passkey"
13
+ import { PasskeySkeleton } from "./passkey-skeleton"
14
+ import { PasskeysEmpty } from "./passkeys-empty"
27
15
 
28
16
  export type PasskeysProps = {
29
17
  className?: string
@@ -35,162 +23,53 @@ export function Passkeys({
35
23
  variant,
36
24
  ...props
37
25
  }: PasskeysProps & Omit<CardProps, "children">) {
38
- const { authClient, localization } = useAuth()
26
+ const { authClient } = useAuth()
39
27
  const { localization: passkeyLocalization } = useAuthPlugin(passkeyPlugin)
40
28
 
41
29
  const { data: passkeys, isPending } = useListPasskeys(
42
30
  authClient as PasskeyAuthClient
43
31
  )
44
- const { mutate: addPasskey, isPending: isAdding } = useAddPasskey(
45
- authClient as PasskeyAuthClient
46
- )
47
-
48
- const [nameOpen, setNameOpen] = useState(false)
49
- const [name, setName] = useState("")
50
32
 
51
- const handleDialogOpenChange = (open: boolean) => {
52
- setNameOpen(open)
53
- setName("")
54
- }
55
-
56
- const handleSubmit = async (e: SyntheticEvent<HTMLFormElement>) => {
57
- e.preventDefault()
58
-
59
- addPasskey(
60
- { name: name.trim() || undefined },
61
- {
62
- onSuccess: () => {
63
- setNameOpen(false)
64
- setName("")
65
- }
66
- }
67
- )
68
- }
33
+ const [addOpen, setAddOpen] = useState(false)
69
34
 
70
35
  return (
71
- <div>
72
- <h2 className={cn("text-sm font-semibold mb-3")}>
73
- {passkeyLocalization.passkeys}
74
- </h2>
75
-
76
- <Card className={cn(className)} variant={variant} {...props}>
77
- <Card.Content className="gap-0">
78
- <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
79
- <div>
80
- <p className="text-sm font-medium leading-tight">
81
- {passkeyLocalization.passkeysDescription}
82
- </p>
83
-
84
- <p className="text-muted text-xs mt-0.5">
85
- {passkeyLocalization.passkeysInstructions}
86
- </p>
87
- </div>
88
-
89
- <AlertDialog>
90
- <Button
91
- className="shrink-0"
92
- size="sm"
93
- isDisabled={isPending}
94
- onPress={() => setNameOpen(true)}
95
- >
96
- {passkeyLocalization.addPasskey}
97
- </Button>
98
-
99
- <AlertDialog.Backdrop
100
- isOpen={nameOpen}
101
- onOpenChange={handleDialogOpenChange}
102
- >
103
- <AlertDialog.Container>
104
- <AlertDialog.Dialog>
105
- <Form onSubmit={handleSubmit}>
106
- <AlertDialog.CloseTrigger />
107
-
108
- <AlertDialog.Header>
109
- <AlertDialog.Icon status="default">
110
- <Fingerprint />
111
- </AlertDialog.Icon>
112
-
113
- <AlertDialog.Heading>
114
- {passkeyLocalization.addPasskey}
115
- </AlertDialog.Heading>
116
- </AlertDialog.Header>
117
-
118
- <AlertDialog.Body className="overflow-visible">
119
- <p className="text-muted text-sm">
120
- {passkeyLocalization.passkeysInstructions}
121
- </p>
122
-
123
- <TextField
124
- className="mt-4"
125
- name="passkey-name"
126
- isDisabled={isAdding}
127
- value={name}
128
- onChange={setName}
129
- >
130
- <Label>{passkeyLocalization.passkey}</Label>
131
-
132
- <Input
133
- autoFocus
134
- placeholder={localization.settings.optional}
135
- variant="secondary"
136
- />
137
-
138
- <FieldError />
139
- </TextField>
140
- </AlertDialog.Body>
141
-
142
- <AlertDialog.Footer>
143
- <Button
144
- slot="close"
145
- variant="tertiary"
146
- isDisabled={isAdding}
147
- >
148
- {localization.settings.cancel}
149
- </Button>
150
-
151
- <Button type="submit" isPending={isAdding}>
152
- {isAdding && <Spinner color="current" size="sm" />}
153
-
154
- {passkeyLocalization.addPasskey}
155
- </Button>
156
- </AlertDialog.Footer>
157
- </Form>
158
- </AlertDialog.Dialog>
159
- </AlertDialog.Container>
160
- </AlertDialog.Backdrop>
161
- </AlertDialog>
162
- </div>
36
+ <div className={cn("flex flex-col gap-3", className)}>
37
+ <div className="flex items-end justify-between gap-3">
38
+ <h2 className="text-sm font-semibold truncate">
39
+ {passkeyLocalization.passkeys}
40
+ </h2>
41
+
42
+ <Button
43
+ className="shrink-0"
44
+ size="sm"
45
+ isDisabled={isPending}
46
+ onPress={() => setAddOpen(true)}
47
+ >
48
+ {passkeyLocalization.addPasskey}
49
+ </Button>
50
+ </div>
163
51
 
52
+ <Card variant={variant} {...props}>
53
+ <Card.Content>
164
54
  {isPending ? (
165
- <>
166
- <div className="border-b border-dashed -mx-4 md:-mx-6 my-4" />
167
- <PasskeySkeleton />
168
- </>
55
+ <PasskeySkeleton />
56
+ ) : !passkeys?.length ? (
57
+ <PasskeysEmpty onAddPress={() => setAddOpen(true)} />
169
58
  ) : (
170
- passkeys?.map((passkey) => (
59
+ passkeys.map((passkey, index) => (
171
60
  <div key={passkey.id}>
172
- <div className="border-b border-dashed -mx-4 md:-mx-6 my-4" />
61
+ {index > 0 && (
62
+ <div className="border-b border-dashed -mx-4 my-4" />
63
+ )}
64
+
173
65
  <Passkey passkey={passkey} />
174
66
  </div>
175
67
  ))
176
68
  )}
177
69
  </Card.Content>
178
70
  </Card>
179
- </div>
180
- )
181
- }
182
71
 
183
- function PasskeySkeleton() {
184
- return (
185
- <div className="flex items-center justify-between">
186
- <div className="flex items-center gap-3">
187
- <Skeleton className="size-10 rounded-xl" />
188
-
189
- <div className="flex flex-col gap-1">
190
- <Skeleton className="h-4 w-24 rounded-lg" />
191
- <Skeleton className="h-3 w-20 rounded-lg" />
192
- </div>
193
- </div>
72
+ <AddPasskeyDialog isOpen={addOpen} onOpenChange={setAddOpen} />
194
73
  </div>
195
74
  )
196
75
  }
@@ -60,11 +60,9 @@ export function LinkedAccount({ account, provider }: LinkedAccountProps) {
60
60
  )}
61
61
  >
62
62
  {ProviderIcon ? (
63
- <ProviderIcon className={cn("size-4.5", !account && "opacity-50")} />
63
+ <ProviderIcon className="size-4.5" />
64
64
  ) : (
65
- <PlugConnection
66
- className={cn("size-4.5", !account && "opacity-50")}
67
- />
65
+ <PlugConnection className="size-4.5" />
68
66
  )}
69
67
  </div>
70
68
 
@@ -0,0 +1,15 @@
1
+ import { createAuthPlugin } from "@better-auth-ui/core"
2
+ import {
3
+ type ApiKeyPluginOptions,
4
+ apiKeyPlugin as coreApiKeyPlugin
5
+ } from "@better-auth-ui/core/plugins"
6
+
7
+ import { ApiKeys } from "../../components/auth/api-key/api-keys"
8
+
9
+ export const apiKeyPlugin = createAuthPlugin(
10
+ coreApiKeyPlugin.id,
11
+ (options: ApiKeyPluginOptions = {}) => ({
12
+ ...coreApiKeyPlugin(options),
13
+ securityCards: [ApiKeys]
14
+ })
15
+ )
package/src/plugins.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  "use client"
2
2
 
3
+ export * from "./components/auth/api-key/api-keys"
3
4
  export * from "./components/auth/delete-user/danger-zone"
4
5
  export * from "./components/auth/delete-user/delete-user"
5
6
  // Plugin-contributed components that may be used standalone
@@ -14,6 +15,7 @@ export * from "./components/auth/theme/appearance"
14
15
  export * from "./components/auth/theme/theme-toggle-item"
15
16
  export * from "./components/auth/username/sign-in-username"
16
17
  export * from "./components/auth/username/username-field"
18
+ export * from "./lib/auth/api-key-plugin"
17
19
  export * from "./lib/auth/auth-plugin"
18
20
  export * from "./lib/auth/delete-user-plugin"
19
21
  export * from "./lib/auth/magic-link-plugin"