@pixygon/auth 1.0.0 → 1.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.
- package/README.md +1 -1
- package/dist/{chunk-E34M2RJD.mjs → chunk-ELVIBXBG.mjs} +61 -4
- package/dist/components/index.d.mts +5 -5
- package/dist/components/index.d.ts +5 -5
- package/dist/components/index.js +115 -86
- package/dist/components/index.mjs +100 -83
- package/dist/{index-CIK2MKl9.d.mts → index-CuhQGwDH.d.mts} +32 -3
- package/dist/{index-CIK2MKl9.d.ts → index-CuhQGwDH.d.ts} +32 -3
- package/dist/index.d.mts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +62 -4
- package/dist/index.mjs +3 -1
- package/package.json +1 -1
- package/src/api/client.ts +34 -1
- package/src/components/ForgotPasswordForm.tsx +26 -23
- package/src/components/LoginForm.tsx +18 -15
- package/src/components/PixygonAuth.tsx +11 -0
- package/src/components/RegisterForm.tsx +21 -18
- package/src/components/VerifyForm.tsx +19 -16
- package/src/hooks/index.ts +2 -0
- package/src/index.ts +9 -0
- package/src/providers/AuthProvider.tsx +12 -0
- package/src/types/index.ts +51 -2
- package/src/utils/storage.ts +15 -3
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { useState, useCallback, type FormEvent } from 'react';
|
|
7
7
|
import { useAuth } from '../hooks';
|
|
8
8
|
import type { LoginFormProps, AuthError } from '../types';
|
|
9
|
+
import { DEFAULT_THEME } from '../types';
|
|
9
10
|
|
|
10
11
|
export function LoginForm({
|
|
11
12
|
onSuccess,
|
|
@@ -14,7 +15,9 @@ export function LoginForm({
|
|
|
14
15
|
onNavigateForgotPassword,
|
|
15
16
|
showBranding = true,
|
|
16
17
|
className = '',
|
|
18
|
+
theme,
|
|
17
19
|
}: LoginFormProps) {
|
|
20
|
+
const t = { ...DEFAULT_THEME, ...theme };
|
|
18
21
|
const { login, isLoading, error } = useAuth();
|
|
19
22
|
|
|
20
23
|
const [userName, setUserName] = useState('');
|
|
@@ -53,11 +56,11 @@ export function LoginForm({
|
|
|
53
56
|
<div className={`pixygon-auth-container ${className}`}>
|
|
54
57
|
<style>{`
|
|
55
58
|
.pixygon-auth-container {
|
|
56
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
57
|
-
background:
|
|
58
|
-
color:
|
|
59
|
+
font-family: ${t.fontFamily === 'inherit' ? "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" : t.fontFamily};
|
|
60
|
+
background: ${t.backgroundColor};
|
|
61
|
+
color: ${t.textColor};
|
|
59
62
|
padding: 2rem;
|
|
60
|
-
border-radius:
|
|
63
|
+
border-radius: ${t.borderRadius};
|
|
61
64
|
max-width: 400px;
|
|
62
65
|
width: 100%;
|
|
63
66
|
margin: 0 auto;
|
|
@@ -83,7 +86,7 @@ export function LoginForm({
|
|
|
83
86
|
|
|
84
87
|
.pixygon-auth-subtitle {
|
|
85
88
|
font-size: 0.875rem;
|
|
86
|
-
color:
|
|
89
|
+
color: ${t.textSecondary};
|
|
87
90
|
margin: 0;
|
|
88
91
|
}
|
|
89
92
|
|
|
@@ -102,31 +105,31 @@ export function LoginForm({
|
|
|
102
105
|
.pixygon-auth-label {
|
|
103
106
|
font-size: 0.875rem;
|
|
104
107
|
font-weight: 500;
|
|
105
|
-
color:
|
|
108
|
+
color: ${t.textSecondary};
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
.pixygon-auth-input {
|
|
109
|
-
background:
|
|
112
|
+
background: ${t.surfaceColor};
|
|
110
113
|
border: 1px solid #404040;
|
|
111
114
|
border-radius: 0.5rem;
|
|
112
115
|
padding: 0.75rem 1rem;
|
|
113
116
|
font-size: 1rem;
|
|
114
|
-
color:
|
|
117
|
+
color: ${t.textColor};
|
|
115
118
|
outline: none;
|
|
116
119
|
transition: border-color 0.2s, box-shadow 0.2s;
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
.pixygon-auth-input:focus {
|
|
120
|
-
border-color:
|
|
123
|
+
border-color: ${t.primaryColor};
|
|
121
124
|
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
.pixygon-auth-input.error {
|
|
125
|
-
border-color:
|
|
128
|
+
border-color: ${t.errorColor};
|
|
126
129
|
}
|
|
127
130
|
|
|
128
131
|
.pixygon-auth-button {
|
|
129
|
-
background:
|
|
132
|
+
background: ${t.primaryColor};
|
|
130
133
|
color: white;
|
|
131
134
|
border: none;
|
|
132
135
|
border-radius: 0.5rem;
|
|
@@ -153,7 +156,7 @@ export function LoginForm({
|
|
|
153
156
|
|
|
154
157
|
.pixygon-auth-error {
|
|
155
158
|
background: rgba(239, 68, 68, 0.1);
|
|
156
|
-
border: 1px solid
|
|
159
|
+
border: 1px solid ${t.errorColor};
|
|
157
160
|
border-radius: 0.5rem;
|
|
158
161
|
padding: 0.75rem 1rem;
|
|
159
162
|
color: #fca5a5;
|
|
@@ -161,7 +164,7 @@ export function LoginForm({
|
|
|
161
164
|
}
|
|
162
165
|
|
|
163
166
|
.pixygon-auth-link {
|
|
164
|
-
color:
|
|
167
|
+
color: ${t.primaryColor};
|
|
165
168
|
text-decoration: none;
|
|
166
169
|
font-size: 0.875rem;
|
|
167
170
|
cursor: pointer;
|
|
@@ -180,7 +183,7 @@ export function LoginForm({
|
|
|
180
183
|
text-align: center;
|
|
181
184
|
margin-top: 1.5rem;
|
|
182
185
|
font-size: 0.875rem;
|
|
183
|
-
color:
|
|
186
|
+
color: ${t.textSecondary};
|
|
184
187
|
}
|
|
185
188
|
|
|
186
189
|
.pixygon-auth-branding {
|
|
@@ -219,7 +222,7 @@ export function LoginForm({
|
|
|
219
222
|
fill="none"
|
|
220
223
|
xmlns="http://www.w3.org/2000/svg"
|
|
221
224
|
>
|
|
222
|
-
<circle cx="50" cy="50" r="45" fill=
|
|
225
|
+
<circle cx="50" cy="50" r="45" fill={t.primaryColor} />
|
|
223
226
|
<path
|
|
224
227
|
d="M30 45L45 30L70 55L55 70L30 45Z"
|
|
225
228
|
fill="white"
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
import { useState, useCallback, useEffect } from 'react';
|
|
7
7
|
import type { PixygonAuthProps, User, AuthError } from '../types';
|
|
8
|
+
import { DEFAULT_THEME } from '../types';
|
|
9
|
+
import type { AuthTheme } from '../types';
|
|
10
|
+
import { useAuthContext } from '../providers/AuthProvider';
|
|
8
11
|
import { LoginForm } from './LoginForm';
|
|
9
12
|
import { RegisterForm } from './RegisterForm';
|
|
10
13
|
import { VerifyForm } from './VerifyForm';
|
|
@@ -22,6 +25,9 @@ export function PixygonAuth({
|
|
|
22
25
|
theme = 'dark',
|
|
23
26
|
className = '',
|
|
24
27
|
}: PixygonAuthProps) {
|
|
28
|
+
const { config } = useAuthContext();
|
|
29
|
+
const mergedTheme: Required<AuthTheme> = { ...DEFAULT_THEME, ...config.theme };
|
|
30
|
+
|
|
25
31
|
const [mode, setMode] = useState<AuthMode>(initialMode);
|
|
26
32
|
const [userName, setUserName] = useState(initialUserName || '');
|
|
27
33
|
|
|
@@ -125,6 +131,7 @@ export function PixygonAuth({
|
|
|
125
131
|
onNavigateRegister={() => handleModeChange('register')}
|
|
126
132
|
onNavigateForgotPassword={() => handleModeChange('forgot-password')}
|
|
127
133
|
showBranding={showBranding}
|
|
134
|
+
theme={mergedTheme}
|
|
128
135
|
/>
|
|
129
136
|
)}
|
|
130
137
|
|
|
@@ -134,6 +141,7 @@ export function PixygonAuth({
|
|
|
134
141
|
onError={handleError}
|
|
135
142
|
onNavigateLogin={() => handleModeChange('login')}
|
|
136
143
|
showBranding={showBranding}
|
|
144
|
+
theme={mergedTheme}
|
|
137
145
|
/>
|
|
138
146
|
)}
|
|
139
147
|
|
|
@@ -144,6 +152,7 @@ export function PixygonAuth({
|
|
|
144
152
|
onError={handleError}
|
|
145
153
|
onNavigateLogin={() => handleModeChange('login')}
|
|
146
154
|
showBranding={showBranding}
|
|
155
|
+
theme={mergedTheme}
|
|
147
156
|
/>
|
|
148
157
|
)}
|
|
149
158
|
|
|
@@ -153,6 +162,7 @@ export function PixygonAuth({
|
|
|
153
162
|
onError={handleError}
|
|
154
163
|
onNavigateLogin={() => handleModeChange('login')}
|
|
155
164
|
showBranding={showBranding}
|
|
165
|
+
theme={mergedTheme}
|
|
156
166
|
/>
|
|
157
167
|
)}
|
|
158
168
|
|
|
@@ -163,6 +173,7 @@ export function PixygonAuth({
|
|
|
163
173
|
onError={handleError}
|
|
164
174
|
onNavigateLogin={() => handleModeChange('login')}
|
|
165
175
|
showBranding={showBranding}
|
|
176
|
+
theme={mergedTheme}
|
|
166
177
|
/>
|
|
167
178
|
)}
|
|
168
179
|
</div>
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { useState, useCallback, type FormEvent } from 'react';
|
|
7
7
|
import { useAuth } from '../hooks';
|
|
8
8
|
import type { RegisterFormProps, AuthError } from '../types';
|
|
9
|
+
import { DEFAULT_THEME } from '../types';
|
|
9
10
|
|
|
10
11
|
export function RegisterForm({
|
|
11
12
|
onSuccess,
|
|
@@ -13,7 +14,9 @@ export function RegisterForm({
|
|
|
13
14
|
onNavigateLogin,
|
|
14
15
|
showBranding = true,
|
|
15
16
|
className = '',
|
|
17
|
+
theme,
|
|
16
18
|
}: RegisterFormProps) {
|
|
19
|
+
const t = { ...DEFAULT_THEME, ...theme };
|
|
17
20
|
const { register, isLoading, error } = useAuth();
|
|
18
21
|
|
|
19
22
|
const [userName, setUserName] = useState('');
|
|
@@ -113,11 +116,11 @@ export function RegisterForm({
|
|
|
113
116
|
<div className={`pixygon-auth-container ${className}`}>
|
|
114
117
|
<style>{`
|
|
115
118
|
.pixygon-auth-container {
|
|
116
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
117
|
-
background:
|
|
118
|
-
color:
|
|
119
|
+
font-family: ${t.fontFamily === 'inherit' ? "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" : t.fontFamily};
|
|
120
|
+
background: ${t.backgroundColor};
|
|
121
|
+
color: ${t.textColor};
|
|
119
122
|
padding: 2rem;
|
|
120
|
-
border-radius:
|
|
123
|
+
border-radius: ${t.borderRadius};
|
|
121
124
|
max-width: 400px;
|
|
122
125
|
width: 100%;
|
|
123
126
|
margin: 0 auto;
|
|
@@ -143,7 +146,7 @@ export function RegisterForm({
|
|
|
143
146
|
|
|
144
147
|
.pixygon-auth-subtitle {
|
|
145
148
|
font-size: 0.875rem;
|
|
146
|
-
color:
|
|
149
|
+
color: ${t.textSecondary};
|
|
147
150
|
margin: 0;
|
|
148
151
|
}
|
|
149
152
|
|
|
@@ -162,31 +165,31 @@ export function RegisterForm({
|
|
|
162
165
|
.pixygon-auth-label {
|
|
163
166
|
font-size: 0.875rem;
|
|
164
167
|
font-weight: 500;
|
|
165
|
-
color:
|
|
168
|
+
color: ${t.textSecondary};
|
|
166
169
|
}
|
|
167
170
|
|
|
168
171
|
.pixygon-auth-input {
|
|
169
|
-
background:
|
|
172
|
+
background: ${t.surfaceColor};
|
|
170
173
|
border: 1px solid #404040;
|
|
171
174
|
border-radius: 0.5rem;
|
|
172
175
|
padding: 0.75rem 1rem;
|
|
173
176
|
font-size: 1rem;
|
|
174
|
-
color:
|
|
177
|
+
color: ${t.textColor};
|
|
175
178
|
outline: none;
|
|
176
179
|
transition: border-color 0.2s, box-shadow 0.2s;
|
|
177
180
|
}
|
|
178
181
|
|
|
179
182
|
.pixygon-auth-input:focus {
|
|
180
|
-
border-color:
|
|
183
|
+
border-color: ${t.primaryColor};
|
|
181
184
|
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
|
|
182
185
|
}
|
|
183
186
|
|
|
184
187
|
.pixygon-auth-input.error {
|
|
185
|
-
border-color:
|
|
188
|
+
border-color: ${t.errorColor};
|
|
186
189
|
}
|
|
187
190
|
|
|
188
191
|
.pixygon-auth-button {
|
|
189
|
-
background:
|
|
192
|
+
background: ${t.primaryColor};
|
|
190
193
|
color: white;
|
|
191
194
|
border: none;
|
|
192
195
|
border-radius: 0.5rem;
|
|
@@ -213,7 +216,7 @@ export function RegisterForm({
|
|
|
213
216
|
|
|
214
217
|
.pixygon-auth-error {
|
|
215
218
|
background: rgba(239, 68, 68, 0.1);
|
|
216
|
-
border: 1px solid
|
|
219
|
+
border: 1px solid ${t.errorColor};
|
|
217
220
|
border-radius: 0.5rem;
|
|
218
221
|
padding: 0.75rem 1rem;
|
|
219
222
|
color: #fca5a5;
|
|
@@ -221,7 +224,7 @@ export function RegisterForm({
|
|
|
221
224
|
}
|
|
222
225
|
|
|
223
226
|
.pixygon-auth-link {
|
|
224
|
-
color:
|
|
227
|
+
color: ${t.primaryColor};
|
|
225
228
|
text-decoration: none;
|
|
226
229
|
font-size: 0.875rem;
|
|
227
230
|
cursor: pointer;
|
|
@@ -240,7 +243,7 @@ export function RegisterForm({
|
|
|
240
243
|
text-align: center;
|
|
241
244
|
margin-top: 1.5rem;
|
|
242
245
|
font-size: 0.875rem;
|
|
243
|
-
color:
|
|
246
|
+
color: ${t.textSecondary};
|
|
244
247
|
}
|
|
245
248
|
|
|
246
249
|
.pixygon-auth-branding {
|
|
@@ -281,11 +284,11 @@ export function RegisterForm({
|
|
|
281
284
|
}
|
|
282
285
|
|
|
283
286
|
.pixygon-auth-password-strength-bar.active {
|
|
284
|
-
background:
|
|
287
|
+
background: ${t.primaryColor};
|
|
285
288
|
}
|
|
286
289
|
|
|
287
290
|
.pixygon-auth-password-strength-bar.weak {
|
|
288
|
-
background:
|
|
291
|
+
background: ${t.errorColor};
|
|
289
292
|
}
|
|
290
293
|
|
|
291
294
|
.pixygon-auth-password-strength-bar.fair {
|
|
@@ -293,7 +296,7 @@ export function RegisterForm({
|
|
|
293
296
|
}
|
|
294
297
|
|
|
295
298
|
.pixygon-auth-password-strength-bar.good {
|
|
296
|
-
background:
|
|
299
|
+
background: ${t.successColor};
|
|
297
300
|
}
|
|
298
301
|
|
|
299
302
|
.pixygon-auth-password-strength-bar.strong {
|
|
@@ -314,7 +317,7 @@ export function RegisterForm({
|
|
|
314
317
|
fill="none"
|
|
315
318
|
xmlns="http://www.w3.org/2000/svg"
|
|
316
319
|
>
|
|
317
|
-
<circle cx="50" cy="50" r="45" fill=
|
|
320
|
+
<circle cx="50" cy="50" r="45" fill={t.primaryColor} />
|
|
318
321
|
<path
|
|
319
322
|
d="M30 45L45 30L70 55L55 70L30 45Z"
|
|
320
323
|
fill="white"
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { useState, useCallback, useRef, useEffect, type FormEvent, type KeyboardEvent, type ClipboardEvent } from 'react';
|
|
7
7
|
import { useAuth } from '../hooks';
|
|
8
8
|
import type { VerifyFormProps, AuthError } from '../types';
|
|
9
|
+
import { DEFAULT_THEME } from '../types';
|
|
9
10
|
|
|
10
11
|
export function VerifyForm({
|
|
11
12
|
userName,
|
|
@@ -14,7 +15,9 @@ export function VerifyForm({
|
|
|
14
15
|
onNavigateLogin,
|
|
15
16
|
showBranding = true,
|
|
16
17
|
className = '',
|
|
18
|
+
theme,
|
|
17
19
|
}: VerifyFormProps) {
|
|
20
|
+
const t = { ...DEFAULT_THEME, ...theme };
|
|
18
21
|
const { verify, resendVerification, isLoading, error } = useAuth();
|
|
19
22
|
|
|
20
23
|
const [code, setCode] = useState(['', '', '', '', '', '']);
|
|
@@ -135,11 +138,11 @@ export function VerifyForm({
|
|
|
135
138
|
<div className={`pixygon-auth-container ${className}`}>
|
|
136
139
|
<style>{`
|
|
137
140
|
.pixygon-auth-container {
|
|
138
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
139
|
-
background:
|
|
140
|
-
color:
|
|
141
|
+
font-family: ${t.fontFamily === 'inherit' ? "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" : t.fontFamily};
|
|
142
|
+
background: ${t.backgroundColor};
|
|
143
|
+
color: ${t.textColor};
|
|
141
144
|
padding: 2rem;
|
|
142
|
-
border-radius:
|
|
145
|
+
border-radius: ${t.borderRadius};
|
|
143
146
|
max-width: 400px;
|
|
144
147
|
width: 100%;
|
|
145
148
|
margin: 0 auto;
|
|
@@ -165,7 +168,7 @@ export function VerifyForm({
|
|
|
165
168
|
|
|
166
169
|
.pixygon-auth-subtitle {
|
|
167
170
|
font-size: 0.875rem;
|
|
168
|
-
color:
|
|
171
|
+
color: ${t.textSecondary};
|
|
169
172
|
margin: 0;
|
|
170
173
|
}
|
|
171
174
|
|
|
@@ -187,25 +190,25 @@ export function VerifyForm({
|
|
|
187
190
|
text-align: center;
|
|
188
191
|
font-size: 1.5rem;
|
|
189
192
|
font-weight: 600;
|
|
190
|
-
background:
|
|
193
|
+
background: ${t.surfaceColor};
|
|
191
194
|
border: 1px solid #404040;
|
|
192
195
|
border-radius: 0.5rem;
|
|
193
|
-
color:
|
|
196
|
+
color: ${t.textColor};
|
|
194
197
|
outline: none;
|
|
195
198
|
transition: border-color 0.2s, box-shadow 0.2s;
|
|
196
199
|
}
|
|
197
200
|
|
|
198
201
|
.pixygon-auth-code-input:focus {
|
|
199
|
-
border-color:
|
|
202
|
+
border-color: ${t.primaryColor};
|
|
200
203
|
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
|
|
201
204
|
}
|
|
202
205
|
|
|
203
206
|
.pixygon-auth-code-input.error {
|
|
204
|
-
border-color:
|
|
207
|
+
border-color: ${t.errorColor};
|
|
205
208
|
}
|
|
206
209
|
|
|
207
210
|
.pixygon-auth-button {
|
|
208
|
-
background:
|
|
211
|
+
background: ${t.primaryColor};
|
|
209
212
|
color: white;
|
|
210
213
|
border: none;
|
|
211
214
|
border-radius: 0.5rem;
|
|
@@ -231,7 +234,7 @@ export function VerifyForm({
|
|
|
231
234
|
|
|
232
235
|
.pixygon-auth-error {
|
|
233
236
|
background: rgba(239, 68, 68, 0.1);
|
|
234
|
-
border: 1px solid
|
|
237
|
+
border: 1px solid ${t.errorColor};
|
|
235
238
|
border-radius: 0.5rem;
|
|
236
239
|
padding: 0.75rem 1rem;
|
|
237
240
|
color: #fca5a5;
|
|
@@ -240,7 +243,7 @@ export function VerifyForm({
|
|
|
240
243
|
|
|
241
244
|
.pixygon-auth-success {
|
|
242
245
|
background: rgba(34, 197, 94, 0.1);
|
|
243
|
-
border: 1px solid
|
|
246
|
+
border: 1px solid ${t.successColor};
|
|
244
247
|
border-radius: 0.5rem;
|
|
245
248
|
padding: 0.75rem 1rem;
|
|
246
249
|
color: #86efac;
|
|
@@ -248,7 +251,7 @@ export function VerifyForm({
|
|
|
248
251
|
}
|
|
249
252
|
|
|
250
253
|
.pixygon-auth-link {
|
|
251
|
-
color:
|
|
254
|
+
color: ${t.primaryColor};
|
|
252
255
|
text-decoration: none;
|
|
253
256
|
font-size: 0.875rem;
|
|
254
257
|
cursor: pointer;
|
|
@@ -272,7 +275,7 @@ export function VerifyForm({
|
|
|
272
275
|
text-align: center;
|
|
273
276
|
margin-top: 1.5rem;
|
|
274
277
|
font-size: 0.875rem;
|
|
275
|
-
color:
|
|
278
|
+
color: ${t.textSecondary};
|
|
276
279
|
}
|
|
277
280
|
|
|
278
281
|
.pixygon-auth-branding {
|
|
@@ -301,7 +304,7 @@ export function VerifyForm({
|
|
|
301
304
|
.pixygon-auth-resend {
|
|
302
305
|
text-align: center;
|
|
303
306
|
font-size: 0.875rem;
|
|
304
|
-
color:
|
|
307
|
+
color: ${t.textSecondary};
|
|
305
308
|
}
|
|
306
309
|
`}</style>
|
|
307
310
|
|
|
@@ -312,7 +315,7 @@ export function VerifyForm({
|
|
|
312
315
|
fill="none"
|
|
313
316
|
xmlns="http://www.w3.org/2000/svg"
|
|
314
317
|
>
|
|
315
|
-
<circle cx="50" cy="50" r="45" fill=
|
|
318
|
+
<circle cx="50" cy="50" r="45" fill={t.primaryColor} />
|
|
316
319
|
<path
|
|
317
320
|
d="M30 45L45 30L70 55L55 70L30 45Z"
|
|
318
321
|
fill="white"
|
package/src/hooks/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ export interface UseAuthReturn {
|
|
|
28
28
|
resendVerification: ReturnType<typeof useAuthContext>['resendVerification'];
|
|
29
29
|
forgotPassword: ReturnType<typeof useAuthContext>['forgotPassword'];
|
|
30
30
|
recoverPassword: ReturnType<typeof useAuthContext>['recoverPassword'];
|
|
31
|
+
changePassword: ReturnType<typeof useAuthContext>['changePassword'];
|
|
31
32
|
|
|
32
33
|
// Utilities
|
|
33
34
|
hasRole: (role: UserRole | UserRole[]) => boolean;
|
|
@@ -57,6 +58,7 @@ export function useAuth(): UseAuthReturn {
|
|
|
57
58
|
resendVerification: context.resendVerification,
|
|
58
59
|
forgotPassword: context.forgotPassword,
|
|
59
60
|
recoverPassword: context.recoverPassword,
|
|
61
|
+
changePassword: context.changePassword,
|
|
60
62
|
|
|
61
63
|
// Utilities
|
|
62
64
|
hasRole: context.hasRole,
|
package/src/index.ts
CHANGED
|
@@ -46,11 +46,17 @@ export type {
|
|
|
46
46
|
RefreshTokenResponse,
|
|
47
47
|
ResendVerificationRequest,
|
|
48
48
|
ResendVerificationResponse,
|
|
49
|
+
ChangePasswordRequest,
|
|
50
|
+
ChangePasswordResponse,
|
|
51
|
+
LogoutResponse,
|
|
49
52
|
|
|
50
53
|
// Error types
|
|
51
54
|
AuthError,
|
|
52
55
|
AuthErrorCode,
|
|
53
56
|
|
|
57
|
+
// Theme types
|
|
58
|
+
AuthTheme,
|
|
59
|
+
|
|
54
60
|
// Config types
|
|
55
61
|
AuthConfig,
|
|
56
62
|
AuthStorage,
|
|
@@ -64,6 +70,9 @@ export type {
|
|
|
64
70
|
PixygonAuthProps,
|
|
65
71
|
} from './types';
|
|
66
72
|
|
|
73
|
+
// Theme
|
|
74
|
+
export { DEFAULT_THEME } from './types';
|
|
75
|
+
|
|
67
76
|
// Provider
|
|
68
77
|
export { AuthProvider, AuthContext, useAuthContext } from './providers/AuthProvider';
|
|
69
78
|
export type { AuthProviderProps } from './providers/AuthProvider';
|
|
@@ -31,6 +31,8 @@ import type {
|
|
|
31
31
|
RecoverPasswordResponse,
|
|
32
32
|
ResendVerificationRequest,
|
|
33
33
|
ResendVerificationResponse,
|
|
34
|
+
ChangePasswordRequest,
|
|
35
|
+
ChangePasswordResponse,
|
|
34
36
|
} from '../types';
|
|
35
37
|
import { createTokenStorage } from '../utils/storage';
|
|
36
38
|
import { createAuthApiClient } from '../api/client';
|
|
@@ -368,9 +370,17 @@ export function AuthProvider({ config: userConfig, children }: AuthProviderProps
|
|
|
368
370
|
[apiClient]
|
|
369
371
|
);
|
|
370
372
|
|
|
373
|
+
const changePassword = useCallback(
|
|
374
|
+
async (data: ChangePasswordRequest): Promise<ChangePasswordResponse> => {
|
|
375
|
+
return apiClient.changePassword(data);
|
|
376
|
+
},
|
|
377
|
+
[apiClient]
|
|
378
|
+
);
|
|
379
|
+
|
|
371
380
|
const logout = useCallback(async (): Promise<void> => {
|
|
372
381
|
log('Logging out...');
|
|
373
382
|
|
|
383
|
+
await apiClient.logout();
|
|
374
384
|
await tokenStorage.clear();
|
|
375
385
|
apiClient.setAccessToken(null);
|
|
376
386
|
|
|
@@ -437,6 +447,7 @@ export function AuthProvider({ config: userConfig, children }: AuthProviderProps
|
|
|
437
447
|
resendVerification,
|
|
438
448
|
forgotPassword,
|
|
439
449
|
recoverPassword,
|
|
450
|
+
changePassword,
|
|
440
451
|
refreshTokens,
|
|
441
452
|
|
|
442
453
|
// Utilities
|
|
@@ -455,6 +466,7 @@ export function AuthProvider({ config: userConfig, children }: AuthProviderProps
|
|
|
455
466
|
resendVerification,
|
|
456
467
|
forgotPassword,
|
|
457
468
|
recoverPassword,
|
|
469
|
+
changePassword,
|
|
458
470
|
refreshTokens,
|
|
459
471
|
getAccessToken,
|
|
460
472
|
hasRole,
|
package/src/types/index.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
export type UserRole = 'user' | 'creator' | 'admin' | 'superadmin';
|
|
11
11
|
|
|
12
|
-
export type SubscriptionTier = 'free' | '
|
|
12
|
+
export type SubscriptionTier = 'free' | 'plus' | 'family' | 'basic' | 'pro' | 'enterprise';
|
|
13
13
|
|
|
14
14
|
export interface User {
|
|
15
15
|
_id: string;
|
|
@@ -164,6 +164,19 @@ export interface ResendVerificationResponse {
|
|
|
164
164
|
message: string;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
export interface ChangePasswordRequest {
|
|
168
|
+
currentPassword: string;
|
|
169
|
+
newPassword: string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface ChangePasswordResponse {
|
|
173
|
+
status: string;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface LogoutResponse {
|
|
177
|
+
status: string;
|
|
178
|
+
}
|
|
179
|
+
|
|
167
180
|
// ============================================================================
|
|
168
181
|
// Error Types
|
|
169
182
|
// ============================================================================
|
|
@@ -190,12 +203,40 @@ export interface AuthError {
|
|
|
190
203
|
details?: Record<string, unknown>;
|
|
191
204
|
}
|
|
192
205
|
|
|
206
|
+
// ============================================================================
|
|
207
|
+
// Theme Types
|
|
208
|
+
// ============================================================================
|
|
209
|
+
|
|
210
|
+
export interface AuthTheme {
|
|
211
|
+
primaryColor?: string; // Default: '#6366f1'
|
|
212
|
+
backgroundColor?: string; // Default: '#0f0f0f'
|
|
213
|
+
surfaceColor?: string; // Default: '#262626'
|
|
214
|
+
textColor?: string; // Default: '#ffffff'
|
|
215
|
+
textSecondary?: string; // Default: '#a3a3a3'
|
|
216
|
+
errorColor?: string; // Default: '#ef4444'
|
|
217
|
+
successColor?: string; // Default: '#22c55e'
|
|
218
|
+
borderRadius?: string; // Default: '1rem'
|
|
219
|
+
fontFamily?: string; // Default: inherit
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export const DEFAULT_THEME: Required<AuthTheme> = {
|
|
223
|
+
primaryColor: '#6366f1',
|
|
224
|
+
backgroundColor: '#0f0f0f',
|
|
225
|
+
surfaceColor: '#262626',
|
|
226
|
+
textColor: '#ffffff',
|
|
227
|
+
textSecondary: '#a3a3a3',
|
|
228
|
+
errorColor: '#ef4444',
|
|
229
|
+
successColor: '#22c55e',
|
|
230
|
+
borderRadius: '1rem',
|
|
231
|
+
fontFamily: 'inherit',
|
|
232
|
+
};
|
|
233
|
+
|
|
193
234
|
// ============================================================================
|
|
194
235
|
// Configuration Types
|
|
195
236
|
// ============================================================================
|
|
196
237
|
|
|
197
238
|
export interface AuthConfig {
|
|
198
|
-
/** Base URL for the auth API (e.g., https://pixygon
|
|
239
|
+
/** Base URL for the auth API (e.g., https://api.pixygon.com/v1) */
|
|
199
240
|
baseUrl: string;
|
|
200
241
|
|
|
201
242
|
/** App identifier for token storage keys */
|
|
@@ -227,6 +268,9 @@ export interface AuthConfig {
|
|
|
227
268
|
|
|
228
269
|
/** Enable debug logging (default: false) */
|
|
229
270
|
debug?: boolean;
|
|
271
|
+
|
|
272
|
+
/** Theme customization for branded components */
|
|
273
|
+
theme?: AuthTheme;
|
|
230
274
|
}
|
|
231
275
|
|
|
232
276
|
export interface AuthStorage {
|
|
@@ -248,6 +292,7 @@ export interface AuthContextValue extends AuthState {
|
|
|
248
292
|
resendVerification: (data: ResendVerificationRequest) => Promise<ResendVerificationResponse>;
|
|
249
293
|
forgotPassword: (data: ForgotPasswordRequest) => Promise<ForgotPasswordResponse>;
|
|
250
294
|
recoverPassword: (data: RecoverPasswordRequest) => Promise<RecoverPasswordResponse>;
|
|
295
|
+
changePassword: (data: ChangePasswordRequest) => Promise<ChangePasswordResponse>;
|
|
251
296
|
refreshTokens: () => Promise<void>;
|
|
252
297
|
|
|
253
298
|
// Utility
|
|
@@ -271,6 +316,7 @@ export interface LoginFormProps {
|
|
|
271
316
|
onNavigateForgotPassword?: () => void;
|
|
272
317
|
showBranding?: boolean;
|
|
273
318
|
className?: string;
|
|
319
|
+
theme?: AuthTheme;
|
|
274
320
|
}
|
|
275
321
|
|
|
276
322
|
export interface RegisterFormProps {
|
|
@@ -279,6 +325,7 @@ export interface RegisterFormProps {
|
|
|
279
325
|
onNavigateLogin?: () => void;
|
|
280
326
|
showBranding?: boolean;
|
|
281
327
|
className?: string;
|
|
328
|
+
theme?: AuthTheme;
|
|
282
329
|
}
|
|
283
330
|
|
|
284
331
|
export interface VerifyFormProps {
|
|
@@ -288,6 +335,7 @@ export interface VerifyFormProps {
|
|
|
288
335
|
onNavigateLogin?: () => void;
|
|
289
336
|
showBranding?: boolean;
|
|
290
337
|
className?: string;
|
|
338
|
+
theme?: AuthTheme;
|
|
291
339
|
}
|
|
292
340
|
|
|
293
341
|
export interface ForgotPasswordFormProps {
|
|
@@ -296,6 +344,7 @@ export interface ForgotPasswordFormProps {
|
|
|
296
344
|
onNavigateLogin?: () => void;
|
|
297
345
|
showBranding?: boolean;
|
|
298
346
|
className?: string;
|
|
347
|
+
theme?: AuthTheme;
|
|
299
348
|
}
|
|
300
349
|
|
|
301
350
|
export interface PixygonAuthProps {
|
package/src/utils/storage.ts
CHANGED
|
@@ -17,15 +17,27 @@ const getKeys = (appId: string) => ({
|
|
|
17
17
|
const defaultStorage: AuthStorage = {
|
|
18
18
|
getItem: (key: string) => {
|
|
19
19
|
if (typeof window === 'undefined') return null;
|
|
20
|
-
|
|
20
|
+
try {
|
|
21
|
+
return localStorage.getItem(key);
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
21
25
|
},
|
|
22
26
|
setItem: (key: string, value: string) => {
|
|
23
27
|
if (typeof window === 'undefined') return;
|
|
24
|
-
|
|
28
|
+
try {
|
|
29
|
+
localStorage.setItem(key, value);
|
|
30
|
+
} catch {
|
|
31
|
+
// Silently fail in private browsing
|
|
32
|
+
}
|
|
25
33
|
},
|
|
26
34
|
removeItem: (key: string) => {
|
|
27
35
|
if (typeof window === 'undefined') return;
|
|
28
|
-
|
|
36
|
+
try {
|
|
37
|
+
localStorage.removeItem(key);
|
|
38
|
+
} catch {
|
|
39
|
+
// Silently fail in private browsing
|
|
40
|
+
}
|
|
29
41
|
},
|
|
30
42
|
};
|
|
31
43
|
|