@insforge/react 0.1.7 → 0.2.1
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 +286 -570
- package/dist/atoms.js +5 -5
- package/dist/atoms.js.map +1 -1
- package/dist/atoms.mjs +5 -5
- package/dist/atoms.mjs.map +1 -1
- package/dist/components.js +413 -219
- package/dist/components.js.map +1 -1
- package/dist/components.mjs +413 -219
- package/dist/components.mjs.map +1 -1
- package/dist/forms.js +413 -219
- package/dist/forms.js.map +1 -1
- package/dist/forms.mjs +413 -219
- package/dist/forms.mjs.map +1 -1
- package/dist/hooks.d.mts +2 -2
- package/dist/hooks.d.ts +2 -2
- package/dist/hooks.js.map +1 -1
- package/dist/hooks.mjs.map +1 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +471 -220
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +471 -221
- package/dist/index.mjs.map +1 -1
- package/dist/router.d.mts +105 -0
- package/dist/router.d.ts +105 -0
- package/dist/router.js +140 -0
- package/dist/router.js.map +1 -0
- package/dist/router.mjs +138 -0
- package/dist/router.mjs.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/types.d.mts +257 -39
- package/dist/types.d.ts +257 -39
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
# @insforge/react
|
|
2
2
|
|
|
3
|
-
**Complete authentication solution for React applications.**
|
|
3
|
+
**Complete authentication solution for React applications.** Production-ready components with full business logic included.
|
|
4
4
|
|
|
5
5
|
## Why @insforge/react?
|
|
6
6
|
|
|
7
|
-
✅ **
|
|
8
|
-
✅ **
|
|
9
|
-
✅ **
|
|
7
|
+
✅ **5-Minute Setup** - One provider + one line of router config = done
|
|
8
|
+
✅ **Built-in Auth UI** - Use deployed auth pages (like Next.js middleware)
|
|
9
|
+
✅ **Framework Agnostic** - Works with any React framework
|
|
10
10
|
✅ **Full TypeScript** - Complete type safety out of the box
|
|
11
|
-
✅ **Customizable** -
|
|
11
|
+
✅ **Fully Customizable** - Deep styling control when you need it
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
Get authentication working in your React app in 5 minutes.
|
|
18
|
+
|
|
19
|
+
### 1. Install
|
|
16
20
|
|
|
17
21
|
```bash
|
|
18
22
|
npm install @insforge/react
|
|
@@ -22,443 +26,328 @@ yarn add @insforge/react
|
|
|
22
26
|
pnpm add @insforge/react
|
|
23
27
|
```
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## Quick Start
|
|
29
|
+
### 2. Setup Provider
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Wrap your app with `InsforgeProvider` in the root:
|
|
31
|
+
Wrap your app with `InsforgeProvider`:
|
|
34
32
|
|
|
35
33
|
```tsx
|
|
36
|
-
//
|
|
34
|
+
// src/main.tsx (Vite) or src/index.tsx (CRA)
|
|
35
|
+
import { StrictMode } from 'react';
|
|
36
|
+
import { createRoot } from 'react-dom/client';
|
|
37
37
|
import { InsforgeProvider } from '@insforge/react';
|
|
38
38
|
import '@insforge/react/styles.css';
|
|
39
|
+
import App from './App';
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
createRoot(document.getElementById('root')!).render(
|
|
42
|
+
<StrictMode>
|
|
42
43
|
<InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}>
|
|
43
|
-
|
|
44
|
+
<App />
|
|
44
45
|
</InsforgeProvider>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
```tsx
|
|
50
|
-
// Next.js App Router
|
|
51
|
-
'use client';
|
|
52
|
-
import { InsforgeProvider } from '@insforge/react';
|
|
53
|
-
import '@insforge/react/styles.css';
|
|
54
|
-
|
|
55
|
-
export default function RootLayout({ children }) {
|
|
56
|
-
return (
|
|
57
|
-
<html>
|
|
58
|
-
<body>
|
|
59
|
-
<InsforgeProvider baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL}>
|
|
60
|
-
{children}
|
|
61
|
-
</InsforgeProvider>
|
|
62
|
-
</body>
|
|
63
|
-
</html>
|
|
64
|
-
);
|
|
65
|
-
}
|
|
46
|
+
</StrictMode>
|
|
47
|
+
);
|
|
66
48
|
```
|
|
67
49
|
|
|
68
|
-
|
|
69
|
-
- `baseUrl` (required): Your Insforge backend URL
|
|
70
|
-
- `onAuthChange` (optional): Callback when auth state changes
|
|
71
|
-
- `syncTokenToCookie` (optional): Custom function to sync token to cookies (for Next.js SSR)
|
|
72
|
-
- `clearCookie` (optional): Custom function to clear cookie on sign out
|
|
73
|
-
|
|
74
|
-
### 2. Use Pre-built Components
|
|
75
|
-
|
|
76
|
-
The easiest way to add authentication:
|
|
50
|
+
### 3. Configure Router (Built-in Auth)
|
|
77
51
|
|
|
78
52
|
```tsx
|
|
79
|
-
|
|
80
|
-
import {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
)
|
|
92
|
-
|
|
53
|
+
// src/App.tsx
|
|
54
|
+
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
|
55
|
+
import { getInsforgeRoutes } from '@insforge/react/router';
|
|
56
|
+
import Home from './pages/Home';
|
|
57
|
+
import Dashboard from './pages/Dashboard';
|
|
58
|
+
|
|
59
|
+
const router = createBrowserRouter([
|
|
60
|
+
{ path: '/', element: <Home /> },
|
|
61
|
+
|
|
62
|
+
...getInsforgeRoutes({
|
|
63
|
+
baseUrl: import.meta.env.VITE_INSFORGE_BASE_URL,
|
|
64
|
+
builtInAuth: true
|
|
65
|
+
}),
|
|
66
|
+
|
|
67
|
+
{ path: '/dashboard', element: <Dashboard /> }
|
|
68
|
+
]);
|
|
93
69
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return (
|
|
97
|
-
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
|
98
|
-
<SignUp
|
|
99
|
-
afterSignUpUrl="/dashboard"
|
|
100
|
-
signInUrl="/sign-in"
|
|
101
|
-
/>
|
|
102
|
-
</div>
|
|
103
|
-
);
|
|
70
|
+
export default function App() {
|
|
71
|
+
return <RouterProvider router={router} />;
|
|
104
72
|
}
|
|
105
73
|
```
|
|
106
74
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
```tsx
|
|
112
|
-
'use client'; // for Next.js
|
|
113
|
-
import { InsforgeCallback } from '@insforge/react';
|
|
114
|
-
|
|
115
|
-
export default function CallbackPage() {
|
|
116
|
-
return <InsforgeCallback />;
|
|
117
|
-
}
|
|
118
|
-
```
|
|
75
|
+
**What this does:**
|
|
76
|
+
- Visiting `/sign-in` → Redirects to `your-project.insforge.app/auth/sign-in`
|
|
77
|
+
- Visiting `/sign-up` → Redirects to `your-project.insforge.app/auth/sign-up`
|
|
78
|
+
- After auth → Redirects back to `/auth/callback` → Goes to dashboard
|
|
119
79
|
|
|
120
|
-
### 4.
|
|
80
|
+
### 4. Add Auth UI to Your Pages
|
|
121
81
|
|
|
122
82
|
```tsx
|
|
123
|
-
|
|
124
|
-
import { SignedIn, SignedOut, UserButton
|
|
83
|
+
// src/pages/Home.tsx
|
|
84
|
+
import { SignedIn, SignedOut, UserButton } from '@insforge/react';
|
|
125
85
|
|
|
126
86
|
export default function Home() {
|
|
127
|
-
const { isSignedIn } = useAuth();
|
|
128
|
-
const { user } = useUser();
|
|
129
|
-
|
|
130
87
|
return (
|
|
131
88
|
<div>
|
|
132
|
-
<
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
<
|
|
138
|
-
|
|
139
|
-
|
|
89
|
+
<nav>
|
|
90
|
+
<SignedOut>
|
|
91
|
+
<a href="/sign-in">Sign In</a>
|
|
92
|
+
</SignedOut>
|
|
93
|
+
|
|
94
|
+
<SignedIn>
|
|
95
|
+
<UserButton afterSignOutUrl="/" />
|
|
96
|
+
</SignedIn>
|
|
97
|
+
</nav>
|
|
98
|
+
|
|
99
|
+
<h1>Welcome to My App!</h1>
|
|
140
100
|
</div>
|
|
141
101
|
);
|
|
142
102
|
}
|
|
143
103
|
```
|
|
144
104
|
|
|
145
|
-
**That's it!** 🎉
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## How It Works
|
|
150
|
-
|
|
151
|
-
```
|
|
152
|
-
1. User visits Sign In page → Renders <SignIn> component
|
|
153
|
-
↓
|
|
154
|
-
2. User enters credentials → Component calls SDK methods
|
|
155
|
-
↓
|
|
156
|
-
3. SDK communicates with backend → Returns auth token
|
|
157
|
-
↓
|
|
158
|
-
4. Provider updates auth state → Components re-render
|
|
159
|
-
↓
|
|
160
|
-
5. User sees authenticated UI → Redirect to dashboard
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
**Architecture:**
|
|
164
|
-
- **InsforgeProvider**: Manages authentication state globally
|
|
165
|
-
- **SDK Integration**: All auth operations go through `@insforge/sdk`
|
|
166
|
-
- **React Context**: Provides auth state to all child components
|
|
167
|
-
- **Hooks**: Easy access to auth methods and user data
|
|
105
|
+
**That's it!** 🎉 You now have production-ready authentication.
|
|
168
106
|
|
|
169
107
|
---
|
|
170
108
|
|
|
171
|
-
##
|
|
109
|
+
## Router Configuration Options
|
|
172
110
|
|
|
173
|
-
|
|
111
|
+
### Built-in Auth (Recommended)
|
|
174
112
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
Complete sign-in component with email/password and OAuth:
|
|
113
|
+
Uses your deployed Insforge auth pages:
|
|
178
114
|
|
|
179
115
|
```tsx
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
console.log('Signed in:', user);
|
|
193
|
-
}}
|
|
194
|
-
onError={(error) => {
|
|
195
|
-
console.error('Error:', error);
|
|
196
|
-
}}
|
|
197
|
-
onRedirect={(url) => navigate(url)}
|
|
198
|
-
// Customization
|
|
199
|
-
title="Welcome Back"
|
|
200
|
-
subtitle="Sign in to continue"
|
|
201
|
-
appearance={{
|
|
202
|
-
containerClassName: "shadow-xl",
|
|
203
|
-
buttonClassName: "bg-blue-600"
|
|
204
|
-
}}
|
|
205
|
-
/>
|
|
206
|
-
);
|
|
207
|
-
}
|
|
116
|
+
...getInsforgeRoutes({
|
|
117
|
+
baseUrl: 'https://your-project.insforge.app',
|
|
118
|
+
builtInAuth: true, // Default
|
|
119
|
+
paths: {
|
|
120
|
+
signIn: '/sign-in', // Custom path (optional)
|
|
121
|
+
signUp: '/sign-up',
|
|
122
|
+
verifyEmail: '/verify-email',
|
|
123
|
+
forgotPassword: '/forgot-password',
|
|
124
|
+
resetPassword: '/reset-password',
|
|
125
|
+
callback: '/auth/callback'
|
|
126
|
+
}
|
|
127
|
+
})
|
|
208
128
|
```
|
|
209
129
|
|
|
210
|
-
|
|
211
|
-
- Email/password authentication
|
|
212
|
-
- OAuth provider buttons (auto-detected from backend)
|
|
213
|
-
- Password visibility toggle
|
|
214
|
-
- Error handling
|
|
215
|
-
- Loading states
|
|
216
|
-
- Customizable text and styling
|
|
217
|
-
|
|
218
|
-
### `<SignUp />`
|
|
130
|
+
### Custom UI Components
|
|
219
131
|
|
|
220
|
-
|
|
132
|
+
Use package components with your own styling:
|
|
221
133
|
|
|
222
134
|
```tsx
|
|
223
|
-
import { SignUp } from '@insforge/react';
|
|
135
|
+
import { SignIn, SignUp } from '@insforge/react';
|
|
224
136
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
137
|
+
const router = createBrowserRouter([
|
|
138
|
+
{ path: '/', element: <Home /> },
|
|
139
|
+
|
|
140
|
+
// Still need callback route for OAuth
|
|
141
|
+
...getInsforgeRoutes({
|
|
142
|
+
baseUrl: import.meta.env.VITE_INSFORGE_BASE_URL,
|
|
143
|
+
builtInAuth: false // Don't redirect to deployed UI
|
|
144
|
+
}),
|
|
145
|
+
|
|
146
|
+
// Use package components
|
|
147
|
+
{ path: '/sign-in', element: <SignIn afterSignInUrl="/dashboard" /> },
|
|
148
|
+
{ path: '/sign-up', element: <SignUp afterSignUpUrl="/dashboard" /> }
|
|
149
|
+
]);
|
|
237
150
|
```
|
|
238
151
|
|
|
239
|
-
|
|
240
|
-
- Email/password registration
|
|
241
|
-
- Real-time password strength indicator
|
|
242
|
-
- OAuth provider buttons
|
|
243
|
-
- Form validation
|
|
244
|
-
- Customizable requirements
|
|
152
|
+
### Fully Custom UI
|
|
245
153
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
User profile dropdown with sign-out:
|
|
154
|
+
Build your own auth pages from scratch:
|
|
249
155
|
|
|
250
156
|
```tsx
|
|
251
|
-
import {
|
|
157
|
+
import { useAuth } from '@insforge/react';
|
|
252
158
|
|
|
253
|
-
function
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
buttonClassName: "hover:bg-gray-100",
|
|
264
|
-
nameClassName: "text-gray-900",
|
|
265
|
-
emailClassName: "text-gray-600"
|
|
266
|
-
}}
|
|
267
|
-
/>
|
|
268
|
-
</header>
|
|
269
|
-
);
|
|
159
|
+
function CustomSignIn() {
|
|
160
|
+
const { signIn } = useAuth();
|
|
161
|
+
|
|
162
|
+
const handleSubmit = async (e) => {
|
|
163
|
+
e.preventDefault();
|
|
164
|
+
await signIn(email, password);
|
|
165
|
+
navigate('/dashboard');
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
return <form onSubmit={handleSubmit}>...</form>;
|
|
270
169
|
}
|
|
271
170
|
```
|
|
272
171
|
|
|
273
|
-
|
|
274
|
-
- `detailed`: Shows avatar + name + email
|
|
275
|
-
- `simple`: Shows avatar only
|
|
276
|
-
|
|
277
|
-
### `<Protect />`
|
|
278
|
-
|
|
279
|
-
Protected content with conditional rendering:
|
|
280
|
-
|
|
281
|
-
```tsx
|
|
282
|
-
import { Protect } from '@insforge/react';
|
|
283
|
-
|
|
284
|
-
function Dashboard() {
|
|
285
|
-
return (
|
|
286
|
-
<div>
|
|
287
|
-
<h1>Dashboard</h1>
|
|
288
|
-
|
|
289
|
-
{/* Simple protection */}
|
|
290
|
-
<Protect redirectTo="/sign-in">
|
|
291
|
-
<UserContent />
|
|
292
|
-
</Protect>
|
|
293
|
-
|
|
294
|
-
{/* Role-based protection */}
|
|
295
|
-
<Protect
|
|
296
|
-
redirectTo="/unauthorized"
|
|
297
|
-
condition={(user) => user.role === 'admin'}
|
|
298
|
-
>
|
|
299
|
-
<AdminPanel />
|
|
300
|
-
</Protect>
|
|
301
|
-
</div>
|
|
302
|
-
);
|
|
303
|
-
}
|
|
304
|
-
```
|
|
172
|
+
---
|
|
305
173
|
|
|
306
|
-
|
|
174
|
+
## Core Features
|
|
307
175
|
|
|
308
|
-
|
|
176
|
+
### Components
|
|
309
177
|
|
|
310
|
-
|
|
311
|
-
|
|
178
|
+
**Pre-built with Business Logic:**
|
|
179
|
+
- `<SignIn />` - Complete sign-in with email/password & OAuth
|
|
180
|
+
- `<SignUp />` - Registration with password validation
|
|
181
|
+
- `<UserButton />` - User dropdown with sign-out
|
|
182
|
+
- `<Protect />` - Route protection wrapper
|
|
183
|
+
- `<SignedIn>` / `<SignedOut>` - Conditional rendering
|
|
184
|
+
- `<InsforgeCallback />` - OAuth callback handler
|
|
312
185
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
</SignedOut>
|
|
320
|
-
|
|
321
|
-
<SignedIn>
|
|
322
|
-
<a href="/dashboard">Dashboard</a>
|
|
323
|
-
<UserButton />
|
|
324
|
-
</SignedIn>
|
|
325
|
-
</nav>
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
```
|
|
186
|
+
**Form Components (Pure UI):**
|
|
187
|
+
- `<SignInForm />` - Sign-in UI without logic
|
|
188
|
+
- `<SignUpForm />` - Sign-up UI without logic
|
|
189
|
+
- `<ForgotPasswordForm />` - Password reset request
|
|
190
|
+
- `<ResetPasswordForm />` - Password reset with token
|
|
191
|
+
- `<VerifyEmailStatus />` - Email verification status
|
|
329
192
|
|
|
330
|
-
|
|
193
|
+
**Atomic Components (13 total):**
|
|
194
|
+
- `<AuthContainer />`, `<AuthHeader />`, `<AuthFormField />`, `<AuthPasswordField />`, etc.
|
|
331
195
|
|
|
332
|
-
|
|
196
|
+
### Hooks
|
|
333
197
|
|
|
334
198
|
```tsx
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
export default function CallbackPage() {
|
|
339
|
-
return <InsforgeCallback redirectTo="/dashboard" />;
|
|
340
|
-
}
|
|
199
|
+
const { signIn, signUp, signOut, isSignedIn, isLoaded } = useAuth();
|
|
200
|
+
const { user, updateUser, isLoaded } = useUser();
|
|
201
|
+
const { oauthProviders, emailConfig, isLoaded } = usePublicAuthConfig();
|
|
341
202
|
```
|
|
342
203
|
|
|
343
204
|
---
|
|
344
205
|
|
|
345
|
-
##
|
|
206
|
+
## Customization
|
|
346
207
|
|
|
347
|
-
###
|
|
208
|
+
### Basic Styling
|
|
348
209
|
|
|
349
|
-
|
|
210
|
+
All components support `appearance` props:
|
|
350
211
|
|
|
351
212
|
```tsx
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
await signIn('user@example.com', 'password');
|
|
360
|
-
// Redirect or update UI
|
|
361
|
-
} catch (error) {
|
|
362
|
-
console.error('Sign in failed:', error);
|
|
363
|
-
}
|
|
364
|
-
};
|
|
365
|
-
|
|
366
|
-
if (!isLoaded) return <div>Loading...</div>;
|
|
367
|
-
|
|
368
|
-
return (
|
|
369
|
-
<button onClick={isSignedIn ? signOut : handleSignIn}>
|
|
370
|
-
{isSignedIn ? 'Sign Out' : 'Sign In'}
|
|
371
|
-
</button>
|
|
372
|
-
);
|
|
373
|
-
}
|
|
213
|
+
<SignIn
|
|
214
|
+
appearance={{
|
|
215
|
+
container: "max-w-lg",
|
|
216
|
+
card: "bg-white shadow-2xl",
|
|
217
|
+
button: "bg-blue-600 hover:bg-blue-700"
|
|
218
|
+
}}
|
|
219
|
+
/>
|
|
374
220
|
```
|
|
375
221
|
|
|
376
|
-
|
|
377
|
-
- `signIn(email, password)` - Sign in with email/password
|
|
378
|
-
- `signUp(email, password)` - Sign up new user
|
|
379
|
-
- `signOut()` - Sign out current user
|
|
380
|
-
- `isSignedIn` - Boolean auth state
|
|
381
|
-
- `isLoaded` - Boolean loading state
|
|
222
|
+
### Deep Customization (Hierarchical Appearance)
|
|
382
223
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
Access user data:
|
|
224
|
+
Style nested components through hierarchical structure:
|
|
386
225
|
|
|
387
226
|
```tsx
|
|
388
|
-
|
|
227
|
+
<SignIn
|
|
228
|
+
appearance={{
|
|
229
|
+
card: "bg-gradient-to-br from-blue-50 to-white shadow-2xl",
|
|
230
|
+
header: {
|
|
231
|
+
title: "text-3xl font-bold text-purple-900",
|
|
232
|
+
subtitle: "text-purple-600"
|
|
233
|
+
},
|
|
234
|
+
form: {
|
|
235
|
+
emailField: {
|
|
236
|
+
label: "text-gray-800 font-semibold",
|
|
237
|
+
input: "border-purple-300 focus:border-purple-500 rounded-lg"
|
|
238
|
+
},
|
|
239
|
+
passwordField: {
|
|
240
|
+
input: "border-purple-300 focus:border-purple-500 rounded-lg",
|
|
241
|
+
forgotPasswordLink: "text-purple-600 hover:text-purple-800"
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
button: "bg-purple-600 hover:bg-purple-700 rounded-lg h-12",
|
|
245
|
+
link: {
|
|
246
|
+
text: "text-gray-600",
|
|
247
|
+
link: "text-purple-600 hover:text-purple-800 font-semibold"
|
|
248
|
+
},
|
|
249
|
+
oauth: {
|
|
250
|
+
button: "border-2 hover:bg-gray-50 rounded-xl"
|
|
251
|
+
}
|
|
252
|
+
}}
|
|
253
|
+
/>
|
|
254
|
+
```
|
|
389
255
|
|
|
390
|
-
|
|
391
|
-
const { user, isLoaded, updateUser } = useUser();
|
|
256
|
+
#### Complete Appearance Structure
|
|
392
257
|
|
|
393
|
-
|
|
394
|
-
if (!user) return <div>Not signed in</div>;
|
|
258
|
+
**SignIn / SignUp Components:**
|
|
395
259
|
|
|
396
|
-
|
|
397
|
-
|
|
260
|
+
```typescript
|
|
261
|
+
appearance?: {
|
|
262
|
+
container?: string; // Outermost wrapper
|
|
263
|
+
card?: string; // Inner card box
|
|
264
|
+
header?: {
|
|
265
|
+
container?: string; // Header wrapper
|
|
266
|
+
title?: string; // Title text
|
|
267
|
+
subtitle?: string; // Subtitle text
|
|
268
|
+
};
|
|
269
|
+
errorBanner?: string; // Error message banner
|
|
270
|
+
form?: {
|
|
271
|
+
container?: string; // Form wrapper
|
|
272
|
+
emailField?: {
|
|
273
|
+
container?: string; // Email field wrapper
|
|
274
|
+
label?: string; // Email label
|
|
275
|
+
input?: string; // Email input
|
|
276
|
+
};
|
|
277
|
+
passwordField?: {
|
|
278
|
+
container?: string; // Password field wrapper
|
|
279
|
+
label?: string; // Password label
|
|
280
|
+
input?: string; // Password input
|
|
281
|
+
forgotPasswordLink?: string; // Forgot password link (SignIn only)
|
|
282
|
+
strengthIndicator?: { // Password strength (SignUp only)
|
|
283
|
+
container?: string;
|
|
284
|
+
requirement?: string;
|
|
285
|
+
};
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
button?: string; // Submit button
|
|
289
|
+
link?: {
|
|
290
|
+
container?: string; // Link section wrapper
|
|
291
|
+
text?: string; // Link description text
|
|
292
|
+
link?: string; // Actual link element
|
|
293
|
+
};
|
|
294
|
+
divider?: string; // "or" divider
|
|
295
|
+
oauth?: {
|
|
296
|
+
container?: string; // OAuth buttons wrapper
|
|
297
|
+
button?: string; // Individual OAuth button
|
|
398
298
|
};
|
|
399
|
-
|
|
400
|
-
return (
|
|
401
|
-
<div>
|
|
402
|
-
<p>Email: {user.email}</p>
|
|
403
|
-
<p>Name: {user.name}</p>
|
|
404
|
-
<img src={user.avatarUrl} alt="Avatar" />
|
|
405
|
-
<button onClick={handleUpdate}>Update Name</button>
|
|
406
|
-
</div>
|
|
407
|
-
);
|
|
408
299
|
}
|
|
409
300
|
```
|
|
410
301
|
|
|
411
|
-
|
|
412
|
-
- `user` - User object with id, email, name, avatarUrl
|
|
413
|
-
- `isLoaded` - Boolean loading state
|
|
414
|
-
- `updateUser(data)` - Update user profile
|
|
415
|
-
- `setUser(user)` - Manually set user state
|
|
416
|
-
|
|
417
|
-
### `usePublicAuthConfig()`
|
|
302
|
+
### Text Customization
|
|
418
303
|
|
|
419
|
-
|
|
304
|
+
All text is customizable:
|
|
420
305
|
|
|
421
306
|
```tsx
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
);
|
|
435
|
-
}
|
|
307
|
+
<SignIn
|
|
308
|
+
title="Welcome Back!"
|
|
309
|
+
subtitle="We're happy to see you again"
|
|
310
|
+
emailLabel="Your Email Address"
|
|
311
|
+
emailPlaceholder="you@company.com"
|
|
312
|
+
passwordLabel="Your Password"
|
|
313
|
+
submitButtonText="Login Now"
|
|
314
|
+
loadingButtonText="Signing you in..."
|
|
315
|
+
signUpText="New to our platform?"
|
|
316
|
+
signUpLinkText="Create an account"
|
|
317
|
+
dividerText="or continue with"
|
|
318
|
+
/>
|
|
436
319
|
```
|
|
437
320
|
|
|
438
|
-
**⚠️ Important:** Only use this hook in SignIn/SignUp components to avoid unnecessary API calls.
|
|
439
|
-
|
|
440
321
|
---
|
|
441
322
|
|
|
442
|
-
##
|
|
443
|
-
|
|
444
|
-
Build custom auth flows with pre-built forms:
|
|
323
|
+
## Advanced Usage
|
|
445
324
|
|
|
446
|
-
###
|
|
325
|
+
### Complete Component with Custom Logic
|
|
447
326
|
|
|
448
327
|
```tsx
|
|
449
|
-
import { SignInForm } from '@insforge/react';
|
|
328
|
+
import { SignInForm, useAuth } from '@insforge/react';
|
|
450
329
|
import { useState } from 'react';
|
|
451
330
|
|
|
452
331
|
function CustomSignIn() {
|
|
332
|
+
const { signIn } = useAuth();
|
|
453
333
|
const [email, setEmail] = useState('');
|
|
454
334
|
const [password, setPassword] = useState('');
|
|
455
335
|
const [error, setError] = useState('');
|
|
456
336
|
const [loading, setLoading] = useState(false);
|
|
457
337
|
|
|
458
|
-
const handleSubmit = async (e) => {
|
|
338
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
459
339
|
e.preventDefault();
|
|
460
340
|
setLoading(true);
|
|
461
|
-
|
|
341
|
+
setError('');
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
await signIn(email, password);
|
|
345
|
+
// Custom success logic
|
|
346
|
+
} catch (err) {
|
|
347
|
+
setError(err.message);
|
|
348
|
+
} finally {
|
|
349
|
+
setLoading(false);
|
|
350
|
+
}
|
|
462
351
|
};
|
|
463
352
|
|
|
464
353
|
return (
|
|
@@ -471,23 +360,15 @@ function CustomSignIn() {
|
|
|
471
360
|
error={error}
|
|
472
361
|
loading={loading}
|
|
473
362
|
availableProviders={['google', 'github']}
|
|
474
|
-
onOAuthClick={(provider) =>
|
|
363
|
+
onOAuthClick={(provider) => {
|
|
364
|
+
// Custom OAuth logic
|
|
365
|
+
}}
|
|
475
366
|
/>
|
|
476
367
|
);
|
|
477
368
|
}
|
|
478
369
|
```
|
|
479
370
|
|
|
480
|
-
|
|
481
|
-
- `<SignUpForm />` - Sign up with password strength
|
|
482
|
-
- `<ForgotPasswordForm />` - Request password reset
|
|
483
|
-
- `<ResetPasswordForm />` - Reset password with token
|
|
484
|
-
- `<VerifyEmailStatus />` - Email verification status
|
|
485
|
-
|
|
486
|
-
---
|
|
487
|
-
|
|
488
|
-
## Atomic Components (Maximum Flexibility)
|
|
489
|
-
|
|
490
|
-
Build completely custom UIs:
|
|
371
|
+
### Build from Atomic Components
|
|
491
372
|
|
|
492
373
|
```tsx
|
|
493
374
|
import {
|
|
@@ -564,143 +445,29 @@ function CompletelyCustomAuth() {
|
|
|
564
445
|
}
|
|
565
446
|
```
|
|
566
447
|
|
|
567
|
-
|
|
568
|
-
- `AuthContainer` - Main wrapper with branding
|
|
569
|
-
- `AuthHeader` - Title and subtitle
|
|
570
|
-
- `AuthErrorBanner` - Error messages
|
|
571
|
-
- `AuthFormField` - Standard input
|
|
572
|
-
- `AuthPasswordField` - Password with toggle
|
|
573
|
-
- `AuthPasswordStrengthIndicator` - Password checklist
|
|
574
|
-
- `AuthSubmitButton` - Loading button
|
|
575
|
-
- `AuthLink` - Navigation link
|
|
576
|
-
- `AuthDivider` - Visual separator
|
|
577
|
-
- `AuthOAuthButton` - Single OAuth button
|
|
578
|
-
- `AuthOAuthProviders` - OAuth grid
|
|
579
|
-
- `AuthVerificationCodeInput` - 6-digit OTP
|
|
580
|
-
- `AuthBranding` - Insforge branding
|
|
581
|
-
|
|
582
|
-
---
|
|
583
|
-
|
|
584
|
-
## Customization
|
|
585
|
-
|
|
586
|
-
### Appearance Props
|
|
587
|
-
|
|
588
|
-
All components support Tailwind className overrides:
|
|
589
|
-
|
|
590
|
-
```tsx
|
|
591
|
-
<SignIn
|
|
592
|
-
appearance={{
|
|
593
|
-
containerClassName: "shadow-2xl max-w-lg",
|
|
594
|
-
cardClassName: "bg-gradient-to-br from-blue-50 to-white",
|
|
595
|
-
formClassName: "space-y-6",
|
|
596
|
-
buttonClassName: "bg-blue-600 hover:bg-blue-700 h-12"
|
|
597
|
-
}}
|
|
598
|
-
/>
|
|
599
|
-
|
|
600
|
-
<UserButton
|
|
601
|
-
appearance={{
|
|
602
|
-
buttonClassName: "hover:bg-gray-100 rounded-full",
|
|
603
|
-
nameClassName: "text-gray-900 font-semibold",
|
|
604
|
-
emailClassName: "text-gray-500",
|
|
605
|
-
dropdownClassName: "shadow-xl"
|
|
606
|
-
}}
|
|
607
|
-
/>
|
|
608
|
-
```
|
|
609
|
-
|
|
610
|
-
### Text Customization
|
|
611
|
-
|
|
612
|
-
All text is customizable:
|
|
613
|
-
|
|
614
|
-
```tsx
|
|
615
|
-
<SignIn
|
|
616
|
-
title="Welcome Back!"
|
|
617
|
-
subtitle="We're happy to see you again"
|
|
618
|
-
emailLabel="Your Email Address"
|
|
619
|
-
emailPlaceholder="you@company.com"
|
|
620
|
-
passwordLabel="Your Password"
|
|
621
|
-
submitButtonText="Login Now"
|
|
622
|
-
loadingButtonText="Signing you in..."
|
|
623
|
-
signUpText="New to our platform?"
|
|
624
|
-
signUpLinkText="Create an account"
|
|
625
|
-
dividerText="or continue with"
|
|
626
|
-
/>
|
|
627
|
-
```
|
|
628
|
-
|
|
629
|
-
---
|
|
630
|
-
|
|
631
|
-
## Framework Integration
|
|
632
|
-
|
|
633
|
-
### Next.js (App Router)
|
|
448
|
+
### Route Protection
|
|
634
449
|
|
|
635
450
|
```tsx
|
|
636
|
-
|
|
637
|
-
'use client';
|
|
638
|
-
import { InsforgeProvider } from '@insforge/react';
|
|
639
|
-
import '@insforge/react/styles.css';
|
|
451
|
+
import { Protect } from '@insforge/react';
|
|
640
452
|
|
|
641
|
-
|
|
453
|
+
function Dashboard() {
|
|
642
454
|
return (
|
|
643
|
-
<
|
|
644
|
-
<
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
body: JSON.stringify({ token })
|
|
651
|
-
});
|
|
652
|
-
return true;
|
|
653
|
-
}}
|
|
654
|
-
clearCookie={async () => {
|
|
655
|
-
await fetch('/api/auth', { method: 'DELETE' });
|
|
656
|
-
}}
|
|
657
|
-
>
|
|
658
|
-
{children}
|
|
659
|
-
</InsforgeProvider>
|
|
660
|
-
</body>
|
|
661
|
-
</html>
|
|
662
|
-
);
|
|
663
|
-
}
|
|
664
|
-
```
|
|
665
|
-
|
|
666
|
-
### Vite / React
|
|
667
|
-
|
|
668
|
-
```tsx
|
|
669
|
-
// src/main.tsx
|
|
670
|
-
import { StrictMode } from 'react';
|
|
671
|
-
import { createRoot } from 'react-dom/client';
|
|
672
|
-
import { BrowserRouter } from 'react-router-dom';
|
|
673
|
-
import { InsforgeProvider } from '@insforge/react';
|
|
674
|
-
import '@insforge/react/styles.css';
|
|
675
|
-
import App from './App';
|
|
676
|
-
|
|
677
|
-
createRoot(document.getElementById('root')!).render(
|
|
678
|
-
<StrictMode>
|
|
679
|
-
<BrowserRouter>
|
|
680
|
-
<InsforgeProvider baseUrl={import.meta.env.VITE_INSFORGE_BASE_URL}>
|
|
681
|
-
<App />
|
|
682
|
-
</InsforgeProvider>
|
|
683
|
-
</BrowserRouter>
|
|
684
|
-
</StrictMode>
|
|
685
|
-
);
|
|
686
|
-
```
|
|
687
|
-
|
|
688
|
-
### Remix
|
|
689
|
-
|
|
690
|
-
```tsx
|
|
691
|
-
// app/root.tsx
|
|
692
|
-
import { InsforgeProvider } from '@insforge/react';
|
|
693
|
-
import '@insforge/react/styles.css';
|
|
455
|
+
<div>
|
|
456
|
+
<h1>Dashboard</h1>
|
|
457
|
+
|
|
458
|
+
{/* Simple protection */}
|
|
459
|
+
<Protect redirectTo="/sign-in">
|
|
460
|
+
<UserContent />
|
|
461
|
+
</Protect>
|
|
694
462
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
</html>
|
|
463
|
+
{/* Role-based protection */}
|
|
464
|
+
<Protect
|
|
465
|
+
redirectTo="/unauthorized"
|
|
466
|
+
condition={(user) => user.role === 'admin'}
|
|
467
|
+
>
|
|
468
|
+
<AdminPanel />
|
|
469
|
+
</Protect>
|
|
470
|
+
</div>
|
|
704
471
|
);
|
|
705
472
|
}
|
|
706
473
|
```
|
|
@@ -716,6 +483,8 @@ import type {
|
|
|
716
483
|
InsforgeUser,
|
|
717
484
|
SignInProps,
|
|
718
485
|
SignUpProps,
|
|
486
|
+
SignInAppearance,
|
|
487
|
+
SignUpAppearance,
|
|
719
488
|
UserButtonProps,
|
|
720
489
|
ProtectProps,
|
|
721
490
|
ConditionalProps,
|
|
@@ -726,74 +495,12 @@ import type {
|
|
|
726
495
|
OAuthProvider,
|
|
727
496
|
EmailAuthConfig,
|
|
728
497
|
InsforgeProviderProps,
|
|
498
|
+
GetInsforgeRoutesConfig,
|
|
729
499
|
} from '@insforge/react';
|
|
730
500
|
```
|
|
731
501
|
|
|
732
502
|
---
|
|
733
503
|
|
|
734
|
-
## API Reference
|
|
735
|
-
|
|
736
|
-
### InsforgeProvider Props
|
|
737
|
-
|
|
738
|
-
```tsx
|
|
739
|
-
interface InsforgeProviderProps {
|
|
740
|
-
baseUrl: string; // Insforge backend URL
|
|
741
|
-
onAuthChange?: (user: InsforgeUser | null) => void; // Auth state callback
|
|
742
|
-
syncTokenToCookie?: (token: string) => Promise<boolean>; // Custom cookie sync
|
|
743
|
-
clearCookie?: () => Promise<void>; // Custom cookie clear
|
|
744
|
-
}
|
|
745
|
-
```
|
|
746
|
-
|
|
747
|
-
### SignIn / SignUp Props
|
|
748
|
-
|
|
749
|
-
```tsx
|
|
750
|
-
interface SignInProps {
|
|
751
|
-
afterSignInUrl?: string; // Redirect after sign in
|
|
752
|
-
signUpUrl?: string; // Link to sign up page
|
|
753
|
-
forgotPasswordUrl?: string; // Link to forgot password
|
|
754
|
-
onSuccess?: (user, token) => void; // Success callback
|
|
755
|
-
onError?: (error: Error) => void; // Error callback
|
|
756
|
-
onRedirect?: (url: string) => void; // Custom redirect handler
|
|
757
|
-
title?: string; // Custom title
|
|
758
|
-
subtitle?: string; // Custom subtitle
|
|
759
|
-
appearance?: { // Custom styling
|
|
760
|
-
containerClassName?: string;
|
|
761
|
-
cardClassName?: string;
|
|
762
|
-
formClassName?: string;
|
|
763
|
-
buttonClassName?: string;
|
|
764
|
-
};
|
|
765
|
-
// ... more text customization props
|
|
766
|
-
}
|
|
767
|
-
```
|
|
768
|
-
|
|
769
|
-
### InsforgeCallback Props
|
|
770
|
-
|
|
771
|
-
```tsx
|
|
772
|
-
interface InsforgeCallbackProps {
|
|
773
|
-
redirectTo?: string; // Custom redirect destination
|
|
774
|
-
onSuccess?: () => void; // Success callback
|
|
775
|
-
onError?: (error: string) => void; // Error callback
|
|
776
|
-
loadingComponent?: ReactNode; // Custom loading UI
|
|
777
|
-
onRedirect?: (url: string) => void; // Custom redirect handler
|
|
778
|
-
}
|
|
779
|
-
```
|
|
780
|
-
|
|
781
|
-
---
|
|
782
|
-
|
|
783
|
-
## Validation Utilities
|
|
784
|
-
|
|
785
|
-
```tsx
|
|
786
|
-
import { emailSchema, cn } from '@insforge/react';
|
|
787
|
-
|
|
788
|
-
// Validate email with Zod
|
|
789
|
-
const result = emailSchema.safeParse('user@example.com');
|
|
790
|
-
|
|
791
|
-
// Merge Tailwind classes
|
|
792
|
-
const className = cn('px-4 py-2', 'bg-blue-500', conditionalClass);
|
|
793
|
-
```
|
|
794
|
-
|
|
795
|
-
---
|
|
796
|
-
|
|
797
504
|
## OAuth Providers
|
|
798
505
|
|
|
799
506
|
Built-in support for 10+ OAuth providers:
|
|
@@ -813,28 +520,37 @@ Providers are auto-detected from your backend configuration.
|
|
|
813
520
|
|
|
814
521
|
---
|
|
815
522
|
|
|
816
|
-
##
|
|
523
|
+
## Validation Utilities
|
|
817
524
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
- 🔒 Production-ready security built-in
|
|
821
|
-
- 🎨 Customizable when needed, works out of the box
|
|
822
|
-
- 🚀 No framework lock-in
|
|
525
|
+
```tsx
|
|
526
|
+
import { emailSchema, cn } from '@insforge/react/lib';
|
|
823
527
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
- 🎯 Framework agnostic (works everywhere)
|
|
827
|
-
- 🤖 SDK-first approach (consistent API)
|
|
828
|
-
- 💰 Self-hosted (no vendor lock-in)
|
|
528
|
+
// Validate email with Zod
|
|
529
|
+
const result = emailSchema.safeParse('user@example.com');
|
|
829
530
|
|
|
830
|
-
|
|
531
|
+
// Merge Tailwind classes
|
|
532
|
+
const className = cn('px-4 py-2', 'bg-blue-500', conditionalClass);
|
|
533
|
+
```
|
|
831
534
|
|
|
832
|
-
|
|
535
|
+
---
|
|
833
536
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
-
|
|
837
|
-
|
|
537
|
+
## Available Atomic Components
|
|
538
|
+
|
|
539
|
+
Low-level building blocks for complete customization:
|
|
540
|
+
|
|
541
|
+
- `<AuthBranding />` - Insforge branding footer
|
|
542
|
+
- `<AuthContainer />` - Main container wrapper
|
|
543
|
+
- `<AuthHeader />` - Title and subtitle display
|
|
544
|
+
- `<AuthErrorBanner />` - Error message display
|
|
545
|
+
- `<AuthFormField />` - Standard input field
|
|
546
|
+
- `<AuthPasswordField />` - Password input with features
|
|
547
|
+
- `<AuthPasswordStrengthIndicator />` - Password checklist
|
|
548
|
+
- `<AuthSubmitButton />` - Submit button with states
|
|
549
|
+
- `<AuthLink />` - Call-to-action link
|
|
550
|
+
- `<AuthDivider />` - Visual separator
|
|
551
|
+
- `<AuthOAuthButton />` - Single OAuth provider button
|
|
552
|
+
- `<AuthOAuthProviders />` - Smart OAuth grid
|
|
553
|
+
- `<AuthVerificationCodeInput />` - 6-digit OTP input
|
|
838
554
|
|
|
839
555
|
---
|
|
840
556
|
|