topiray-auth-react 1.0.0
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/README.md +704 -0
- package/dist/browser-D0L_Twu1.js +1538 -0
- package/dist/components/auth/AuthCard.d.ts +3 -0
- package/dist/components/auth/ForgottenPasswordForm.d.ts +3 -0
- package/dist/components/auth/SignInForm.d.ts +3 -0
- package/dist/components/auth/SignUpForm.d.ts +3 -0
- package/dist/components/auth/TwoFactorSetupCompleteForm.d.ts +3 -0
- package/dist/components/auth/TwoFactorSetupEnterVerificationForm.d.ts +3 -0
- package/dist/components/auth/TwoFactorSetupForm.d.ts +10 -0
- package/dist/components/auth/VerifyEmailForm.d.ts +3 -0
- package/dist/components/auth/index.d.ts +9 -0
- package/dist/components/auth/types.d.ts +55 -0
- package/dist/components/common/AlertMessage.d.ts +3 -0
- package/dist/components/common/BackArrow.d.ts +3 -0
- package/dist/components/common/Button.d.ts +3 -0
- package/dist/components/common/SocialLoginButtons.d.ts +3 -0
- package/dist/components/common/types.d.ts +33 -0
- package/dist/demo.d.ts +1 -0
- package/dist/index-sG0o_Gt2.js +7856 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.es.js +23 -0
- package/dist/index.umd.js +251 -0
- package/dist/layouts/NavLinksLayout.d.ts +3 -0
- package/dist/layouts/TwoPanelLayout.d.ts +3 -0
- package/dist/layouts/types.d.ts +13 -0
- package/dist/theme/ThemeProvider.d.ts +8 -0
- package/dist/theme/defaultTheme.d.ts +4 -0
- package/dist/theme/types.d.ts +100 -0
- package/dist/topiray-auth-react.css +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
# Topiray Auth React Component Library
|
|
2
|
+
|
|
3
|
+
A comprehensive, themeable React component library for authentication flows. Built with TypeScript, CSS Modules, and designed for maximum customization and accessibility.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎨 **Fully Themeable** - Customize colors, fonts, spacing, and more
|
|
8
|
+
- 🔧 **CSS Modules** - Strongly-typed, scoped styling
|
|
9
|
+
- 📱 **Responsive Design** - Mobile-first approach with breakpoint support
|
|
10
|
+
- ♿ **Accessible** - ARIA labels, keyboard navigation, focus management
|
|
11
|
+
- 🔒 **Complete Auth Flow** - Sign in/up, 2FA, email verification, password reset
|
|
12
|
+
- ⚡ **TypeScript** - Full type safety and IntelliSense support
|
|
13
|
+
- 🎯 **Tree Shakeable** - Import only what you need
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install topiray-auth-react
|
|
19
|
+
# or
|
|
20
|
+
yarn add topiray-auth-react
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Peer Dependencies
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install react react-dom lucide-react @mui/material
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### CSS Import
|
|
30
|
+
|
|
31
|
+
**Important**: You must import the CSS file for proper styling:
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
// Import the CSS file in your main App component or index file
|
|
35
|
+
import 'topiray-auth-react/dist/topiray-auth-react.css'
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Or if you're using a bundler that supports CSS imports:
|
|
39
|
+
|
|
40
|
+
```css
|
|
41
|
+
/* In your main CSS file */
|
|
42
|
+
@import 'topiray-auth-react/dist/topiray-auth-react.css';
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import React from 'react'
|
|
49
|
+
import {
|
|
50
|
+
ThemeProvider,
|
|
51
|
+
defaultTheme,
|
|
52
|
+
TwoPanelLayout,
|
|
53
|
+
AuthCard,
|
|
54
|
+
SignInForm
|
|
55
|
+
} from 'topiray-auth-react'
|
|
56
|
+
|
|
57
|
+
// Import the CSS file
|
|
58
|
+
import 'topiray-auth-react/dist/topiray-auth-react.css'
|
|
59
|
+
|
|
60
|
+
function App() {
|
|
61
|
+
const handleSignIn = (email: string, password: string) => {
|
|
62
|
+
console.log('Sign in:', { email, password })
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<ThemeProvider theme={defaultTheme}>
|
|
67
|
+
<TwoPanelLayout
|
|
68
|
+
rightContent={
|
|
69
|
+
<AuthCard>
|
|
70
|
+
<SignInForm
|
|
71
|
+
onSubmit={handleSignIn}
|
|
72
|
+
onForgotPassword={() => console.log('Forgot password')}
|
|
73
|
+
onSignUp={() => console.log('Sign up')}
|
|
74
|
+
onSocialLogin={(provider) => console.log('Social:', provider)}
|
|
75
|
+
/>
|
|
76
|
+
</AuthCard>
|
|
77
|
+
}
|
|
78
|
+
/>
|
|
79
|
+
</ThemeProvider>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Components
|
|
85
|
+
|
|
86
|
+
### Auth Components
|
|
87
|
+
|
|
88
|
+
#### AuthCard
|
|
89
|
+
Container wrapper for auth forms with consistent styling.
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
import { AuthCard } from 'topiray-auth-react'
|
|
93
|
+
|
|
94
|
+
<AuthCard>
|
|
95
|
+
{/* Your auth form content */}
|
|
96
|
+
</AuthCard>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### SignInForm
|
|
100
|
+
Complete sign-in form with email/password and social login options.
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
import { SignInForm } from 'topiray-auth-react'
|
|
104
|
+
|
|
105
|
+
<SignInForm
|
|
106
|
+
onSubmit={(email, password) => handleSignIn(email, password)}
|
|
107
|
+
onForgotPassword={() => navigate('/forgot-password')}
|
|
108
|
+
onSignUp={() => navigate('/sign-up')}
|
|
109
|
+
onSocialLogin={(provider) => handleSocialLogin(provider)}
|
|
110
|
+
isLoading={isSigningIn}
|
|
111
|
+
logoSrc="/your-logo.png"
|
|
112
|
+
/>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### SignUpForm
|
|
116
|
+
Account creation form with business/individual selection.
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import { SignUpForm } from 'topiray-auth-react'
|
|
120
|
+
|
|
121
|
+
<SignUpForm
|
|
122
|
+
onSubmit={(email, password, accountType) => handleSignUp(email, password, accountType)}
|
|
123
|
+
onSignIn={() => navigate('/sign-in')}
|
|
124
|
+
onSocialLogin={(provider) => handleSocialLogin(provider)}
|
|
125
|
+
isLoading={isSigningUp}
|
|
126
|
+
/>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### ForgottenPasswordForm
|
|
130
|
+
Password reset request form.
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
import { ForgottenPasswordForm } from 'topiray-auth-react'
|
|
134
|
+
|
|
135
|
+
<ForgottenPasswordForm
|
|
136
|
+
onSubmit={(email) => handlePasswordReset(email)}
|
|
137
|
+
isLoading={isLoading}
|
|
138
|
+
/>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### VerifyEmailForm
|
|
142
|
+
Email verification flow with resend functionality.
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
import { VerifyEmailForm } from 'topiray-auth-react'
|
|
146
|
+
|
|
147
|
+
<VerifyEmailForm
|
|
148
|
+
onSubmit={() => navigate('/sign-in')}
|
|
149
|
+
onResendEmail={() => handleResendEmail()}
|
|
150
|
+
email="user@example.com"
|
|
151
|
+
isLoading={isLoading}
|
|
152
|
+
/>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Two-Factor Authentication
|
|
156
|
+
|
|
157
|
+
#### TwoFactorSetupForm
|
|
158
|
+
QR code setup for authenticator apps.
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
import { TwoFactorSetupForm } from 'topiray-auth-react'
|
|
162
|
+
|
|
163
|
+
<TwoFactorSetupForm
|
|
164
|
+
onNext={() => navigate('/2fa/verify')}
|
|
165
|
+
onCancel={() => navigate('/dashboard')}
|
|
166
|
+
qrCodeUri="otpauth://totp/App:user@example.com?secret=SECRET&issuer=App"
|
|
167
|
+
sharedKey="JBSWY3DPEHPK3PXP"
|
|
168
|
+
isLoading={isLoading}
|
|
169
|
+
/>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### TwoFactorSetupEnterVerificationForm
|
|
173
|
+
6-digit code entry with auto-focus and paste support.
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
import { TwoFactorSetupEnterVerificationForm } from 'topiray-auth-react'
|
|
177
|
+
|
|
178
|
+
<TwoFactorSetupEnterVerificationForm
|
|
179
|
+
onVerify={(code) => handleVerification(code)}
|
|
180
|
+
isLoading={isVerifying}
|
|
181
|
+
error={error}
|
|
182
|
+
backRoute="/2fa/setup"
|
|
183
|
+
/>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### TwoFactorSetupCompleteForm
|
|
187
|
+
Backup codes display with copy/download functionality.
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
import { TwoFactorSetupCompleteForm } from 'topiray-auth-react'
|
|
191
|
+
|
|
192
|
+
<TwoFactorSetupCompleteForm
|
|
193
|
+
onDone={() => navigate('/dashboard')}
|
|
194
|
+
backupCodes={recoveryCodes}
|
|
195
|
+
isLoading={isLoading}
|
|
196
|
+
/>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Layout Components
|
|
200
|
+
|
|
201
|
+
#### TwoPanelLayout
|
|
202
|
+
Responsive layout with left branding panel and right content area.
|
|
203
|
+
|
|
204
|
+
```tsx
|
|
205
|
+
import { TwoPanelLayout } from 'topiray-auth-react'
|
|
206
|
+
|
|
207
|
+
<TwoPanelLayout
|
|
208
|
+
leftContent={<YourBrandingContent />}
|
|
209
|
+
rightContent={<YourAuthForm />}
|
|
210
|
+
leftBackgroundImage="/background.jpg"
|
|
211
|
+
logoSrc="/logo.png"
|
|
212
|
+
/>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### NavLinksLayout
|
|
216
|
+
Flexible content layout for pages with navigation.
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
import { NavLinksLayout } from 'topiray-auth-react'
|
|
220
|
+
|
|
221
|
+
<NavLinksLayout
|
|
222
|
+
middle={<MainContent />}
|
|
223
|
+
right={<SidebarContent />}
|
|
224
|
+
/>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Common Components
|
|
228
|
+
|
|
229
|
+
#### Button
|
|
230
|
+
Versatile button with loading states and variants.
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
import { Button } from 'topiray-auth-react'
|
|
234
|
+
|
|
235
|
+
<Button variant="primary" isLoading={isLoading} fullWidth>
|
|
236
|
+
Sign In
|
|
237
|
+
</Button>
|
|
238
|
+
|
|
239
|
+
<Button variant="secondary" icon="google">
|
|
240
|
+
Sign in with Google
|
|
241
|
+
</Button>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### AlertMessage
|
|
245
|
+
Dismissible alert messages for different states.
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
import { AlertMessage } from 'topiray-auth-react'
|
|
249
|
+
|
|
250
|
+
<AlertMessage
|
|
251
|
+
type="error"
|
|
252
|
+
message="Invalid credentials"
|
|
253
|
+
dismissible
|
|
254
|
+
onDismiss={() => setError(null)}
|
|
255
|
+
/>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
#### SocialLoginButtons
|
|
259
|
+
Pre-configured social login buttons.
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
import { SocialLoginButtons } from 'topiray-auth-react'
|
|
263
|
+
|
|
264
|
+
<SocialLoginButtons
|
|
265
|
+
onSocialLogin={(provider) => handleSocialLogin(provider)}
|
|
266
|
+
providers={['google', 'apple', 'facebook']}
|
|
267
|
+
orientation="vertical"
|
|
268
|
+
isLoading={isLoading}
|
|
269
|
+
/>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Real-World Usage Examples
|
|
273
|
+
|
|
274
|
+
### Complete Sign-In Page
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
import React, { useState, useEffect } from 'react'
|
|
278
|
+
import { useNavigate, useLocation } from 'react-router-dom'
|
|
279
|
+
import {
|
|
280
|
+
ThemeProvider,
|
|
281
|
+
defaultTheme,
|
|
282
|
+
TwoPanelLayout,
|
|
283
|
+
AuthCard,
|
|
284
|
+
SignInForm,
|
|
285
|
+
AlertMessage
|
|
286
|
+
} from 'topiray-auth-react'
|
|
287
|
+
|
|
288
|
+
// Import the CSS file
|
|
289
|
+
import 'topiray-auth-react/dist/topiray-auth-react.css'
|
|
290
|
+
|
|
291
|
+
function SignInPage() {
|
|
292
|
+
const navigate = useNavigate()
|
|
293
|
+
const location = useLocation()
|
|
294
|
+
const [error, setError] = useState<string | null>(null)
|
|
295
|
+
const [isLoading, setIsLoading] = useState(false)
|
|
296
|
+
|
|
297
|
+
// Get success message from registration
|
|
298
|
+
const successMessage = location.state?.message
|
|
299
|
+
|
|
300
|
+
const handleSignIn = async (email: string, password: string) => {
|
|
301
|
+
try {
|
|
302
|
+
setError(null)
|
|
303
|
+
setIsLoading(true)
|
|
304
|
+
|
|
305
|
+
const result = await signInAPI(email, password)
|
|
306
|
+
|
|
307
|
+
if (result.succeeded) {
|
|
308
|
+
navigate('/dashboard')
|
|
309
|
+
} else if (result.requiresTwoFactor) {
|
|
310
|
+
navigate('/2fa/signin', { state: { userId: result.userId } })
|
|
311
|
+
} else if (result.isNotAllowed) {
|
|
312
|
+
navigate(`/verify-email?email=${encodeURIComponent(email)}`)
|
|
313
|
+
} else {
|
|
314
|
+
setError('Invalid email or password.')
|
|
315
|
+
}
|
|
316
|
+
} catch (error) {
|
|
317
|
+
setError('An error occurred during sign in.')
|
|
318
|
+
} finally {
|
|
319
|
+
setIsLoading(false)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return (
|
|
324
|
+
<ThemeProvider theme={defaultTheme}>
|
|
325
|
+
<TwoPanelLayout
|
|
326
|
+
rightContent={
|
|
327
|
+
<AuthCard>
|
|
328
|
+
{successMessage && (
|
|
329
|
+
<AlertMessage message={successMessage} type="success" />
|
|
330
|
+
)}
|
|
331
|
+
{error && (
|
|
332
|
+
<AlertMessage message={error} type="error" />
|
|
333
|
+
)}
|
|
334
|
+
<SignInForm
|
|
335
|
+
onSubmit={handleSignIn}
|
|
336
|
+
onForgotPassword={() => navigate('/forgot-password')}
|
|
337
|
+
onSignUp={() => navigate('/sign-up')}
|
|
338
|
+
onSocialLogin={(provider) => handleSocialLogin(provider)}
|
|
339
|
+
isLoading={isLoading}
|
|
340
|
+
/>
|
|
341
|
+
</AuthCard>
|
|
342
|
+
}
|
|
343
|
+
/>
|
|
344
|
+
</ThemeProvider>
|
|
345
|
+
)
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Two-Factor Setup with QR Code
|
|
350
|
+
|
|
351
|
+
```tsx
|
|
352
|
+
import React, { useEffect, useState } from 'react'
|
|
353
|
+
import { useNavigate } from 'react-router-dom'
|
|
354
|
+
import QRCode from 'qrcode'
|
|
355
|
+
import {
|
|
356
|
+
TwoPanelLayout,
|
|
357
|
+
AuthCard,
|
|
358
|
+
TwoFactorSetupForm,
|
|
359
|
+
AlertMessage
|
|
360
|
+
} from 'topiray-auth-react'
|
|
361
|
+
|
|
362
|
+
function TwoFactorSetupPage() {
|
|
363
|
+
const navigate = useNavigate()
|
|
364
|
+
const [qrCodeDataUrl, setQrCodeDataUrl] = useState<string | null>(null)
|
|
365
|
+
const [sharedKey, setSharedKey] = useState<string | null>(null)
|
|
366
|
+
const [error, setError] = useState<string | null>(null)
|
|
367
|
+
const [isLoading, setIsLoading] = useState(false)
|
|
368
|
+
|
|
369
|
+
useEffect(() => {
|
|
370
|
+
generateQRCode()
|
|
371
|
+
}, [])
|
|
372
|
+
|
|
373
|
+
const generateQRCode = async () => {
|
|
374
|
+
try {
|
|
375
|
+
setIsLoading(true)
|
|
376
|
+
const result = await createAuthenticatorKeyAPI()
|
|
377
|
+
|
|
378
|
+
if (result.authenticatorUri && result.sharedKey) {
|
|
379
|
+
const qrDataUrl = await QRCode.toDataURL(result.authenticatorUri, {
|
|
380
|
+
width: 200,
|
|
381
|
+
margin: 2
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
setQrCodeDataUrl(qrDataUrl)
|
|
385
|
+
setSharedKey(result.sharedKey)
|
|
386
|
+
|
|
387
|
+
// Render QR code
|
|
388
|
+
setTimeout(() => {
|
|
389
|
+
const container = document.getElementById('qr-code-container')
|
|
390
|
+
if (container && qrDataUrl) {
|
|
391
|
+
container.innerHTML = `<img src="${qrDataUrl}" alt="QR Code" />`
|
|
392
|
+
}
|
|
393
|
+
}, 100)
|
|
394
|
+
} else {
|
|
395
|
+
setError('Failed to generate QR code.')
|
|
396
|
+
}
|
|
397
|
+
} catch (error) {
|
|
398
|
+
setError('Failed to generate QR code.')
|
|
399
|
+
} finally {
|
|
400
|
+
setIsLoading(false)
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return (
|
|
405
|
+
<TwoPanelLayout
|
|
406
|
+
rightContent={
|
|
407
|
+
<AuthCard>
|
|
408
|
+
{error && <AlertMessage message={error} type="error" />}
|
|
409
|
+
<TwoFactorSetupForm
|
|
410
|
+
onNext={() => navigate('/2fa/verify')}
|
|
411
|
+
onCancel={() => navigate('/dashboard')}
|
|
412
|
+
qrCodeUri={qrCodeDataUrl}
|
|
413
|
+
sharedKey={sharedKey}
|
|
414
|
+
isLoading={isLoading}
|
|
415
|
+
/>
|
|
416
|
+
</AuthCard>
|
|
417
|
+
}
|
|
418
|
+
/>
|
|
419
|
+
)
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Theming
|
|
424
|
+
|
|
425
|
+
### Using Built-in Themes
|
|
426
|
+
|
|
427
|
+
```tsx
|
|
428
|
+
import { ThemeProvider, defaultTheme, darkTheme } from 'topiray-auth-react'
|
|
429
|
+
|
|
430
|
+
// Light theme
|
|
431
|
+
<ThemeProvider theme={defaultTheme}>
|
|
432
|
+
<App />
|
|
433
|
+
</ThemeProvider>
|
|
434
|
+
|
|
435
|
+
// Dark theme
|
|
436
|
+
<ThemeProvider theme={darkTheme}>
|
|
437
|
+
<App />
|
|
438
|
+
</ThemeProvider>
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Creating Custom Themes
|
|
442
|
+
|
|
443
|
+
```tsx
|
|
444
|
+
import { createCustomTheme } from 'topiray-auth-react'
|
|
445
|
+
|
|
446
|
+
const corporateTheme = createCustomTheme({
|
|
447
|
+
colors: {
|
|
448
|
+
primary: '#0066cc',
|
|
449
|
+
secondary: '#6b7280',
|
|
450
|
+
background: '#ffffff',
|
|
451
|
+
surface: '#f9fafb',
|
|
452
|
+
text: '#111827',
|
|
453
|
+
textSecondary: '#6b7280',
|
|
454
|
+
border: '#d1d5db',
|
|
455
|
+
success: '#10b981',
|
|
456
|
+
warning: '#f59e0b',
|
|
457
|
+
error: '#ef4444',
|
|
458
|
+
info: '#3b82f6',
|
|
459
|
+
hover: '#f3f4f6',
|
|
460
|
+
active: '#e5e7eb',
|
|
461
|
+
disabled: '#9ca3af',
|
|
462
|
+
inputBackground: '#ffffff',
|
|
463
|
+
inputBorder: '#d1d5db',
|
|
464
|
+
inputText: '#111827',
|
|
465
|
+
inputPlaceholder: '#9ca3af',
|
|
466
|
+
buttonPrimary: '#0066cc',
|
|
467
|
+
buttonPrimaryText: '#ffffff',
|
|
468
|
+
buttonSecondary: '#6b7280',
|
|
469
|
+
buttonSecondaryText: '#ffffff',
|
|
470
|
+
buttonSocial: '#374151',
|
|
471
|
+
buttonSocialText: '#ffffff'
|
|
472
|
+
},
|
|
473
|
+
brand: {
|
|
474
|
+
logo: '/corporate-logo.png',
|
|
475
|
+
logoAlt: 'Corporate Logo'
|
|
476
|
+
},
|
|
477
|
+
customization: {
|
|
478
|
+
showFormHeader: true,
|
|
479
|
+
showSocialLogin: true,
|
|
480
|
+
showBackArrow: true,
|
|
481
|
+
showLogo: true,
|
|
482
|
+
roundedCorners: true,
|
|
483
|
+
animations: true
|
|
484
|
+
}
|
|
485
|
+
})
|
|
486
|
+
|
|
487
|
+
<ThemeProvider theme={corporateTheme}>
|
|
488
|
+
<App />
|
|
489
|
+
</ThemeProvider>
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
### Advanced Theme Customization
|
|
493
|
+
|
|
494
|
+
```tsx
|
|
495
|
+
const advancedTheme = createCustomTheme({
|
|
496
|
+
colors: {
|
|
497
|
+
// Custom color palette
|
|
498
|
+
primary: '#7c3aed',
|
|
499
|
+
secondary: '#64748b',
|
|
500
|
+
// ... other colors
|
|
501
|
+
},
|
|
502
|
+
components: {
|
|
503
|
+
spacing: {
|
|
504
|
+
xs: '0.25rem',
|
|
505
|
+
sm: '0.5rem',
|
|
506
|
+
md: '1rem',
|
|
507
|
+
lg: '1.5rem',
|
|
508
|
+
xl: '2rem'
|
|
509
|
+
},
|
|
510
|
+
borderRadius: {
|
|
511
|
+
sm: '0.25rem',
|
|
512
|
+
md: '0.5rem',
|
|
513
|
+
lg: '0.75rem',
|
|
514
|
+
xl: '1rem'
|
|
515
|
+
},
|
|
516
|
+
typography: {
|
|
517
|
+
fontFamily: '"Inter", system-ui, sans-serif',
|
|
518
|
+
fontSize: {
|
|
519
|
+
xs: '0.75rem',
|
|
520
|
+
sm: '0.875rem',
|
|
521
|
+
md: '1rem',
|
|
522
|
+
lg: '1.125rem',
|
|
523
|
+
xl: '1.25rem',
|
|
524
|
+
xxl: '1.5rem'
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
},
|
|
528
|
+
customization: {
|
|
529
|
+
backgroundImage: '/custom-background.jpg',
|
|
530
|
+
leftPanelContent: <CustomBrandingComponent />
|
|
531
|
+
}
|
|
532
|
+
})
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
## CSS Custom Properties
|
|
536
|
+
|
|
537
|
+
The library uses CSS custom properties for theming. Make sure to import the CSS file first, then you can override these properties:
|
|
538
|
+
|
|
539
|
+
```tsx
|
|
540
|
+
// First, import the CSS file
|
|
541
|
+
import 'topiray-auth-react/dist/topiray-auth-react.css'
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
```css
|
|
545
|
+
/* Then override custom properties in your CSS */
|
|
546
|
+
:root {
|
|
547
|
+
--topiray-color-primary: #your-brand-color;
|
|
548
|
+
--topiray-color-surface: #your-surface-color;
|
|
549
|
+
--topiray-font-family: 'Your Font', sans-serif;
|
|
550
|
+
--topiray-radius-md: 12px;
|
|
551
|
+
--topiray-spacing-lg: 24px;
|
|
552
|
+
}
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
## Integration Patterns
|
|
556
|
+
|
|
557
|
+
### With React Router
|
|
558
|
+
|
|
559
|
+
```tsx
|
|
560
|
+
import { BrowserRouter, Routes, Route } from 'react-router-dom'
|
|
561
|
+
|
|
562
|
+
// Import the CSS file once at the app level
|
|
563
|
+
import 'topiray-auth-react/dist/topiray-auth-react.css'
|
|
564
|
+
|
|
565
|
+
function App() {
|
|
566
|
+
return (
|
|
567
|
+
<ThemeProvider theme={defaultTheme}>
|
|
568
|
+
<BrowserRouter>
|
|
569
|
+
<Routes>
|
|
570
|
+
<Route path="/signin" element={<SignInPage />} />
|
|
571
|
+
<Route path="/signup" element={<SignUpPage />} />
|
|
572
|
+
<Route path="/forgot-password" element={<ForgotPasswordPage />} />
|
|
573
|
+
<Route path="/verify-email" element={<VerifyEmailPage />} />
|
|
574
|
+
<Route path="/2fa/setup" element={<TwoFactorSetupPage />} />
|
|
575
|
+
<Route path="/2fa/verify" element={<TwoFactorVerifyPage />} />
|
|
576
|
+
<Route path="/2fa/complete" element={<TwoFactorCompletePage />} />
|
|
577
|
+
</Routes>
|
|
578
|
+
</BrowserRouter>
|
|
579
|
+
</ThemeProvider>
|
|
580
|
+
)
|
|
581
|
+
}
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### With State Management
|
|
585
|
+
|
|
586
|
+
```tsx
|
|
587
|
+
// Using React Context
|
|
588
|
+
const AuthContext = createContext()
|
|
589
|
+
|
|
590
|
+
function AuthProvider({ children }) {
|
|
591
|
+
const [user, setUser] = useState(null)
|
|
592
|
+
const [isLoading, setIsLoading] = useState(false)
|
|
593
|
+
|
|
594
|
+
const login = async (email, password) => {
|
|
595
|
+
setIsLoading(true)
|
|
596
|
+
try {
|
|
597
|
+
const result = await signInAPI(email, password)
|
|
598
|
+
setUser(result.user)
|
|
599
|
+
return result
|
|
600
|
+
} finally {
|
|
601
|
+
setIsLoading(false)
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
return (
|
|
606
|
+
<AuthContext.Provider value={{ user, isLoading, login }}>
|
|
607
|
+
{children}
|
|
608
|
+
</AuthContext.Provider>
|
|
609
|
+
)
|
|
610
|
+
}
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### With Form Validation
|
|
614
|
+
|
|
615
|
+
```tsx
|
|
616
|
+
import { z } from 'zod'
|
|
617
|
+
|
|
618
|
+
const signInSchema = z.object({
|
|
619
|
+
email: z.string().email('Invalid email address'),
|
|
620
|
+
password: z.string().min(8, 'Password must be at least 8 characters')
|
|
621
|
+
})
|
|
622
|
+
|
|
623
|
+
function SignInPage() {
|
|
624
|
+
const [errors, setErrors] = useState({})
|
|
625
|
+
|
|
626
|
+
const handleSignIn = (email, password) => {
|
|
627
|
+
try {
|
|
628
|
+
signInSchema.parse({ email, password })
|
|
629
|
+
setErrors({})
|
|
630
|
+
// Proceed with sign in
|
|
631
|
+
} catch (error) {
|
|
632
|
+
setErrors(error.flatten().fieldErrors)
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
return (
|
|
637
|
+
<SignInForm
|
|
638
|
+
onSubmit={handleSignIn}
|
|
639
|
+
// Pass validation errors to form
|
|
640
|
+
/>
|
|
641
|
+
)
|
|
642
|
+
}
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
## TypeScript Support
|
|
646
|
+
|
|
647
|
+
Full TypeScript support with comprehensive type definitions:
|
|
648
|
+
|
|
649
|
+
```tsx
|
|
650
|
+
import type {
|
|
651
|
+
ThemeConfig,
|
|
652
|
+
SignInFormProps,
|
|
653
|
+
AuthCardProps
|
|
654
|
+
} from 'topiray-auth-react'
|
|
655
|
+
|
|
656
|
+
// Custom theme with full type safety
|
|
657
|
+
const myTheme: ThemeConfig = {
|
|
658
|
+
colors: {
|
|
659
|
+
primary: '#0066cc',
|
|
660
|
+
// ... TypeScript will validate all required properties
|
|
661
|
+
},
|
|
662
|
+
// ... rest of theme configuration
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// Component props are fully typed
|
|
666
|
+
const handleSignIn: SignInFormProps['onSubmit'] = (email, password) => {
|
|
667
|
+
// email and password are properly typed as strings
|
|
668
|
+
}
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
## Accessibility Features
|
|
672
|
+
|
|
673
|
+
- **Keyboard Navigation**: Full keyboard support for all interactive elements
|
|
674
|
+
- **Screen Reader Support**: Proper ARIA labels and descriptions
|
|
675
|
+
- **Focus Management**: Logical focus flow and focus trapping in modals
|
|
676
|
+
- **High Contrast**: Colors meet WCAG contrast requirements
|
|
677
|
+
- **Reduced Motion**: Respects user's motion preferences
|
|
678
|
+
|
|
679
|
+
## Browser Support
|
|
680
|
+
|
|
681
|
+
- Chrome 90+
|
|
682
|
+
- Firefox 88+
|
|
683
|
+
- Safari 14+
|
|
684
|
+
- Edge 90+
|
|
685
|
+
|
|
686
|
+
## Contributing
|
|
687
|
+
|
|
688
|
+
1. Fork the repository
|
|
689
|
+
2. Create a feature branch
|
|
690
|
+
3. Make your changes
|
|
691
|
+
4. Add tests for new functionality
|
|
692
|
+
5. Submit a pull request
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
## Support
|
|
696
|
+
|
|
697
|
+
For questions and support:
|
|
698
|
+
- Create an issue on GitHub
|
|
699
|
+
- Check the documentation
|
|
700
|
+
- Review the demo application
|
|
701
|
+
|
|
702
|
+
---
|
|
703
|
+
|
|
704
|
+
Built with ❤️ for the React community
|