@zerodev/wallet-react-ui 0.0.6 → 0.0.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.
Files changed (53) hide show
  1. package/README.md +54 -10
  2. package/dist/_types/auth/authStoreSlice.d.ts +3 -4
  3. package/dist/_types/auth/authStoreSlice.d.ts.map +1 -1
  4. package/dist/_types/auth/hooks/useAuth.d.ts +0 -2
  5. package/dist/_types/auth/hooks/useAuth.d.ts.map +1 -1
  6. package/dist/_types/auth/index.d.ts +9 -1
  7. package/dist/_types/auth/index.d.ts.map +1 -1
  8. package/dist/_types/auth/pages/OtpInput.d.ts.map +1 -1
  9. package/dist/_types/auth/pages/SignUp/Email.d.ts +4 -0
  10. package/dist/_types/auth/pages/SignUp/Email.d.ts.map +1 -0
  11. package/dist/_types/auth/pages/SignUp/Google.d.ts +3 -0
  12. package/dist/_types/auth/pages/SignUp/Google.d.ts.map +1 -0
  13. package/dist/_types/auth/pages/SignUp/Passkey.d.ts +3 -0
  14. package/dist/_types/auth/pages/SignUp/Passkey.d.ts.map +1 -0
  15. package/dist/_types/auth/pages/SignUp/context.d.ts +25 -0
  16. package/dist/_types/auth/pages/SignUp/context.d.ts.map +1 -0
  17. package/dist/_types/auth/pages/SignUp/index.d.ts +31 -0
  18. package/dist/_types/auth/pages/SignUp/index.d.ts.map +1 -0
  19. package/dist/_types/auth/pages/Verifying.d.ts.map +1 -1
  20. package/dist/_types/auth/types.d.ts +0 -8
  21. package/dist/_types/auth/types.d.ts.map +1 -1
  22. package/dist/_types/auth/utils/isCancellationError.d.ts +2 -0
  23. package/dist/_types/auth/utils/isCancellationError.d.ts.map +1 -0
  24. package/dist/_types/connector.d.ts +3 -13
  25. package/dist/_types/connector.d.ts.map +1 -1
  26. package/dist/_types/index.d.ts +4 -3
  27. package/dist/_types/index.d.ts.map +1 -1
  28. package/dist/_types/store.d.ts +1 -6
  29. package/dist/_types/store.d.ts.map +1 -1
  30. package/dist/index.cjs +3 -3
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.mjs +555 -562
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/styles.css +1 -1
  35. package/package.json +3 -3
  36. package/src/auth/authStoreSlice.ts +7 -13
  37. package/src/auth/hooks/useAuth.ts +0 -5
  38. package/src/auth/index.tsx +19 -7
  39. package/src/auth/pages/OtpInput.tsx +1 -4
  40. package/src/auth/pages/SignUp/Email.tsx +86 -0
  41. package/src/auth/pages/SignUp/Google.tsx +43 -0
  42. package/src/auth/pages/SignUp/Passkey.tsx +56 -0
  43. package/src/auth/pages/SignUp/context.tsx +41 -0
  44. package/src/auth/pages/SignUp/index.tsx +138 -0
  45. package/src/auth/pages/Verifying.tsx +3 -10
  46. package/src/auth/types.ts +0 -9
  47. package/src/auth/utils/isCancellationError.ts +8 -0
  48. package/src/connector.ts +12 -28
  49. package/src/index.ts +3 -3
  50. package/src/store.ts +1 -8
  51. package/dist/_types/auth/pages/SignUp.d.ts +0 -2
  52. package/dist/_types/auth/pages/SignUp.d.ts.map +0 -1
  53. package/src/auth/pages/SignUp.tsx +0 -311
package/src/index.ts CHANGED
@@ -4,14 +4,14 @@
4
4
  */
5
5
 
6
6
  // Auth
7
- export { AuthFlow } from './auth'
7
+ export { ConnectWallet } from './auth'
8
8
  export { useAuth } from './auth/hooks/useAuth'
9
- export type { AuthMethod, AuthStep } from './auth/types'
9
+ export { SignUp } from './auth/pages/SignUp'
10
+ export type { AuthMethod, AuthStep, EmailAuthMethod } from './auth/types'
10
11
 
11
12
  // Connector
12
13
  export type {
13
14
  // SigningConfig,
14
- ZeroDevKitConfig,
15
15
  ZeroDevKitConnectorParams,
16
16
  } from './connector.js'
17
17
  export { zeroDevWallet } from './connector.js'
package/src/store.ts CHANGED
@@ -1,4 +1,3 @@
1
- import type { ReactNode } from 'react'
2
1
  import { create } from 'zustand'
3
2
  import { subscribeWithSelector } from 'zustand/middleware'
4
3
  import {
@@ -10,23 +9,17 @@ import type { PendingRequest } from './types.js'
10
9
  export type State = {
11
10
  pendingRequests: PendingRequest[]
12
11
  userConfirmationListenerActive: boolean
13
- logo: ReactNode | null
14
12
  addPendingRequest: (request: PendingRequest) => void
15
13
  removePendingRequest: (id: string) => void
16
14
  clearPendingRequests: () => void
17
15
  setUserConfirmationListenerActive: (active: boolean) => void
18
16
  } & AuthStoreSlice
19
17
 
20
- export type CreateStoreOptions = {
21
- logo?: ReactNode
22
- }
23
-
24
- export const createStore = (options: CreateStoreOptions = {}) =>
18
+ export const createStore = () =>
25
19
  create<State>()(
26
20
  subscribeWithSelector((set, get, store) => ({
27
21
  pendingRequests: [],
28
22
  userConfirmationListenerActive: false,
29
- logo: options.logo ?? null,
30
23
  addPendingRequest: (request) =>
31
24
  set((state) => ({
32
25
  pendingRequests: [...state.pendingRequests, request],
@@ -1,2 +0,0 @@
1
- export declare function SignUp(): import("react").JSX.Element;
2
- //# sourceMappingURL=SignUp.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SignUp.d.ts","sourceRoot":"","sources":["../../../../src/auth/pages/SignUp.tsx"],"names":[],"mappings":"AA+BA,wBAAgB,MAAM,gCAuRrB"}
@@ -1,311 +0,0 @@
1
- import {
2
- Button,
3
- Icon,
4
- Input,
5
- ListItem,
6
- ListItemChevron,
7
- ListItemIcon,
8
- Text,
9
- } from '@zerodev/react-ui'
10
- import {
11
- useAuthenticateOAuth,
12
- useLoginPasskey,
13
- useRegisterPasskey,
14
- useSendMagicLink,
15
- useSendOTP,
16
- } from '@zerodev/wallet-react'
17
- import { useState } from 'react'
18
- import { SignUpFooter } from '../../shared/components/SignUpFooter'
19
- import { isValidEmailAddress } from '../../shared/utils/common'
20
- import { BlobAnimation } from '../components/BlobAnimation'
21
- import { useAuth } from '../hooks/useAuth'
22
-
23
- function isCancellationError(err: unknown): boolean {
24
- if (!(err instanceof Error)) return false
25
- // WebAuthn / passkey
26
- if (err.name === 'AbortError' || err.name === 'NotAllowedError') return true
27
- // OAuth (existing logic, message-based)
28
- const msg = err.message.toLowerCase()
29
- return msg.includes('oauth popup was closed')
30
- }
31
-
32
- export function SignUp() {
33
- const { goToStep, setEmail, setOtpSession, config, enabledMethods } =
34
- useAuth()
35
- const [agreedToTerms, setAgreedToTerms] = useState(false)
36
- const [highlightAgreement, setHighlightAgreement] = useState(false)
37
- const [emailInput, setEmailInput] = useState('')
38
- const shouldUseOtp = config?.emailAuthMethod === 'otp'
39
- const { mutateAsync: sendOtp, isPending: isSendOtpPending } = useSendOTP()
40
- const { mutateAsync: sendMagicLink, isPending: isSendMagicLinkPending } =
41
- useSendMagicLink()
42
- const isEmailLoading = isSendOtpPending || isSendMagicLinkPending
43
-
44
- const [error, setError] = useState<string | null>(null)
45
-
46
- const { mutateAsync: authenticateOAuth, isPending: isGoogleLoading } =
47
- useAuthenticateOAuth({
48
- mutation: {
49
- onSuccess: async () => {
50
- goToStep('authenticated')
51
- config?.onSuccess?.()
52
- },
53
- onError: (err) => {
54
- config?.onError?.(err)
55
- },
56
- },
57
- })
58
-
59
- const { mutate: registerPasskey, isPending: isRegisterPasskeyPending } =
60
- useRegisterPasskey({
61
- mutation: {
62
- onSuccess: () => {
63
- goToStep('authenticated')
64
- config?.onSuccess?.()
65
- },
66
- onError: (err) => {
67
- if (!isCancellationError(err)) {
68
- setError(err instanceof Error ? err.message : String(err))
69
- }
70
- config?.onError?.(err)
71
- },
72
- },
73
- })
74
-
75
- const { mutate: loginPasskey, isPending: isLoginPasskeyPending } =
76
- useLoginPasskey({
77
- mutation: {
78
- onSuccess: () => {
79
- goToStep('authenticated')
80
- config?.onSuccess?.()
81
- },
82
- onError: (err) => {
83
- if (!isCancellationError(err)) {
84
- setError(err instanceof Error ? err.message : String(err))
85
- }
86
- config?.onError?.(err)
87
- },
88
- },
89
- })
90
-
91
- const anyPending =
92
- isGoogleLoading ||
93
- isEmailLoading ||
94
- isRegisterPasskeyPending ||
95
- isLoginPasskeyPending
96
- const requiresAgreement = !!(
97
- config?.termsAndConditionsUrl || config?.privacyPolicyUrl
98
- )
99
- const needsToAcceptAgreement = requiresAgreement && !agreedToTerms
100
-
101
- const handleRegisterPasskey = () => {
102
- if (anyPending) return
103
- if (needsToAcceptAgreement) {
104
- setHighlightAgreement(true)
105
- return
106
- }
107
- setError(null)
108
- registerPasskey()
109
- }
110
-
111
- const handleLoginPasskey = () => {
112
- if (anyPending) return
113
- if (needsToAcceptAgreement) {
114
- setHighlightAgreement(true)
115
- return
116
- }
117
- setError(null)
118
- loginPasskey()
119
- }
120
-
121
- const handleGoogleAuth = async () => {
122
- if (needsToAcceptAgreement) {
123
- setHighlightAgreement(true)
124
- return
125
- }
126
- setError(null)
127
- try {
128
- await authenticateOAuth({ provider: 'google' })
129
- } catch (err) {
130
- const message = err instanceof Error ? err.message : String(err)
131
- if (!isCancellationError(err)) {
132
- setError(message)
133
- }
134
- }
135
- }
136
-
137
- const handleEmailOtp = async () => {
138
- if (!emailInput || anyPending) return
139
- if (!isValidEmailAddress(emailInput)) return
140
- if (needsToAcceptAgreement) {
141
- setHighlightAgreement(true)
142
- return
143
- }
144
-
145
- setError(null)
146
- try {
147
- const { otpId, otpEncryptionTargetBundle } = await sendOtp({
148
- email: emailInput,
149
- })
150
- setEmail(emailInput)
151
- setOtpSession({ otpId, otpEncryptionTargetBundle })
152
- goToStep('otp-input')
153
- } catch (err) {
154
- setError(
155
- err instanceof Error ? err.message : 'Failed to send verification code',
156
- )
157
- }
158
- }
159
-
160
- const handleEmailMagicLink = async () => {
161
- if (!emailInput || anyPending) return
162
- if (!isValidEmailAddress(emailInput)) return
163
- if (needsToAcceptAgreement) {
164
- setHighlightAgreement(true)
165
- return
166
- }
167
-
168
- setError(null)
169
- try {
170
- const { otpId, otpEncryptionTargetBundle } = await sendMagicLink({
171
- email: emailInput,
172
- })
173
- setEmail(emailInput)
174
- setOtpSession({ otpId, otpEncryptionTargetBundle })
175
- goToStep('email-verification')
176
- } catch (err) {
177
- setError(
178
- err instanceof Error ? err.message : 'Failed to send verification code',
179
- )
180
- }
181
- }
182
-
183
- const handleEmailSubmit = shouldUseOtp ? handleEmailOtp : handleEmailMagicLink
184
-
185
- if (error) {
186
- return (
187
- <div className="zd:flex zd:items-center zd:justify-center zd:h-full">
188
- <div className="zd:flex zd:flex-col zd:gap-4 zd:max-w-md">
189
- <Text className="zd:text-h2 zd:text-center">Error occurred</Text>
190
- <Text className="zd:text-center zd:text-red-500">{error}</Text>
191
- <Button
192
- action="primary"
193
- text="Try again"
194
- onClick={() => setError(null)}
195
- />
196
- </div>
197
- </div>
198
- )
199
- }
200
-
201
- return (
202
- <div className="zd:flex-1 zd:flex zd:flex-col zd:justify-between zd:pb-4 zd:overflow-y-auto zd:overflow-x-hidden">
203
- <div className="zd:flex-1 zd:flex zd:flex-col zd:justify-center">
204
- <div className="zd:px-4 zd:flex zd:flex-col zd:items-center">
205
- <div className="zd:w-full zd:px-16 zd:py-4">
206
- <BlobAnimation className="zd:w-full zd:pointer-events-none zd:select-none" />
207
- </div>
208
- <Text className="zd:text-h2 zd:text-center">
209
- Continue to your wallet
210
- </Text>
211
- <Text className="zd:mt-2 zd:text-center zd:text-greyScale/50">
212
- Choose a sign-in method to proceed
213
- </Text>
214
- </div>
215
- <div className="zd:mt-6 zd:flex zd:flex-col zd:gap-4 zd:mb-4">
216
- {enabledMethods.includes('passkey') && (
217
- <>
218
- <div className="zd:px-4 zd:flex zd:flex-col zd:gap-2">
219
- <Button
220
- action="secondary"
221
- text="Create a passkey"
222
- iconName="key"
223
- trailIcon
224
- disabled={anyPending}
225
- onClick={handleRegisterPasskey}
226
- />
227
- <Button
228
- action="secondary"
229
- text="Log in with passkey"
230
- iconName="key"
231
- trailIcon
232
- disabled={anyPending}
233
- onClick={handleLoginPasskey}
234
- />
235
- </div>
236
- <div className="zd:flex zd:items-center zd:gap-3">
237
- <div className="zd:h-px zd:flex-1 zd:bg-greyScale/30" />
238
- <Text className="zd:text-body3">or</Text>
239
- <div className="zd:h-px zd:flex-1 zd:bg-greyScale/30" />
240
- </div>
241
- </>
242
- )}
243
- <div className="zd:px-4 zd:flex zd:flex-col zd:gap-2">
244
- {enabledMethods.includes('google') && (
245
- <ListItem
246
- icon={<ListItemIcon name="google" />}
247
- title="Google"
248
- trailing={<ListItemChevron />}
249
- className="zd:rounded-3xl"
250
- disabled={anyPending}
251
- onClick={handleGoogleAuth}
252
- />
253
- )}
254
- {enabledMethods.includes('email') && (
255
- <Input
256
- iconName="email"
257
- placeholder="Enter your email"
258
- value={emailInput}
259
- onChange={(e) => setEmailInput(e.target.value)}
260
- type="email"
261
- autoCapitalize="none"
262
- autoComplete="email"
263
- disabled={anyPending}
264
- variant="listItemStyle"
265
- containerClassName="zd:rounded-3xl"
266
- onKeyDown={(e) => {
267
- if (e.key === 'Enter' && emailInput && !anyPending) {
268
- handleEmailSubmit()
269
- }
270
- }}
271
- >
272
- {isEmailLoading ? (
273
- <div className="zd:w-13 zd:h-13 zd:flex zd:items-center zd:justify-center">
274
- <div className="zd:w-5 zd:h-5 zd:border-2 zd:border-solarOrange zd:border-t-transparent zd:rounded-full zd:animate-spin" />
275
- </div>
276
- ) : (
277
- <button
278
- type="button"
279
- disabled={
280
- !isValidEmailAddress(emailInput) || needsToAcceptAgreement
281
- }
282
- className={`zd:w-13 zd:h-13 zd:rounded-2xl zd:flex zd:items-center zd:justify-center zd:transition-colors ${
283
- isValidEmailAddress(emailInput) && !needsToAcceptAgreement
284
- ? 'zd:cursor-pointer'
285
- : 'zd:cursor-not-allowed zd:opacity-50'
286
- }`}
287
- onClick={() => handleEmailSubmit()}
288
- >
289
- <Icon name="chevronRight" className="zd:text-greyScale" />
290
- </button>
291
- )}
292
- </Input>
293
- )}
294
- </div>
295
- </div>
296
- </div>
297
- <div className="zd:px-4">
298
- <SignUpFooter
299
- termsAndConditionsUrl={config?.termsAndConditionsUrl}
300
- privacyPolicyUrl={config?.privacyPolicyUrl}
301
- agreedToTerms={agreedToTerms}
302
- setAgreedToTerms={(agreed) => {
303
- setAgreedToTerms(agreed)
304
- if (agreed) setHighlightAgreement(false)
305
- }}
306
- highlight={highlightAgreement}
307
- />
308
- </div>
309
- </div>
310
- )
311
- }