@proveanything/smartlinks-auth-ui 0.1.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.
Files changed (48) hide show
  1. package/README.md +323 -0
  2. package/dist/api.d.ts +44 -0
  3. package/dist/api.d.ts.map +1 -0
  4. package/dist/api.js +105 -0
  5. package/dist/components/AuthContainer.d.ts +12 -0
  6. package/dist/components/AuthContainer.d.ts.map +1 -0
  7. package/dist/components/AuthContainer.js +46 -0
  8. package/dist/components/AuthUIPreview.d.ts +11 -0
  9. package/dist/components/AuthUIPreview.d.ts.map +1 -0
  10. package/dist/components/AuthUIPreview.js +10 -0
  11. package/dist/components/EmailAuthForm.d.ts +14 -0
  12. package/dist/components/EmailAuthForm.d.ts.map +1 -0
  13. package/dist/components/EmailAuthForm.js +20 -0
  14. package/dist/components/PasswordResetForm.d.ts +13 -0
  15. package/dist/components/PasswordResetForm.d.ts.map +1 -0
  16. package/dist/components/PasswordResetForm.js +37 -0
  17. package/dist/components/PhoneAuthForm.d.ts +11 -0
  18. package/dist/components/PhoneAuthForm.d.ts.map +1 -0
  19. package/dist/components/PhoneAuthForm.js +20 -0
  20. package/dist/components/ProtectedRoute.d.ts +9 -0
  21. package/dist/components/ProtectedRoute.d.ts.map +1 -0
  22. package/dist/components/ProtectedRoute.js +20 -0
  23. package/dist/components/ProviderButtons.d.ts +12 -0
  24. package/dist/components/ProviderButtons.d.ts.map +1 -0
  25. package/dist/components/ProviderButtons.js +8 -0
  26. package/dist/context/AuthContext.d.ts +20 -0
  27. package/dist/context/AuthContext.d.ts.map +1 -0
  28. package/dist/context/AuthContext.js +113 -0
  29. package/dist/index.css +2 -0
  30. package/dist/index.css.map +1 -0
  31. package/dist/index.d.ts +10 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.esm.css +2 -0
  34. package/dist/index.esm.css.map +1 -0
  35. package/dist/index.esm.js +840 -0
  36. package/dist/index.esm.js.map +1 -0
  37. package/dist/index.js +867 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/smartlinks.d.ts +65 -0
  40. package/dist/smartlinks.d.ts.map +1 -0
  41. package/dist/smartlinks.js +141 -0
  42. package/dist/types.d.ts +101 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +1 -0
  45. package/dist/utils/tokenStorage.d.ts +14 -0
  46. package/dist/utils/tokenStorage.d.ts.map +1 -0
  47. package/dist/utils/tokenStorage.js +71 -0
  48. package/package.json +57 -0
package/README.md ADDED
@@ -0,0 +1,323 @@
1
+ # @smartlinks/auth-ui
2
+
3
+ A lightweight, drop-in React authentication UI component library with bearer token support, session management, and multi-tenant account data. Provides a complete authentication solution without exposing backend implementation details to the frontend.
4
+
5
+ ## Features
6
+
7
+ - 🔐 **Multiple Auth Methods**: Email/Password, Google OAuth, SMS (Phone)
8
+ - 🎨 **Beautiful Pre-built UI**: Professional, responsive authentication flows
9
+ - 🪙 **Bearer Token Based**: Returns JWT tokens for seamless API authentication
10
+ - 🗂️ **Session Management**: Built-in AuthProvider, useAuth hook, and ProtectedRoute
11
+ - 🏢 **Multi-Tenant Support**: Client ID for identifying different systems/tenants
12
+ - 📊 **Account Data**: Store custom metadata per user account
13
+ - 🔗 **URL Flow Handling**: Email verification, password reset links
14
+ - ⚡ **Lightweight**: Minimal dependencies, no backend SDK required in consuming apps
15
+ - 📱 **Fully Responsive**: Works seamlessly on mobile and desktop
16
+ - ♿ **Accessible**: WCAG compliant authentication forms
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install @smartlinks/auth-ui
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ### Basic Usage with Session Management
27
+
28
+ ```tsx
29
+ import { SmartlinksAuthUI, AuthProvider, useAuth } from '@smartlinks/auth-ui';
30
+
31
+ function App() {
32
+ return (
33
+ <AuthProvider apiEndpoint="https://your-api.smartlinks.com" clientId="your-client-123">
34
+ <YourApp />
35
+ </AuthProvider>
36
+ );
37
+ }
38
+
39
+ function YourApp() {
40
+ const { user, token, accountData, isAuthenticated, logout } = useAuth();
41
+
42
+ if (isAuthenticated) {
43
+ return (
44
+ <div>
45
+ <h1>Welcome, {user.displayName}!</h1>
46
+ <p>Account: {accountData?.companyName}</p>
47
+ <button onClick={logout}>Logout</button>
48
+ </div>
49
+ );
50
+ }
51
+
52
+ return (
53
+ <SmartlinksAuthUI
54
+ apiEndpoint="https://your-api.smartlinks.com"
55
+ clientId="your-client-123" // REQUIRED - identifies your application
56
+ clientName="Acme Corp"
57
+ accountData={{
58
+ companyName: "Acme Corp",
59
+ plan: "pro"
60
+ }}
61
+ onAuthSuccess={(token, user, accountData) => {
62
+ console.log('Authenticated!', { token, user, accountData });
63
+ }}
64
+ enabledProviders={['email', 'google', 'phone']}
65
+ />
66
+ );
67
+ }
68
+ ```
69
+
70
+ ## Props
71
+
72
+ ### SmartlinksAuthUI
73
+
74
+ | Prop | Type | Required | Description |
75
+ |------|------|----------|-------------|
76
+ | `apiEndpoint` | string | Yes | Your Smartlinks API endpoint (e.g., `https://api.smartlinks.com`) |
77
+ | `clientId` | string | **Yes** | **REQUIRED** - Client identifier used in all API calls |
78
+ | `clientName` | string | No | Client name for branded emails |
79
+ | `accountData` | Record<string, any> | No | Custom metadata to store on registration |
80
+ | `onAuthSuccess` | (token: string, user: AuthUser, accountData?: Record<string, any>) => void | Yes | Callback when authentication succeeds |
81
+ | `onAuthError` | (error: Error) => void | No | Callback when authentication fails |
82
+ | `enabledProviders` | Array<'email' \| 'google' \| 'phone'> | No | Auth providers to enable (default: all) |
83
+ | `redirectUrl` | string | No | URL to redirect after auth (default: current page) |
84
+ | `theme` | 'light' \| 'dark' | No | UI theme (default: 'light') |
85
+
86
+ ## Session Management
87
+
88
+ ### AuthProvider
89
+
90
+ Wrap your app with AuthProvider to enable session management:
91
+
92
+ ```tsx
93
+ import { AuthProvider } from '@smartlinks/auth-ui';
94
+
95
+ <AuthProvider apiEndpoint="https://your-api.smartlinks.com/api/v1/authkit">
96
+ <App />
97
+ </AuthProvider>
98
+ ```
99
+
100
+ ### useAuth Hook
101
+
102
+ Access authentication state anywhere in your app:
103
+
104
+ ```tsx
105
+ import { useAuth } from '@smartlinks/auth-ui';
106
+
107
+ function MyComponent() {
108
+ const {
109
+ user, // Current user object
110
+ token, // Bearer token
111
+ accountData, // Custom account metadata
112
+ isAuthenticated, // Boolean auth status
113
+ isLoading, // Loading state
114
+ login, // Login function
115
+ logout, // Logout function
116
+ getToken, // Get current token
117
+ } = useAuth();
118
+
119
+ // Your component logic
120
+ }
121
+ ```
122
+
123
+ ### ProtectedRoute
124
+
125
+ Protect routes that require authentication:
126
+
127
+ ```tsx
128
+ import { ProtectedRoute } from '@smartlinks/auth-ui';
129
+
130
+ <ProtectedRoute fallback={<LoginPage />}>
131
+ <DashboardPage />
132
+ </ProtectedRoute>
133
+ ```
134
+
135
+ ## Multi-Tenant & Account Data
136
+
137
+ ### Client ID
138
+
139
+ Use `clientId` to identify which system/tenant is using the auth:
140
+
141
+ ```tsx
142
+ <SmartlinksAuthUI
143
+ apiEndpoint="https://api.smartlinks.com/api/v1/authkit"
144
+ clientId="acme-corp-production"
145
+ onAuthSuccess={(token, user, accountData) => {
146
+ console.log('Client:', accountData.clientId);
147
+ }}
148
+ />
149
+ ```
150
+
151
+ ### Account Data
152
+
153
+ Store custom metadata per user account on registration:
154
+
155
+ ```tsx
156
+ <SmartlinksAuthUI
157
+ apiEndpoint="https://api.smartlinks.com/api/v1/authkit"
158
+ clientId="your-client-123"
159
+ clientName="Acme Corporation"
160
+ accountData={{
161
+ companyName: "Acme Corporation",
162
+ plan: "enterprise",
163
+ seats: 50,
164
+ customField: "value"
165
+ }}
166
+ onAuthSuccess={(token, user, accountData) => {
167
+ // accountData now includes all custom fields
168
+ console.log('Company:', accountData.companyName);
169
+ console.log('Plan:', accountData.plan);
170
+ }}
171
+ />
172
+ ```
173
+
174
+ On login, the account data is automatically retrieved and returned.
175
+
176
+ ## Authentication Flows
177
+
178
+ ### Email/Password Login
179
+ ```tsx
180
+ <SmartlinksAuthUI
181
+ apiEndpoint="https://api.smartlinks.com/api/v1/authkit"
182
+ onAuthSuccess={(token) => console.log('Token:', token)}
183
+ enabledProviders={['email']}
184
+ />
185
+ ```
186
+
187
+ ### Google OAuth
188
+ ```tsx
189
+ <SmartlinksAuthUI
190
+ apiEndpoint="https://api.smartlinks.com/api/v1/authkit"
191
+ onAuthSuccess={(token) => console.log('Token:', token)}
192
+ enabledProviders={['google']}
193
+ />
194
+ ```
195
+
196
+ ### Phone/SMS Authentication
197
+ ```tsx
198
+ <SmartlinksAuthUI
199
+ apiEndpoint="https://api.smartlinks.com/api/v1/authkit"
200
+ onAuthSuccess={(token) => console.log('Token:', token)}
201
+ enabledProviders={['phone']}
202
+ />
203
+ ```
204
+
205
+ ## URL-Based Flows
206
+
207
+ The component automatically handles URL parameters for:
208
+
209
+ - **Email Verification**: `?mode=verifyEmail&token=xxx`
210
+ - **Password Reset**: `?mode=resetPassword&token=xxx`
211
+
212
+ ## API Integration
213
+
214
+ Your Smartlinks API should implement these endpoints with clientId in the URL path:
215
+
216
+ ### POST /api/v1/authkit/:clientId/auth/login
217
+ ```json
218
+ {
219
+ "email": "user@example.com",
220
+ "password": "password123"
221
+ }
222
+ ```
223
+ Response: `{ "token": "bearer_token", "user": {...} }`
224
+
225
+ ### POST /api/v1/authkit/:clientId/auth/register
226
+ ```json
227
+ {
228
+ "email": "user@example.com",
229
+ "password": "password123",
230
+ "displayName": "John Doe"
231
+ }
232
+ ```
233
+ Response: `{ "token": "bearer_token", "user": {...} }`
234
+
235
+ ### POST /api/v1/authkit/:clientId/auth/google
236
+ ```json
237
+ {
238
+ "idToken": "google_id_token"
239
+ }
240
+ ```
241
+ Response: `{ "token": "bearer_token", "user": {...} }`
242
+
243
+ ### POST /api/v1/authkit/:clientId/auth/phone/send-code
244
+ ```json
245
+ {
246
+ "phoneNumber": "+1234567890"
247
+ }
248
+ ```
249
+ Response: `{ "verificationId": "xxx" }`
250
+
251
+ ### POST /api/v1/authkit/:clientId/auth/phone/verify
252
+ ```json
253
+ {
254
+ "verificationId": "xxx",
255
+ "code": "123456"
256
+ }
257
+ ```
258
+ Response: `{ "token": "bearer_token", "user": {...} }`
259
+
260
+ ### POST /api/v1/authkit/:clientId/auth/reset-password
261
+ ```json
262
+ {
263
+ "email": "user@example.com"
264
+ }
265
+ ```
266
+ Response: `{ "success": true }`
267
+
268
+ ### POST /api/v1/authkit/:clientId/auth/verify-reset-token
269
+ ```json
270
+ {
271
+ "oobCode": "reset_code_from_url"
272
+ }
273
+ ```
274
+ Response: `{ "valid": true, "email": "user@example.com" }`
275
+
276
+ ### POST /api/v1/authkit/:clientId/auth/complete-reset
277
+ ```json
278
+ {
279
+ "token": "reset_token_from_email",
280
+ "newPassword": "newpass123"
281
+ }
282
+ ```
283
+ Response: `{ "success": true }`
284
+
285
+ ### GET /api/v1/authkit/:clientId/config
286
+ Get UI configuration for the client (public, cached)
287
+
288
+ Response:
289
+ ```json
290
+ {
291
+ "title": "Welcome to Acme",
292
+ "subtitle": "Sign in to your account",
293
+ "primaryColor": "#3B82F6",
294
+ "buttonStyle": "rounded",
295
+ "enabledProviders": ["email", "google"]
296
+ }
297
+ ```
298
+
299
+ ## Styling
300
+
301
+ The component uses CSS modules and can be customized:
302
+
303
+ ```tsx
304
+ <SmartlinksAuthUI
305
+ apiEndpoint="https://api.smartlinks.com"
306
+ clientId="your-client-123"
307
+ onAuthSuccess={handleAuth}
308
+ className="custom-auth-container"
309
+ theme="dark"
310
+ />
311
+ ```
312
+
313
+ ## TypeScript Support
314
+
315
+ Full TypeScript definitions included:
316
+
317
+ ```tsx
318
+ import type { AuthUser, AuthToken, AuthProvider } from '@smartlinks/auth-ui';
319
+ ```
320
+
321
+ ## License
322
+
323
+ MIT © Smartlinks
package/dist/api.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ import type { AuthResponse, AuthFormData, AuthUIConfig } from './types';
2
+ /**
3
+ * AuthAPI - Thin wrapper around Smartlinks SDK authKit namespace
4
+ * All authentication operations now use the global Smartlinks SDK
5
+ */
6
+ export declare class AuthAPI {
7
+ private clientId;
8
+ private clientName?;
9
+ constructor(_apiEndpoint: string, clientId: string, clientName?: string);
10
+ login(email: string, password: string): Promise<AuthResponse>;
11
+ register(data: AuthFormData): Promise<AuthResponse>;
12
+ loginWithGoogle(idToken: string): Promise<AuthResponse>;
13
+ sendPhoneCode(phoneNumber: string): Promise<{
14
+ verificationId: string;
15
+ }>;
16
+ verifyPhoneCode(verificationId: string, code: string): Promise<AuthResponse>;
17
+ requestPasswordReset(email: string, redirectUrl: string): Promise<{
18
+ success: boolean;
19
+ message: string;
20
+ }>;
21
+ verifyResetToken(token: string): Promise<{
22
+ valid: boolean;
23
+ email?: string;
24
+ expiresAt?: number;
25
+ message?: string;
26
+ }>;
27
+ completePasswordReset(token: string, newPassword: string): Promise<{
28
+ success: boolean;
29
+ message: string;
30
+ }>;
31
+ sendEmailVerification(userId: string, email: string, redirectUrl: string): Promise<{
32
+ success: boolean;
33
+ message: string;
34
+ }>;
35
+ verifyEmailWithToken(token: string): Promise<AuthResponse & {
36
+ message: string;
37
+ }>;
38
+ resendVerification(userId: string, email: string, redirectUrl: string): Promise<{
39
+ success: boolean;
40
+ message: string;
41
+ }>;
42
+ fetchConfig(): Promise<AuthUIConfig>;
43
+ }
44
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAExE;;;GAGG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAC,CAAS;gBAEhB,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;IAOjE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAI7D,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IASnD,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAIvD,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAIvE,eAAe,CACnB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC;IAIlB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAQxG,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAIlH,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAIzG,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IASzH,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAIhF,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAStH,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC;CAkB3C"}
package/dist/api.js ADDED
@@ -0,0 +1,105 @@
1
+ export class AuthAPI {
2
+ constructor(apiEndpoint, clientId, clientName) {
3
+ this.baseUrl = apiEndpoint.replace(/\/$/, '');
4
+ this.clientId = clientId;
5
+ this.clientName = clientName;
6
+ }
7
+ buildUrl(path) {
8
+ return `${this.baseUrl}/api/v1/authkit/${this.clientId}${path}`;
9
+ }
10
+ async request(path, method = 'GET', body) {
11
+ const url = this.buildUrl(path);
12
+ const response = await fetch(url, {
13
+ method,
14
+ headers: {
15
+ 'Content-Type': 'application/json',
16
+ 'ngrok-skip-browser-warning': 'true',
17
+ },
18
+ body: body ? JSON.stringify(body) : undefined,
19
+ });
20
+ if (!response.ok) {
21
+ const error = await response.json().catch(() => ({ message: 'Request failed' }));
22
+ throw new Error(error.message || `HTTP ${response.status}`);
23
+ }
24
+ return response.json();
25
+ }
26
+ async login(email, password) {
27
+ return this.request('/auth/login', 'POST', { email, password });
28
+ }
29
+ async register(data) {
30
+ // Include clientId, redirectUrl, and clientName in registration
31
+ return this.request('/auth/register', 'POST', {
32
+ ...data,
33
+ clientId: this.clientId,
34
+ clientName: this.clientName
35
+ });
36
+ }
37
+ async loginWithGoogle(idToken) {
38
+ return this.request('/auth/google', 'POST', { idToken });
39
+ }
40
+ async sendPhoneCode(phoneNumber) {
41
+ return this.request('/auth/phone/send-code', 'POST', { phoneNumber });
42
+ }
43
+ async verifyPhoneCode(verificationId, code) {
44
+ return this.request('/auth/phone/verify', 'POST', {
45
+ verificationId,
46
+ code,
47
+ });
48
+ }
49
+ // Custom Email Flow Methods (using Resend)
50
+ async requestPasswordReset(email, redirectUrl) {
51
+ return this.request('/auth/reset-password', 'POST', {
52
+ email,
53
+ redirectUrl,
54
+ clientName: this.clientName
55
+ });
56
+ }
57
+ async verifyResetToken(token) {
58
+ return this.request('/auth/verify-reset-token', 'POST', { token });
59
+ }
60
+ async completePasswordReset(token, newPassword) {
61
+ return this.request('/auth/complete-reset', 'POST', {
62
+ token,
63
+ newPassword
64
+ });
65
+ }
66
+ async sendEmailVerification(userId, email, redirectUrl) {
67
+ return this.request('/auth/send-verification', 'POST', {
68
+ userId,
69
+ email,
70
+ redirectUrl,
71
+ clientName: this.clientName
72
+ });
73
+ }
74
+ async verifyEmailWithToken(token) {
75
+ return this.request('/auth/verify-email', 'POST', { token });
76
+ }
77
+ async resendVerification(userId, email, redirectUrl) {
78
+ return this.request('/auth/resend-verification', 'POST', {
79
+ userId,
80
+ email,
81
+ redirectUrl,
82
+ clientName: this.clientName
83
+ });
84
+ }
85
+ // UI Configuration
86
+ async fetchConfig() {
87
+ try {
88
+ return await this.request('/config', 'GET');
89
+ }
90
+ catch (error) {
91
+ console.warn('Failed to fetch UI config, using defaults:', error);
92
+ return {
93
+ branding: {
94
+ title: 'Smartlinks Auth',
95
+ subtitle: 'Sign in to your account',
96
+ primaryColor: '#3B82F6',
97
+ secondaryColor: '#1D4ED8',
98
+ backgroundColor: '#e0f2fe',
99
+ buttonStyle: 'rounded',
100
+ fontFamily: 'Inter, sans-serif'
101
+ }
102
+ };
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import './AuthContainer.css';
3
+ import type { AuthUIConfig } from '../types';
4
+ interface AuthContainerProps {
5
+ children: React.ReactNode;
6
+ theme?: 'light' | 'dark';
7
+ className?: string;
8
+ config?: AuthUIConfig;
9
+ }
10
+ export declare const AuthContainer: React.FC<AuthContainerProps>;
11
+ export {};
12
+ //# sourceMappingURL=AuthContainer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthContainer.d.ts","sourceRoot":"","sources":["../../src/components/AuthContainer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AACzC,OAAO,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA4GtD,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useEffect } from 'react';
3
+ import './AuthContainer.css';
4
+ export const AuthContainer = ({ children, theme = 'light', className = '', config, }) => {
5
+ // Apply CSS variables for customization
6
+ useEffect(() => {
7
+ if (!config?.branding)
8
+ return;
9
+ const root = document.documentElement;
10
+ const { branding } = config;
11
+ if (branding.primaryColor) {
12
+ root.style.setProperty('--auth-primary-color', branding.primaryColor);
13
+ }
14
+ if (branding.secondaryColor) {
15
+ root.style.setProperty('--auth-secondary-color', branding.secondaryColor);
16
+ }
17
+ if (branding.backgroundColor) {
18
+ root.style.setProperty('--auth-bg-color', branding.backgroundColor);
19
+ }
20
+ if (branding.fontFamily) {
21
+ root.style.setProperty('--auth-font-family', branding.fontFamily);
22
+ }
23
+ // Inject custom CSS if provided
24
+ if (branding.customCss) {
25
+ const styleId = 'auth-custom-styles';
26
+ let styleEl = document.getElementById(styleId);
27
+ if (!styleEl) {
28
+ styleEl = document.createElement('style');
29
+ styleEl.id = styleId;
30
+ document.head.appendChild(styleEl);
31
+ }
32
+ styleEl.textContent = branding.customCss;
33
+ }
34
+ return () => {
35
+ // Cleanup on unmount
36
+ root.style.removeProperty('--auth-primary-color');
37
+ root.style.removeProperty('--auth-secondary-color');
38
+ root.style.removeProperty('--auth-bg-color');
39
+ root.style.removeProperty('--auth-font-family');
40
+ };
41
+ }, [config]);
42
+ const title = config?.branding?.title || 'Smartlinks Auth';
43
+ const subtitle = config?.branding?.subtitle || 'Sign in to your account';
44
+ const logoUrl = config?.branding?.logoUrl;
45
+ return (_jsx("div", { className: `auth-container auth-theme-${theme} ${className}`, children: _jsxs("div", { className: "auth-card", style: { borderRadius: config?.branding?.buttonStyle === 'square' ? '4px' : '12px' }, children: [_jsxs("div", { className: "auth-header", children: [_jsx("div", { className: "auth-logo", children: logoUrl ? (_jsx("img", { src: logoUrl, alt: "Logo", style: { width: 40, height: 40, objectFit: 'contain' } })) : (_jsxs("svg", { width: "40", height: "40", viewBox: "0 0 40 40", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("rect", { width: "40", height: "40", rx: "8", fill: "url(#gradient)" }), _jsx("path", { d: "M20 10L12 18L20 26L28 18L20 10Z", fill: "white", fillOpacity: "0.9" }), _jsx("path", { d: "M20 18L16 22L20 26L24 22L20 18Z", fill: "white" }), _jsx("defs", { children: _jsxs("linearGradient", { id: "gradient", x1: "0", y1: "0", x2: "40", y2: "40", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "var(--auth-primary-color, #3B82F6)" }), _jsx("stop", { offset: "1", stopColor: "var(--auth-secondary-color, #1D4ED8)" })] }) })] })) }), _jsx("h1", { className: "auth-title", children: title }), subtitle && _jsx("p", { className: "auth-subtitle", children: subtitle })] }), _jsx("div", { className: "auth-content", children: children }), (config?.branding?.termsUrl || config?.branding?.privacyUrl) && (_jsxs("div", { className: "auth-footer", children: [config.branding.termsUrl && _jsx("a", { href: config.branding.termsUrl, target: "_blank", rel: "noopener noreferrer", children: "Terms" }), config.branding.termsUrl && config.branding.privacyUrl && _jsx("span", { children: "\u2022" }), config.branding.privacyUrl && _jsx("a", { href: config.branding.privacyUrl, target: "_blank", rel: "noopener noreferrer", children: "Privacy" })] }))] }) }));
46
+ };
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import type { AuthProvider, AuthUIConfig } from '../types';
3
+ interface AuthUIPreviewProps {
4
+ customization?: Partial<AuthUIConfig>;
5
+ enabledProviders?: AuthProvider[];
6
+ theme?: 'light' | 'dark';
7
+ className?: string;
8
+ }
9
+ export declare const AuthUIPreview: React.FC<AuthUIPreviewProps>;
10
+ export {};
11
+ //# sourceMappingURL=AuthUIPreview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthUIPreview.d.ts","sourceRoot":"","sources":["../../src/components/AuthUIPreview.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE3D,UAAU,kBAAkB;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,YAAY,EAAE,CAAC;IAClC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA8FtD,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { AuthContainer } from './AuthContainer';
4
+ export const AuthUIPreview = ({ customization, enabledProviders = ['email', 'google', 'phone'], theme = 'light', className, }) => {
5
+ const showEmail = enabledProviders.includes('email');
6
+ const showGoogle = enabledProviders.includes('google');
7
+ const showPhone = enabledProviders.includes('phone');
8
+ const hasProviders = showGoogle || showPhone;
9
+ return (_jsxs(AuthContainer, { theme: theme, className: className, config: customization, children: [showEmail && (_jsxs("div", { className: "auth-form", children: [_jsxs("div", { className: "auth-form-group", children: [_jsx("label", { className: "auth-label", children: "Email" }), _jsx("input", { type: "email", className: "auth-input", placeholder: "Enter your email", disabled: true })] }), _jsxs("div", { className: "auth-form-group", children: [_jsx("label", { className: "auth-label", children: "Password" }), _jsx("input", { type: "password", className: "auth-input", placeholder: "Enter your password", disabled: true })] }), _jsx("button", { className: "auth-button auth-button-primary", disabled: true, children: "Sign In" }), _jsx("div", { style: { textAlign: 'center', marginTop: '1rem' }, children: _jsx("button", { className: "auth-link", disabled: true, children: "Forgot password?" }) }), _jsxs("div", { style: { textAlign: 'center', marginTop: '0.5rem', fontSize: '0.875rem', color: 'var(--auth-text-muted, #6B7280)' }, children: ["Don't have an account?", ' ', _jsx("button", { className: "auth-link", disabled: true, children: "Sign up" })] })] })), hasProviders && (_jsxs(_Fragment, { children: [showEmail && (_jsx("div", { className: "auth-or-divider", children: _jsx("span", { children: "or continue with" }) })), _jsxs("div", { className: "auth-provider-buttons", children: [showGoogle && (_jsxs("button", { className: "auth-provider-button", disabled: true, children: [_jsxs("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", children: [_jsx("path", { d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z", fill: "#4285F4" }), _jsx("path", { d: "M9 18c2.43 0 4.467-.806 5.956-2.183l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332C2.438 15.983 5.482 18 9 18z", fill: "#34A853" }), _jsx("path", { d: "M3.964 10.707c-.18-.54-.282-1.117-.282-1.707 0-.593.102-1.167.282-1.707V4.961H.957C.347 6.175 0 7.548 0 9s.348 2.825.957 4.039l3.007-2.332z", fill: "#FBBC05" }), _jsx("path", { d: "M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0 5.482 0 2.438 2.017.957 4.958L3.964 7.29C4.672 5.163 6.656 3.58 9 3.58z", fill: "#EA4335" })] }), _jsx("span", { children: "Google" })] })), showPhone && (_jsxs("button", { className: "auth-provider-button", disabled: true, children: [_jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" }) }), _jsx("span", { children: "Phone" })] }))] })] }))] }));
10
+ };
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import type { AuthFormData } from '../types';
3
+ import './AuthForm.css';
4
+ interface EmailAuthFormProps {
5
+ mode: 'login' | 'register';
6
+ onSubmit: (data: AuthFormData) => Promise<void>;
7
+ onModeSwitch: () => void;
8
+ onForgotPassword: () => void;
9
+ loading: boolean;
10
+ error?: string;
11
+ }
12
+ export declare const EmailAuthForm: React.FC<EmailAuthFormProps>;
13
+ export {};
14
+ //# sourceMappingURL=EmailAuthForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailAuthForm.d.ts","sourceRoot":"","sources":["../../src/components/EmailAuthForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,gBAAgB,CAAC;AAExB,UAAU,kBAAkB;IAC1B,IAAI,EAAE,OAAO,GAAG,UAAU,CAAC;IAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA4ItD,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useState } from 'react';
3
+ import './AuthForm.css';
4
+ export const EmailAuthForm = ({ mode, onSubmit, onModeSwitch, onForgotPassword, loading, error, }) => {
5
+ const [formData, setFormData] = useState({
6
+ email: '',
7
+ password: '',
8
+ displayName: '',
9
+ });
10
+ const handleSubmit = async (e) => {
11
+ e.preventDefault();
12
+ await onSubmit(formData);
13
+ };
14
+ const handleChange = (field, value) => {
15
+ setFormData(prev => ({ ...prev, [field]: value }));
16
+ };
17
+ return (_jsxs("form", { className: "auth-form", onSubmit: handleSubmit, children: [_jsxs("div", { className: "auth-form-header", children: [_jsx("h2", { className: "auth-form-title", children: mode === 'login' ? 'Sign in' : 'Create account' }), _jsx("p", { className: "auth-form-subtitle", children: mode === 'login'
18
+ ? 'Welcome back! Please enter your credentials.'
19
+ : 'Get started by creating your account.' })] }), error && (_jsxs("div", { className: "auth-error", role: "alert", children: [_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: _jsx("path", { d: "M8 0C3.58 0 0 3.58 0 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm1 13H7v-2h2v2zm0-3H7V4h2v6z" }) }), error] })), mode === 'register' && (_jsxs("div", { className: "auth-form-group", children: [_jsx("label", { htmlFor: "displayName", className: "auth-label", children: "Full Name" }), _jsx("input", { type: "text", id: "displayName", className: "auth-input", value: formData.displayName || '', onChange: (e) => handleChange('displayName', e.target.value), required: mode === 'register', disabled: loading, placeholder: "John Doe" })] })), _jsxs("div", { className: "auth-form-group", children: [_jsx("label", { htmlFor: "email", className: "auth-label", children: "Email address" }), _jsx("input", { type: "email", id: "email", className: "auth-input", value: formData.email || '', onChange: (e) => handleChange('email', e.target.value), required: true, disabled: loading, placeholder: "you@example.com", autoComplete: "email" })] }), _jsxs("div", { className: "auth-form-group", children: [_jsx("label", { htmlFor: "password", className: "auth-label", children: "Password" }), _jsx("input", { type: "password", id: "password", className: "auth-input", value: formData.password || '', onChange: (e) => handleChange('password', e.target.value), required: true, disabled: loading, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", autoComplete: mode === 'login' ? 'current-password' : 'new-password', minLength: 6 })] }), mode === 'login' && (_jsx("div", { className: "auth-form-footer", children: _jsx("button", { type: "button", className: "auth-link", onClick: onForgotPassword, disabled: loading, children: "Forgot password?" }) })), _jsx("button", { type: "submit", className: "auth-button auth-button-primary", disabled: loading, children: loading ? (_jsx("span", { className: "auth-spinner" })) : mode === 'login' ? ('Sign in') : ('Create account') }), _jsxs("div", { className: "auth-divider", children: [_jsx("span", { children: mode === 'login' ? "Don't have an account?" : 'Already have an account?' }), _jsx("button", { type: "button", className: "auth-link auth-link-bold", onClick: onModeSwitch, disabled: loading, children: mode === 'login' ? 'Sign up' : 'Sign in' })] })] }));
20
+ };
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import './AuthForm.css';
3
+ interface PasswordResetFormProps {
4
+ onSubmit: (emailOrPassword: string, confirmPassword?: string) => Promise<void>;
5
+ onBack: () => void;
6
+ loading: boolean;
7
+ error?: string;
8
+ success?: boolean;
9
+ token?: string;
10
+ }
11
+ export declare const PasswordResetForm: React.FC<PasswordResetFormProps>;
12
+ export {};
13
+ //# sourceMappingURL=PasswordResetForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PasswordResetForm.d.ts","sourceRoot":"","sources":["../../src/components/PasswordResetForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AACxC,OAAO,gBAAgB,CAAC;AAExB,UAAU,sBAAsB;IAC9B,QAAQ,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAwL9D,CAAC"}