@drmhse/authos-react 0.1.5 → 0.2.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 CHANGED
@@ -363,7 +363,40 @@ export default async function Dashboard() {
363
363
 
364
364
  ## Styling
365
365
 
366
- All components use data attributes for styling hooks. Use CSS selectors:
366
+ AuthOS components come with **polished default styling** out of the box, similar to best-in-class auth providers. The styling is fully customizable via the `appearance` option or by overriding CSS variables.
367
+
368
+ ### Customization
369
+
370
+ You can customize the theme colors, fonts, and more by passing an `appearance` object to `AuthOSProvider`.
371
+
372
+ ```tsx
373
+ <AuthOSProvider config={{
374
+ baseURL: '...',
375
+ appearance: {
376
+ variables: {
377
+ colorPrimary: '#0066cc',
378
+ colorBackground: '#f5f5f5',
379
+ borderRadius: '0.25rem',
380
+ fontFamily: 'Inter, sans-serif',
381
+ },
382
+ },
383
+ }}>
384
+ ```
385
+
386
+ ### CSS Variables
387
+
388
+ You can also override these CSS variables in your own stylesheet:
389
+
390
+ ```css
391
+ :root {
392
+ --authos-color-primary: #0066cc;
393
+ --authos-border-radius: 4px;
394
+ }
395
+ ```
396
+
397
+ ### Headless Styling
398
+
399
+ If you prefer to completely style the components yourself, you can target the data attributes. The default styles have low specificity, so your CSS classes will easily override them.
367
400
 
368
401
  ```css
369
402
  [data-authos-signin] { /* Container */ }
package/dist/index.d.mts CHANGED
@@ -37,12 +37,76 @@ interface AuthOSConfig extends SsoClientOptions {
37
37
  * @example '/dashboard'
38
38
  */
39
39
  afterSignInUrl?: string;
40
+ /**
41
+ * URL to redirect to after successful sign-up.
42
+ * If not set, user stays on current page.
40
43
  /**
41
44
  * URL to redirect to after successful sign-up.
42
45
  * If not set, user stays on current page.
43
46
  * @example '/onboarding'
44
47
  */
45
48
  afterSignUpUrl?: string;
49
+ /**
50
+ * Appearance customization options.
51
+ * Use to override default theme colors, fonts, and styling.
52
+ * @example
53
+ * ```ts
54
+ * appearance: {
55
+ * variables: {
56
+ * colorPrimary: '#0066cc',
57
+ * borderRadius: '0.25rem',
58
+ * }
59
+ * }
60
+ * ```
61
+ */
62
+ appearance?: AppearanceOptions;
63
+ }
64
+ /**
65
+ * Appearance variables for customizing the visual theme.
66
+ * All properties are optional and use CSS color/size values.
67
+ */
68
+ interface AppearanceVariables {
69
+ /** Primary brand color (e.g., '#6366f1') */
70
+ colorPrimary?: string;
71
+ /** Primary color on hover */
72
+ colorPrimaryHover?: string;
73
+ /** Text color on primary background */
74
+ colorPrimaryForeground?: string;
75
+ /** Error/danger color */
76
+ colorDanger?: string;
77
+ /** Success color */
78
+ colorSuccess?: string;
79
+ /** Warning color */
80
+ colorWarning?: string;
81
+ /** Main background color */
82
+ colorBackground?: string;
83
+ /** Surface/card background color */
84
+ colorSurface?: string;
85
+ /** Main text color */
86
+ colorForeground?: string;
87
+ /** Muted/secondary text color */
88
+ colorMuted?: string;
89
+ /** Border color */
90
+ colorBorder?: string;
91
+ /** Input background color */
92
+ colorInput?: string;
93
+ /** Input border color */
94
+ colorInputBorder?: string;
95
+ /** Focus ring color */
96
+ colorRing?: string;
97
+ /** Font family */
98
+ fontFamily?: string;
99
+ /** Base font size */
100
+ fontSize?: string;
101
+ /** Border radius */
102
+ borderRadius?: string;
103
+ }
104
+ /**
105
+ * Appearance configuration for customizing component styling.
106
+ */
107
+ interface AppearanceOptions {
108
+ /** CSS variable overrides */
109
+ variables?: AppearanceVariables;
46
110
  }
47
111
  /**
48
112
  * Configuration options for the AuthOS React provider
package/dist/index.d.ts CHANGED
@@ -37,12 +37,76 @@ interface AuthOSConfig extends SsoClientOptions {
37
37
  * @example '/dashboard'
38
38
  */
39
39
  afterSignInUrl?: string;
40
+ /**
41
+ * URL to redirect to after successful sign-up.
42
+ * If not set, user stays on current page.
40
43
  /**
41
44
  * URL to redirect to after successful sign-up.
42
45
  * If not set, user stays on current page.
43
46
  * @example '/onboarding'
44
47
  */
45
48
  afterSignUpUrl?: string;
49
+ /**
50
+ * Appearance customization options.
51
+ * Use to override default theme colors, fonts, and styling.
52
+ * @example
53
+ * ```ts
54
+ * appearance: {
55
+ * variables: {
56
+ * colorPrimary: '#0066cc',
57
+ * borderRadius: '0.25rem',
58
+ * }
59
+ * }
60
+ * ```
61
+ */
62
+ appearance?: AppearanceOptions;
63
+ }
64
+ /**
65
+ * Appearance variables for customizing the visual theme.
66
+ * All properties are optional and use CSS color/size values.
67
+ */
68
+ interface AppearanceVariables {
69
+ /** Primary brand color (e.g., '#6366f1') */
70
+ colorPrimary?: string;
71
+ /** Primary color on hover */
72
+ colorPrimaryHover?: string;
73
+ /** Text color on primary background */
74
+ colorPrimaryForeground?: string;
75
+ /** Error/danger color */
76
+ colorDanger?: string;
77
+ /** Success color */
78
+ colorSuccess?: string;
79
+ /** Warning color */
80
+ colorWarning?: string;
81
+ /** Main background color */
82
+ colorBackground?: string;
83
+ /** Surface/card background color */
84
+ colorSurface?: string;
85
+ /** Main text color */
86
+ colorForeground?: string;
87
+ /** Muted/secondary text color */
88
+ colorMuted?: string;
89
+ /** Border color */
90
+ colorBorder?: string;
91
+ /** Input background color */
92
+ colorInput?: string;
93
+ /** Input border color */
94
+ colorInputBorder?: string;
95
+ /** Focus ring color */
96
+ colorRing?: string;
97
+ /** Font family */
98
+ fontFamily?: string;
99
+ /** Base font size */
100
+ fontSize?: string;
101
+ /** Border radius */
102
+ borderRadius?: string;
103
+ }
104
+ /**
105
+ * Appearance configuration for customizing component styling.
106
+ */
107
+ interface AppearanceOptions {
108
+ /** CSS variable overrides */
109
+ variables?: AppearanceVariables;
46
110
  }
47
111
  /**
48
112
  * Configuration options for the AuthOS React provider
package/dist/index.js CHANGED
@@ -5,6 +5,490 @@ var ssoSdk = require('@drmhse/sso-sdk');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
 
7
7
  // src/context.tsx
8
+
9
+ // src/styles.ts
10
+ var AUTHOS_STYLES = `
11
+ /* ==========================================================================
12
+ AuthOS Component Styles
13
+ CSS Variables + Default Theme
14
+ ========================================================================== */
15
+
16
+ :root {
17
+ /* Primary Colors */
18
+ --authos-color-primary: #6366f1;
19
+ --authos-color-primary-hover: #4f46e5;
20
+ --authos-color-primary-foreground: #ffffff;
21
+
22
+ /* Semantic Colors */
23
+ --authos-color-danger: #ef4444;
24
+ --authos-color-danger-foreground: #ffffff;
25
+ --authos-color-success: #22c55e;
26
+ --authos-color-warning: #f59e0b;
27
+
28
+ /* Surface Colors */
29
+ --authos-color-background: #ffffff;
30
+ --authos-color-surface: #ffffff;
31
+ --authos-color-foreground: #0f172a;
32
+ --authos-color-muted: #64748b;
33
+ --authos-color-muted-foreground: #64748b;
34
+
35
+ /* Component Colors */
36
+ --authos-color-border: #e2e8f0;
37
+ --authos-color-input: #ffffff;
38
+ --authos-color-input-border: #cbd5e1;
39
+ --authos-color-input-focus: #6366f1;
40
+ --authos-color-ring: rgba(99, 102, 241, 0.25);
41
+
42
+ /* Typography */
43
+ --authos-font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
44
+ --authos-font-size-xs: 0.75rem;
45
+ --authos-font-size-sm: 0.875rem;
46
+ --authos-font-size-base: 1rem;
47
+ --authos-font-size-lg: 1.125rem;
48
+
49
+ /* Spacing & Shape */
50
+ --authos-border-radius: 0.5rem;
51
+ --authos-border-radius-sm: 0.375rem;
52
+ --authos-border-radius-lg: 0.75rem;
53
+ --authos-spacing-xs: 0.25rem;
54
+ --authos-spacing-sm: 0.5rem;
55
+ --authos-spacing-md: 1rem;
56
+ --authos-spacing-lg: 1.5rem;
57
+
58
+ /* Shadows */
59
+ --authos-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
60
+ --authos-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
61
+ --authos-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
62
+
63
+ /* Transitions */
64
+ --authos-transition: 150ms cubic-bezier(0.4, 0, 0.2, 1);
65
+ }
66
+
67
+ /* Dark Mode */
68
+ @media (prefers-color-scheme: dark) {
69
+ :root {
70
+ --authos-color-primary: #818cf8;
71
+ --authos-color-primary-hover: #a5b4fc;
72
+
73
+ --authos-color-background: #0f172a;
74
+ --authos-color-surface: #1e293b;
75
+ --authos-color-foreground: #f1f5f9;
76
+ --authos-color-muted: #94a3b8;
77
+ --authos-color-muted-foreground: #94a3b8;
78
+
79
+ --authos-color-border: #334155;
80
+ --authos-color-input: #1e293b;
81
+ --authos-color-input-border: #475569;
82
+
83
+ --authos-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
84
+ --authos-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px -1px rgba(0, 0, 0, 0.3);
85
+ --authos-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -4px rgba(0, 0, 0, 0.3);
86
+ }
87
+ }
88
+
89
+ /* ==========================================================================
90
+ Base Form Styles
91
+ ========================================================================== */
92
+
93
+ [data-authos-signin],
94
+ [data-authos-signup],
95
+ [data-authos-magiclink],
96
+ [data-authos-passkey] {
97
+ font-family: var(--authos-font-family);
98
+ font-size: var(--authos-font-size-sm);
99
+ color: var(--authos-color-foreground);
100
+ width: 100%;
101
+ }
102
+
103
+ [data-authos-signin] form,
104
+ [data-authos-signup] form,
105
+ [data-authos-magiclink] form,
106
+ [data-authos-passkey] form {
107
+ display: flex;
108
+ flex-direction: column;
109
+ gap: var(--authos-spacing-md);
110
+ }
111
+
112
+ /* ==========================================================================
113
+ Field Styles
114
+ ========================================================================== */
115
+
116
+ [data-authos-field] {
117
+ display: flex;
118
+ flex-direction: column;
119
+ gap: var(--authos-spacing-xs);
120
+ }
121
+
122
+ [data-authos-field] label {
123
+ font-size: var(--authos-font-size-sm);
124
+ font-weight: 500;
125
+ color: var(--authos-color-foreground);
126
+ }
127
+
128
+ [data-authos-field] input {
129
+ width: 100%;
130
+ padding: 0.625rem 0.875rem;
131
+ font-size: var(--authos-font-size-sm);
132
+ font-family: inherit;
133
+ color: var(--authos-color-foreground);
134
+ background-color: var(--authos-color-input);
135
+ border: 1px solid var(--authos-color-input-border);
136
+ border-radius: var(--authos-border-radius);
137
+ outline: none;
138
+ transition: border-color var(--authos-transition), box-shadow var(--authos-transition);
139
+ }
140
+
141
+ [data-authos-field] input::placeholder {
142
+ color: var(--authos-color-muted);
143
+ }
144
+
145
+ [data-authos-field] input:focus {
146
+ border-color: var(--authos-color-input-focus);
147
+ box-shadow: 0 0 0 3px var(--authos-color-ring);
148
+ }
149
+
150
+ [data-authos-field] input:disabled {
151
+ opacity: 0.6;
152
+ cursor: not-allowed;
153
+ }
154
+
155
+ /* ==========================================================================
156
+ Button Styles
157
+ ========================================================================== */
158
+
159
+ [data-authos-submit] {
160
+ display: inline-flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+ gap: var(--authos-spacing-sm);
164
+ width: 100%;
165
+ padding: 0.625rem 1rem;
166
+ font-size: var(--authos-font-size-sm);
167
+ font-weight: 500;
168
+ font-family: inherit;
169
+ color: var(--authos-color-primary-foreground);
170
+ background-color: var(--authos-color-primary);
171
+ border: none;
172
+ border-radius: var(--authos-border-radius);
173
+ cursor: pointer;
174
+ outline: none;
175
+ transition: background-color var(--authos-transition), box-shadow var(--authos-transition);
176
+ }
177
+
178
+ [data-authos-submit]:hover:not(:disabled) {
179
+ background-color: var(--authos-color-primary-hover);
180
+ }
181
+
182
+ [data-authos-submit]:focus-visible {
183
+ box-shadow: 0 0 0 3px var(--authos-color-ring);
184
+ }
185
+
186
+ [data-authos-submit]:disabled {
187
+ opacity: 0.6;
188
+ cursor: not-allowed;
189
+ }
190
+
191
+ [data-authos-back] {
192
+ display: inline-flex;
193
+ align-items: center;
194
+ justify-content: center;
195
+ padding: 0.5rem 1rem;
196
+ font-size: var(--authos-font-size-sm);
197
+ font-weight: 500;
198
+ font-family: inherit;
199
+ color: var(--authos-color-muted);
200
+ background: transparent;
201
+ border: none;
202
+ border-radius: var(--authos-border-radius);
203
+ cursor: pointer;
204
+ transition: color var(--authos-transition);
205
+ }
206
+
207
+ [data-authos-back]:hover {
208
+ color: var(--authos-color-foreground);
209
+ }
210
+
211
+ /* ==========================================================================
212
+ OAuth Button Styles
213
+ ========================================================================== */
214
+
215
+ [data-authos-oauth] {
216
+ display: inline-flex;
217
+ align-items: center;
218
+ justify-content: center;
219
+ gap: 0.75rem;
220
+ width: 100%;
221
+ padding: 0.625rem 1rem;
222
+ font-size: var(--authos-font-size-sm);
223
+ font-weight: 500;
224
+ font-family: var(--authos-font-family);
225
+ color: var(--authos-color-foreground);
226
+ background-color: var(--authos-color-surface);
227
+ border: 1px solid var(--authos-color-border);
228
+ border-radius: var(--authos-border-radius);
229
+ cursor: pointer;
230
+ outline: none;
231
+ transition: background-color var(--authos-transition), border-color var(--authos-transition), box-shadow var(--authos-transition);
232
+ }
233
+
234
+ [data-authos-oauth]:hover:not(:disabled) {
235
+ background-color: var(--authos-color-background);
236
+ border-color: var(--authos-color-input-border);
237
+ }
238
+
239
+ [data-authos-oauth]:focus-visible {
240
+ box-shadow: 0 0 0 3px var(--authos-color-ring);
241
+ }
242
+
243
+ [data-authos-oauth]:disabled {
244
+ opacity: 0.6;
245
+ cursor: not-allowed;
246
+ }
247
+
248
+ [data-authos-oauth] svg {
249
+ width: 1.25rem;
250
+ height: 1.25rem;
251
+ flex-shrink: 0;
252
+ }
253
+
254
+ /* ==========================================================================
255
+ Divider Styles
256
+ ========================================================================== */
257
+
258
+ [data-authos-divider] {
259
+ display: flex;
260
+ align-items: center;
261
+ gap: var(--authos-spacing-md);
262
+ margin: var(--authos-spacing-sm) 0;
263
+ }
264
+
265
+ [data-authos-divider]::before,
266
+ [data-authos-divider]::after {
267
+ content: '';
268
+ flex: 1;
269
+ height: 1px;
270
+ background-color: var(--authos-color-border);
271
+ }
272
+
273
+ [data-authos-divider] span {
274
+ font-size: var(--authos-font-size-xs);
275
+ color: var(--authos-color-muted);
276
+ text-transform: uppercase;
277
+ letter-spacing: 0.05em;
278
+ }
279
+
280
+ /* ==========================================================================
281
+ Error Styles
282
+ ========================================================================== */
283
+
284
+ [data-authos-error] {
285
+ display: flex;
286
+ align-items: center;
287
+ gap: var(--authos-spacing-sm);
288
+ padding: 0.75rem 1rem;
289
+ font-size: var(--authos-font-size-sm);
290
+ color: var(--authos-color-danger);
291
+ background-color: rgba(239, 68, 68, 0.1);
292
+ border: 1px solid rgba(239, 68, 68, 0.2);
293
+ border-radius: var(--authos-border-radius);
294
+ }
295
+
296
+ /* ==========================================================================
297
+ Link Styles
298
+ ========================================================================== */
299
+
300
+ [data-authos-link] {
301
+ font-size: var(--authos-font-size-sm);
302
+ color: var(--authos-color-primary);
303
+ text-decoration: none;
304
+ transition: color var(--authos-transition);
305
+ }
306
+
307
+ [data-authos-link]:hover {
308
+ color: var(--authos-color-primary-hover);
309
+ text-decoration: underline;
310
+ }
311
+
312
+ [data-authos-signup-prompt],
313
+ [data-authos-signin-prompt] {
314
+ text-align: center;
315
+ font-size: var(--authos-font-size-sm);
316
+ color: var(--authos-color-muted);
317
+ margin-top: var(--authos-spacing-sm);
318
+ }
319
+
320
+ /* ==========================================================================
321
+ OAuth Section
322
+ ========================================================================== */
323
+
324
+ [data-authos-oauth-section] {
325
+ display: flex;
326
+ flex-direction: column;
327
+ gap: var(--authos-spacing-sm);
328
+ }
329
+
330
+ /* ==========================================================================
331
+ User Button Styles
332
+ ========================================================================== */
333
+
334
+ [data-authos-userbutton] {
335
+ position: relative;
336
+ display: inline-flex;
337
+ font-family: var(--authos-font-family);
338
+ font-size: var(--authos-font-size-sm);
339
+ color: var(--authos-color-foreground);
340
+ }
341
+
342
+ [data-authos-user-trigger] {
343
+ display: flex;
344
+ align-items: center;
345
+ gap: var(--authos-spacing-sm);
346
+ padding: 0;
347
+ background: transparent;
348
+ border: none;
349
+ cursor: pointer;
350
+ outline: none;
351
+ }
352
+
353
+ [data-authos-avatar] {
354
+ display: flex;
355
+ align-items: center;
356
+ justify-content: center;
357
+ width: 2rem;
358
+ height: 2rem;
359
+ font-size: var(--authos-font-size-xs);
360
+ font-weight: 600;
361
+ color: var(--authos-color-primary-foreground);
362
+ background-color: var(--authos-color-primary);
363
+ border-radius: 50%;
364
+ flex-shrink: 0;
365
+ }
366
+
367
+ [data-authos-user-menu] {
368
+ position: absolute;
369
+ top: 100%;
370
+ right: 0;
371
+ margin-top: var(--authos-spacing-sm);
372
+ width: 240px;
373
+ background-color: var(--authos-color-surface);
374
+ border: 1px solid var(--authos-color-border);
375
+ border-radius: var(--authos-border-radius);
376
+ box-shadow: var(--authos-shadow-lg);
377
+ z-index: 50;
378
+ overflow: hidden;
379
+ animation: authos-fade-in 150ms ease-out;
380
+ }
381
+
382
+ @keyframes authos-fade-in {
383
+ from { opacity: 0; transform: translateY(-4px); }
384
+ to { opacity: 1; transform: translateY(0); }
385
+ }
386
+
387
+ [data-authos-user-info] {
388
+ padding: var(--authos-spacing-md);
389
+ display: flex;
390
+ flex-direction: column;
391
+ gap: 0.25rem;
392
+ }
393
+
394
+ [data-authos-user-info] [data-authos-email] {
395
+ font-weight: 500;
396
+ color: var(--authos-color-foreground);
397
+ word-break: break-all;
398
+ }
399
+
400
+ [data-authos-badge] {
401
+ display: inline-flex;
402
+ align-self: flex-start;
403
+ padding: 0.125rem 0.375rem;
404
+ font-size: 0.7rem;
405
+ font-weight: 500;
406
+ color: var(--authos-color-primary);
407
+ background-color: rgba(99, 102, 241, 0.1);
408
+ border-radius: 9999px;
409
+ }
410
+
411
+ [data-authos-user-menu] [data-authos-logout] {
412
+ width: 100%;
413
+ text-align: left;
414
+ padding: 0.75rem 1rem;
415
+ font-size: var(--authos-font-size-sm);
416
+ color: var(--authos-color-danger);
417
+ background: transparent;
418
+ border: none;
419
+ border-top: 1px solid var(--authos-color-border);
420
+ cursor: pointer;
421
+ transition: background-color var(--authos-transition);
422
+ }
423
+
424
+ [data-authos-user-menu] [data-authos-logout]:hover {
425
+ background-color: rgba(239, 68, 68, 0.05);
426
+ }
427
+
428
+ /* ==========================================================================
429
+ Organization Switcher Styles
430
+ ========================================================================== */
431
+
432
+ [data-authos-orgswitcher] {
433
+ font-family: var(--authos-font-family);
434
+ font-size: var(--authos-font-size-sm);
435
+ }
436
+
437
+ [data-authos-orgswitcher] select {
438
+ padding: 0.5rem 2rem 0.5rem 0.75rem;
439
+ font-size: var(--authos-font-size-sm);
440
+ font-family: inherit;
441
+ color: var(--authos-color-foreground);
442
+ background-color: var(--authos-color-input);
443
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
444
+ background-repeat: no-repeat;
445
+ background-position: right 0.5rem center;
446
+ border: 1px solid var(--authos-color-input-border);
447
+ border-radius: var(--authos-border-radius);
448
+ cursor: pointer;
449
+ outline: none;
450
+ appearance: none;
451
+ -webkit-appearance: none;
452
+ -moz-appearance: none;
453
+ transition: border-color var(--authos-transition), box-shadow var(--authos-transition);
454
+ }
455
+
456
+ [data-authos-orgswitcher] select:focus {
457
+ border-color: var(--authos-color-input-focus);
458
+ box-shadow: 0 0 0 3px var(--authos-color-ring);
459
+ }
460
+
461
+ [data-authos-orgswitcher] select:disabled {
462
+ opacity: 0.6;
463
+ cursor: not-allowed;
464
+ }
465
+
466
+ /* ==========================================================================
467
+ Loading State
468
+ ========================================================================== */
469
+
470
+ [data-state="loading"] {
471
+ opacity: 0.6;
472
+ }
473
+ `;
474
+ var stylesInjected = false;
475
+ function injectStyles() {
476
+ if (stylesInjected) return;
477
+ if (typeof document === "undefined") return;
478
+ const styleElement = document.createElement("style");
479
+ styleElement.setAttribute("data-authos-styles", "");
480
+ styleElement.textContent = AUTHOS_STYLES;
481
+ document.head.appendChild(styleElement);
482
+ stylesInjected = true;
483
+ }
484
+ function applyVariables(variables) {
485
+ if (typeof document === "undefined") return;
486
+ const root = document.documentElement;
487
+ for (const [key, value] of Object.entries(variables)) {
488
+ const cssVar = `--authos-${key.replace(/([A-Z])/g, "-$1").toLowerCase()}`;
489
+ root.style.setProperty(cssVar, value);
490
+ }
491
+ }
8
492
  var AuthOSContext = react.createContext(null);
9
493
  function AuthOSProvider({ config, children, client: externalClient, initialSessionToken }) {
10
494
  const clientRef = react.useRef(null);
@@ -12,6 +496,12 @@ function AuthOSProvider({ config, children, client: externalClient, initialSessi
12
496
  clientRef.current = externalClient ?? new ssoSdk.SsoClient(config);
13
497
  }
14
498
  const client = clientRef.current;
499
+ react.useEffect(() => {
500
+ injectStyles();
501
+ if (config.appearance?.variables) {
502
+ applyVariables(config.appearance.variables);
503
+ }
504
+ }, [config.appearance]);
15
505
  const hasInitialToken = react.useRef(!!initialSessionToken);
16
506
  react.useEffect(() => {
17
507
  if (initialSessionToken && hasInitialToken.current) {
@@ -124,6 +614,26 @@ var PROVIDER_NAMES = {
124
614
  google: "Google",
125
615
  microsoft: "Microsoft"
126
616
  };
617
+ function getProviderIcon(provider) {
618
+ switch (provider) {
619
+ case "github":
620
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z" }) });
621
+ case "google":
622
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
623
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#4285F4", d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" }),
624
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#34A853", d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" }),
625
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#FBBC05", d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" }),
626
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#EA4335", d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" })
627
+ ] });
628
+ case "microsoft":
629
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 23 23", "aria-hidden": "true", children: [
630
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#f35325", d: "M1 1h10v10H1z" }),
631
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#81bc06", d: "M12 1h10v10H12z" }),
632
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#05a6f0", d: "M1 12h10v10H1z" }),
633
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#ffba08", d: "M12 12h10v10H12z" })
634
+ ] });
635
+ }
636
+ }
127
637
  function OAuthButton({
128
638
  provider,
129
639
  children,
@@ -167,7 +677,13 @@ See: https://docs.authos.dev/react/oauth-setup`
167
677
  disabled,
168
678
  "data-authos-oauth": "",
169
679
  "data-provider": provider,
170
- children: children ?? `Continue with ${PROVIDER_NAMES[provider]}`
680
+ children: children || /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
681
+ getProviderIcon(provider),
682
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
683
+ "Continue with ",
684
+ PROVIDER_NAMES[provider]
685
+ ] })
686
+ ] })
171
687
  }
172
688
  );
173
689
  }
@@ -553,33 +1069,33 @@ function UserButton({ className, showEmail = false, onLogout }) {
553
1069
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-authos-userbutton": true, "data-state": "signed-out", children: /* @__PURE__ */ jsxRuntime.jsx("span", { "data-authos-user-placeholder": true, children: "Not signed in" }) });
554
1070
  }
555
1071
  const initials = user.email.split("@")[0].split(".").map((part) => part[0]?.toUpperCase() ?? "").slice(0, 2).join("");
556
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-authos-userbutton": true, "data-state": isOpen ? "open" : "closed", children: [
1072
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-authos-userbutton": "", "data-state": isOpen ? "open" : "closed", children: [
557
1073
  /* @__PURE__ */ jsxRuntime.jsxs(
558
1074
  "button",
559
1075
  {
560
1076
  type: "button",
561
1077
  onClick: () => setIsOpen(!isOpen),
562
1078
  disabled: isLoggingOut,
563
- "data-authos-user-trigger": true,
1079
+ "data-authos-user-trigger": "",
564
1080
  children: [
565
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-authos-user-avatar": true, "aria-hidden": "true", children: initials }),
566
- showEmail && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-authos-user-email": true, children: user.email })
1081
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-authos-avatar": "", "aria-hidden": "true", children: initials }),
1082
+ showEmail && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-authos-email": "", children: user.email })
567
1083
  ]
568
1084
  }
569
1085
  ),
570
- isOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-user-menu": true, children: [
571
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-user-info": true, children: [
572
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-authos-user-email": true, children: user.email }),
573
- user.is_platform_owner && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-authos-user-badge": true, children: "Platform Owner" })
1086
+ isOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-user-menu": "", children: [
1087
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-user-info": "", children: [
1088
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-authos-email": "", children: user.email }),
1089
+ user.is_platform_owner && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-authos-badge": "", children: "Platform Owner" })
574
1090
  ] }),
575
- /* @__PURE__ */ jsxRuntime.jsx("hr", { "data-authos-divider": true }),
1091
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-authos-divider": "" }),
576
1092
  /* @__PURE__ */ jsxRuntime.jsx(
577
1093
  "button",
578
1094
  {
579
1095
  type: "button",
580
1096
  onClick: handleLogout,
581
1097
  disabled: isLoggingOut,
582
- "data-authos-logout": true,
1098
+ "data-authos-logout": "",
583
1099
  children: isLoggingOut ? "Signing out..." : "Sign out"
584
1100
  }
585
1101
  )
package/dist/index.mjs CHANGED
@@ -4,6 +4,490 @@ export { AuthErrorCodes, SsoApiError, SsoClient } from '@drmhse/sso-sdk';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
 
6
6
  // src/context.tsx
7
+
8
+ // src/styles.ts
9
+ var AUTHOS_STYLES = `
10
+ /* ==========================================================================
11
+ AuthOS Component Styles
12
+ CSS Variables + Default Theme
13
+ ========================================================================== */
14
+
15
+ :root {
16
+ /* Primary Colors */
17
+ --authos-color-primary: #6366f1;
18
+ --authos-color-primary-hover: #4f46e5;
19
+ --authos-color-primary-foreground: #ffffff;
20
+
21
+ /* Semantic Colors */
22
+ --authos-color-danger: #ef4444;
23
+ --authos-color-danger-foreground: #ffffff;
24
+ --authos-color-success: #22c55e;
25
+ --authos-color-warning: #f59e0b;
26
+
27
+ /* Surface Colors */
28
+ --authos-color-background: #ffffff;
29
+ --authos-color-surface: #ffffff;
30
+ --authos-color-foreground: #0f172a;
31
+ --authos-color-muted: #64748b;
32
+ --authos-color-muted-foreground: #64748b;
33
+
34
+ /* Component Colors */
35
+ --authos-color-border: #e2e8f0;
36
+ --authos-color-input: #ffffff;
37
+ --authos-color-input-border: #cbd5e1;
38
+ --authos-color-input-focus: #6366f1;
39
+ --authos-color-ring: rgba(99, 102, 241, 0.25);
40
+
41
+ /* Typography */
42
+ --authos-font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
43
+ --authos-font-size-xs: 0.75rem;
44
+ --authos-font-size-sm: 0.875rem;
45
+ --authos-font-size-base: 1rem;
46
+ --authos-font-size-lg: 1.125rem;
47
+
48
+ /* Spacing & Shape */
49
+ --authos-border-radius: 0.5rem;
50
+ --authos-border-radius-sm: 0.375rem;
51
+ --authos-border-radius-lg: 0.75rem;
52
+ --authos-spacing-xs: 0.25rem;
53
+ --authos-spacing-sm: 0.5rem;
54
+ --authos-spacing-md: 1rem;
55
+ --authos-spacing-lg: 1.5rem;
56
+
57
+ /* Shadows */
58
+ --authos-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
59
+ --authos-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
60
+ --authos-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
61
+
62
+ /* Transitions */
63
+ --authos-transition: 150ms cubic-bezier(0.4, 0, 0.2, 1);
64
+ }
65
+
66
+ /* Dark Mode */
67
+ @media (prefers-color-scheme: dark) {
68
+ :root {
69
+ --authos-color-primary: #818cf8;
70
+ --authos-color-primary-hover: #a5b4fc;
71
+
72
+ --authos-color-background: #0f172a;
73
+ --authos-color-surface: #1e293b;
74
+ --authos-color-foreground: #f1f5f9;
75
+ --authos-color-muted: #94a3b8;
76
+ --authos-color-muted-foreground: #94a3b8;
77
+
78
+ --authos-color-border: #334155;
79
+ --authos-color-input: #1e293b;
80
+ --authos-color-input-border: #475569;
81
+
82
+ --authos-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
83
+ --authos-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px -1px rgba(0, 0, 0, 0.3);
84
+ --authos-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -4px rgba(0, 0, 0, 0.3);
85
+ }
86
+ }
87
+
88
+ /* ==========================================================================
89
+ Base Form Styles
90
+ ========================================================================== */
91
+
92
+ [data-authos-signin],
93
+ [data-authos-signup],
94
+ [data-authos-magiclink],
95
+ [data-authos-passkey] {
96
+ font-family: var(--authos-font-family);
97
+ font-size: var(--authos-font-size-sm);
98
+ color: var(--authos-color-foreground);
99
+ width: 100%;
100
+ }
101
+
102
+ [data-authos-signin] form,
103
+ [data-authos-signup] form,
104
+ [data-authos-magiclink] form,
105
+ [data-authos-passkey] form {
106
+ display: flex;
107
+ flex-direction: column;
108
+ gap: var(--authos-spacing-md);
109
+ }
110
+
111
+ /* ==========================================================================
112
+ Field Styles
113
+ ========================================================================== */
114
+
115
+ [data-authos-field] {
116
+ display: flex;
117
+ flex-direction: column;
118
+ gap: var(--authos-spacing-xs);
119
+ }
120
+
121
+ [data-authos-field] label {
122
+ font-size: var(--authos-font-size-sm);
123
+ font-weight: 500;
124
+ color: var(--authos-color-foreground);
125
+ }
126
+
127
+ [data-authos-field] input {
128
+ width: 100%;
129
+ padding: 0.625rem 0.875rem;
130
+ font-size: var(--authos-font-size-sm);
131
+ font-family: inherit;
132
+ color: var(--authos-color-foreground);
133
+ background-color: var(--authos-color-input);
134
+ border: 1px solid var(--authos-color-input-border);
135
+ border-radius: var(--authos-border-radius);
136
+ outline: none;
137
+ transition: border-color var(--authos-transition), box-shadow var(--authos-transition);
138
+ }
139
+
140
+ [data-authos-field] input::placeholder {
141
+ color: var(--authos-color-muted);
142
+ }
143
+
144
+ [data-authos-field] input:focus {
145
+ border-color: var(--authos-color-input-focus);
146
+ box-shadow: 0 0 0 3px var(--authos-color-ring);
147
+ }
148
+
149
+ [data-authos-field] input:disabled {
150
+ opacity: 0.6;
151
+ cursor: not-allowed;
152
+ }
153
+
154
+ /* ==========================================================================
155
+ Button Styles
156
+ ========================================================================== */
157
+
158
+ [data-authos-submit] {
159
+ display: inline-flex;
160
+ align-items: center;
161
+ justify-content: center;
162
+ gap: var(--authos-spacing-sm);
163
+ width: 100%;
164
+ padding: 0.625rem 1rem;
165
+ font-size: var(--authos-font-size-sm);
166
+ font-weight: 500;
167
+ font-family: inherit;
168
+ color: var(--authos-color-primary-foreground);
169
+ background-color: var(--authos-color-primary);
170
+ border: none;
171
+ border-radius: var(--authos-border-radius);
172
+ cursor: pointer;
173
+ outline: none;
174
+ transition: background-color var(--authos-transition), box-shadow var(--authos-transition);
175
+ }
176
+
177
+ [data-authos-submit]:hover:not(:disabled) {
178
+ background-color: var(--authos-color-primary-hover);
179
+ }
180
+
181
+ [data-authos-submit]:focus-visible {
182
+ box-shadow: 0 0 0 3px var(--authos-color-ring);
183
+ }
184
+
185
+ [data-authos-submit]:disabled {
186
+ opacity: 0.6;
187
+ cursor: not-allowed;
188
+ }
189
+
190
+ [data-authos-back] {
191
+ display: inline-flex;
192
+ align-items: center;
193
+ justify-content: center;
194
+ padding: 0.5rem 1rem;
195
+ font-size: var(--authos-font-size-sm);
196
+ font-weight: 500;
197
+ font-family: inherit;
198
+ color: var(--authos-color-muted);
199
+ background: transparent;
200
+ border: none;
201
+ border-radius: var(--authos-border-radius);
202
+ cursor: pointer;
203
+ transition: color var(--authos-transition);
204
+ }
205
+
206
+ [data-authos-back]:hover {
207
+ color: var(--authos-color-foreground);
208
+ }
209
+
210
+ /* ==========================================================================
211
+ OAuth Button Styles
212
+ ========================================================================== */
213
+
214
+ [data-authos-oauth] {
215
+ display: inline-flex;
216
+ align-items: center;
217
+ justify-content: center;
218
+ gap: 0.75rem;
219
+ width: 100%;
220
+ padding: 0.625rem 1rem;
221
+ font-size: var(--authos-font-size-sm);
222
+ font-weight: 500;
223
+ font-family: var(--authos-font-family);
224
+ color: var(--authos-color-foreground);
225
+ background-color: var(--authos-color-surface);
226
+ border: 1px solid var(--authos-color-border);
227
+ border-radius: var(--authos-border-radius);
228
+ cursor: pointer;
229
+ outline: none;
230
+ transition: background-color var(--authos-transition), border-color var(--authos-transition), box-shadow var(--authos-transition);
231
+ }
232
+
233
+ [data-authos-oauth]:hover:not(:disabled) {
234
+ background-color: var(--authos-color-background);
235
+ border-color: var(--authos-color-input-border);
236
+ }
237
+
238
+ [data-authos-oauth]:focus-visible {
239
+ box-shadow: 0 0 0 3px var(--authos-color-ring);
240
+ }
241
+
242
+ [data-authos-oauth]:disabled {
243
+ opacity: 0.6;
244
+ cursor: not-allowed;
245
+ }
246
+
247
+ [data-authos-oauth] svg {
248
+ width: 1.25rem;
249
+ height: 1.25rem;
250
+ flex-shrink: 0;
251
+ }
252
+
253
+ /* ==========================================================================
254
+ Divider Styles
255
+ ========================================================================== */
256
+
257
+ [data-authos-divider] {
258
+ display: flex;
259
+ align-items: center;
260
+ gap: var(--authos-spacing-md);
261
+ margin: var(--authos-spacing-sm) 0;
262
+ }
263
+
264
+ [data-authos-divider]::before,
265
+ [data-authos-divider]::after {
266
+ content: '';
267
+ flex: 1;
268
+ height: 1px;
269
+ background-color: var(--authos-color-border);
270
+ }
271
+
272
+ [data-authos-divider] span {
273
+ font-size: var(--authos-font-size-xs);
274
+ color: var(--authos-color-muted);
275
+ text-transform: uppercase;
276
+ letter-spacing: 0.05em;
277
+ }
278
+
279
+ /* ==========================================================================
280
+ Error Styles
281
+ ========================================================================== */
282
+
283
+ [data-authos-error] {
284
+ display: flex;
285
+ align-items: center;
286
+ gap: var(--authos-spacing-sm);
287
+ padding: 0.75rem 1rem;
288
+ font-size: var(--authos-font-size-sm);
289
+ color: var(--authos-color-danger);
290
+ background-color: rgba(239, 68, 68, 0.1);
291
+ border: 1px solid rgba(239, 68, 68, 0.2);
292
+ border-radius: var(--authos-border-radius);
293
+ }
294
+
295
+ /* ==========================================================================
296
+ Link Styles
297
+ ========================================================================== */
298
+
299
+ [data-authos-link] {
300
+ font-size: var(--authos-font-size-sm);
301
+ color: var(--authos-color-primary);
302
+ text-decoration: none;
303
+ transition: color var(--authos-transition);
304
+ }
305
+
306
+ [data-authos-link]:hover {
307
+ color: var(--authos-color-primary-hover);
308
+ text-decoration: underline;
309
+ }
310
+
311
+ [data-authos-signup-prompt],
312
+ [data-authos-signin-prompt] {
313
+ text-align: center;
314
+ font-size: var(--authos-font-size-sm);
315
+ color: var(--authos-color-muted);
316
+ margin-top: var(--authos-spacing-sm);
317
+ }
318
+
319
+ /* ==========================================================================
320
+ OAuth Section
321
+ ========================================================================== */
322
+
323
+ [data-authos-oauth-section] {
324
+ display: flex;
325
+ flex-direction: column;
326
+ gap: var(--authos-spacing-sm);
327
+ }
328
+
329
+ /* ==========================================================================
330
+ User Button Styles
331
+ ========================================================================== */
332
+
333
+ [data-authos-userbutton] {
334
+ position: relative;
335
+ display: inline-flex;
336
+ font-family: var(--authos-font-family);
337
+ font-size: var(--authos-font-size-sm);
338
+ color: var(--authos-color-foreground);
339
+ }
340
+
341
+ [data-authos-user-trigger] {
342
+ display: flex;
343
+ align-items: center;
344
+ gap: var(--authos-spacing-sm);
345
+ padding: 0;
346
+ background: transparent;
347
+ border: none;
348
+ cursor: pointer;
349
+ outline: none;
350
+ }
351
+
352
+ [data-authos-avatar] {
353
+ display: flex;
354
+ align-items: center;
355
+ justify-content: center;
356
+ width: 2rem;
357
+ height: 2rem;
358
+ font-size: var(--authos-font-size-xs);
359
+ font-weight: 600;
360
+ color: var(--authos-color-primary-foreground);
361
+ background-color: var(--authos-color-primary);
362
+ border-radius: 50%;
363
+ flex-shrink: 0;
364
+ }
365
+
366
+ [data-authos-user-menu] {
367
+ position: absolute;
368
+ top: 100%;
369
+ right: 0;
370
+ margin-top: var(--authos-spacing-sm);
371
+ width: 240px;
372
+ background-color: var(--authos-color-surface);
373
+ border: 1px solid var(--authos-color-border);
374
+ border-radius: var(--authos-border-radius);
375
+ box-shadow: var(--authos-shadow-lg);
376
+ z-index: 50;
377
+ overflow: hidden;
378
+ animation: authos-fade-in 150ms ease-out;
379
+ }
380
+
381
+ @keyframes authos-fade-in {
382
+ from { opacity: 0; transform: translateY(-4px); }
383
+ to { opacity: 1; transform: translateY(0); }
384
+ }
385
+
386
+ [data-authos-user-info] {
387
+ padding: var(--authos-spacing-md);
388
+ display: flex;
389
+ flex-direction: column;
390
+ gap: 0.25rem;
391
+ }
392
+
393
+ [data-authos-user-info] [data-authos-email] {
394
+ font-weight: 500;
395
+ color: var(--authos-color-foreground);
396
+ word-break: break-all;
397
+ }
398
+
399
+ [data-authos-badge] {
400
+ display: inline-flex;
401
+ align-self: flex-start;
402
+ padding: 0.125rem 0.375rem;
403
+ font-size: 0.7rem;
404
+ font-weight: 500;
405
+ color: var(--authos-color-primary);
406
+ background-color: rgba(99, 102, 241, 0.1);
407
+ border-radius: 9999px;
408
+ }
409
+
410
+ [data-authos-user-menu] [data-authos-logout] {
411
+ width: 100%;
412
+ text-align: left;
413
+ padding: 0.75rem 1rem;
414
+ font-size: var(--authos-font-size-sm);
415
+ color: var(--authos-color-danger);
416
+ background: transparent;
417
+ border: none;
418
+ border-top: 1px solid var(--authos-color-border);
419
+ cursor: pointer;
420
+ transition: background-color var(--authos-transition);
421
+ }
422
+
423
+ [data-authos-user-menu] [data-authos-logout]:hover {
424
+ background-color: rgba(239, 68, 68, 0.05);
425
+ }
426
+
427
+ /* ==========================================================================
428
+ Organization Switcher Styles
429
+ ========================================================================== */
430
+
431
+ [data-authos-orgswitcher] {
432
+ font-family: var(--authos-font-family);
433
+ font-size: var(--authos-font-size-sm);
434
+ }
435
+
436
+ [data-authos-orgswitcher] select {
437
+ padding: 0.5rem 2rem 0.5rem 0.75rem;
438
+ font-size: var(--authos-font-size-sm);
439
+ font-family: inherit;
440
+ color: var(--authos-color-foreground);
441
+ background-color: var(--authos-color-input);
442
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
443
+ background-repeat: no-repeat;
444
+ background-position: right 0.5rem center;
445
+ border: 1px solid var(--authos-color-input-border);
446
+ border-radius: var(--authos-border-radius);
447
+ cursor: pointer;
448
+ outline: none;
449
+ appearance: none;
450
+ -webkit-appearance: none;
451
+ -moz-appearance: none;
452
+ transition: border-color var(--authos-transition), box-shadow var(--authos-transition);
453
+ }
454
+
455
+ [data-authos-orgswitcher] select:focus {
456
+ border-color: var(--authos-color-input-focus);
457
+ box-shadow: 0 0 0 3px var(--authos-color-ring);
458
+ }
459
+
460
+ [data-authos-orgswitcher] select:disabled {
461
+ opacity: 0.6;
462
+ cursor: not-allowed;
463
+ }
464
+
465
+ /* ==========================================================================
466
+ Loading State
467
+ ========================================================================== */
468
+
469
+ [data-state="loading"] {
470
+ opacity: 0.6;
471
+ }
472
+ `;
473
+ var stylesInjected = false;
474
+ function injectStyles() {
475
+ if (stylesInjected) return;
476
+ if (typeof document === "undefined") return;
477
+ const styleElement = document.createElement("style");
478
+ styleElement.setAttribute("data-authos-styles", "");
479
+ styleElement.textContent = AUTHOS_STYLES;
480
+ document.head.appendChild(styleElement);
481
+ stylesInjected = true;
482
+ }
483
+ function applyVariables(variables) {
484
+ if (typeof document === "undefined") return;
485
+ const root = document.documentElement;
486
+ for (const [key, value] of Object.entries(variables)) {
487
+ const cssVar = `--authos-${key.replace(/([A-Z])/g, "-$1").toLowerCase()}`;
488
+ root.style.setProperty(cssVar, value);
489
+ }
490
+ }
7
491
  var AuthOSContext = createContext(null);
8
492
  function AuthOSProvider({ config, children, client: externalClient, initialSessionToken }) {
9
493
  const clientRef = useRef(null);
@@ -11,6 +495,12 @@ function AuthOSProvider({ config, children, client: externalClient, initialSessi
11
495
  clientRef.current = externalClient ?? new SsoClient(config);
12
496
  }
13
497
  const client = clientRef.current;
498
+ useEffect(() => {
499
+ injectStyles();
500
+ if (config.appearance?.variables) {
501
+ applyVariables(config.appearance.variables);
502
+ }
503
+ }, [config.appearance]);
14
504
  const hasInitialToken = useRef(!!initialSessionToken);
15
505
  useEffect(() => {
16
506
  if (initialSessionToken && hasInitialToken.current) {
@@ -123,6 +613,26 @@ var PROVIDER_NAMES = {
123
613
  google: "Google",
124
614
  microsoft: "Microsoft"
125
615
  };
616
+ function getProviderIcon(provider) {
617
+ switch (provider) {
618
+ case "github":
619
+ return /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z" }) });
620
+ case "google":
621
+ return /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", "aria-hidden": "true", children: [
622
+ /* @__PURE__ */ jsx("path", { fill: "#4285F4", d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" }),
623
+ /* @__PURE__ */ jsx("path", { fill: "#34A853", d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" }),
624
+ /* @__PURE__ */ jsx("path", { fill: "#FBBC05", d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" }),
625
+ /* @__PURE__ */ jsx("path", { fill: "#EA4335", d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" })
626
+ ] });
627
+ case "microsoft":
628
+ return /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 23 23", "aria-hidden": "true", children: [
629
+ /* @__PURE__ */ jsx("path", { fill: "#f35325", d: "M1 1h10v10H1z" }),
630
+ /* @__PURE__ */ jsx("path", { fill: "#81bc06", d: "M12 1h10v10H12z" }),
631
+ /* @__PURE__ */ jsx("path", { fill: "#05a6f0", d: "M1 12h10v10H1z" }),
632
+ /* @__PURE__ */ jsx("path", { fill: "#ffba08", d: "M12 12h10v10H12z" })
633
+ ] });
634
+ }
635
+ }
126
636
  function OAuthButton({
127
637
  provider,
128
638
  children,
@@ -166,7 +676,13 @@ See: https://docs.authos.dev/react/oauth-setup`
166
676
  disabled,
167
677
  "data-authos-oauth": "",
168
678
  "data-provider": provider,
169
- children: children ?? `Continue with ${PROVIDER_NAMES[provider]}`
679
+ children: children || /* @__PURE__ */ jsxs(Fragment, { children: [
680
+ getProviderIcon(provider),
681
+ /* @__PURE__ */ jsxs("span", { children: [
682
+ "Continue with ",
683
+ PROVIDER_NAMES[provider]
684
+ ] })
685
+ ] })
170
686
  }
171
687
  );
172
688
  }
@@ -552,33 +1068,33 @@ function UserButton({ className, showEmail = false, onLogout }) {
552
1068
  return /* @__PURE__ */ jsx("div", { className, "data-authos-userbutton": true, "data-state": "signed-out", children: /* @__PURE__ */ jsx("span", { "data-authos-user-placeholder": true, children: "Not signed in" }) });
553
1069
  }
554
1070
  const initials = user.email.split("@")[0].split(".").map((part) => part[0]?.toUpperCase() ?? "").slice(0, 2).join("");
555
- return /* @__PURE__ */ jsxs("div", { className, "data-authos-userbutton": true, "data-state": isOpen ? "open" : "closed", children: [
1071
+ return /* @__PURE__ */ jsxs("div", { className, "data-authos-userbutton": "", "data-state": isOpen ? "open" : "closed", children: [
556
1072
  /* @__PURE__ */ jsxs(
557
1073
  "button",
558
1074
  {
559
1075
  type: "button",
560
1076
  onClick: () => setIsOpen(!isOpen),
561
1077
  disabled: isLoggingOut,
562
- "data-authos-user-trigger": true,
1078
+ "data-authos-user-trigger": "",
563
1079
  children: [
564
- /* @__PURE__ */ jsx("span", { "data-authos-user-avatar": true, "aria-hidden": "true", children: initials }),
565
- showEmail && /* @__PURE__ */ jsx("span", { "data-authos-user-email": true, children: user.email })
1080
+ /* @__PURE__ */ jsx("span", { "data-authos-avatar": "", "aria-hidden": "true", children: initials }),
1081
+ showEmail && /* @__PURE__ */ jsx("span", { "data-authos-email": "", children: user.email })
566
1082
  ]
567
1083
  }
568
1084
  ),
569
- isOpen && /* @__PURE__ */ jsxs("div", { "data-authos-user-menu": true, children: [
570
- /* @__PURE__ */ jsxs("div", { "data-authos-user-info": true, children: [
571
- /* @__PURE__ */ jsx("span", { "data-authos-user-email": true, children: user.email }),
572
- user.is_platform_owner && /* @__PURE__ */ jsx("span", { "data-authos-user-badge": true, children: "Platform Owner" })
1085
+ isOpen && /* @__PURE__ */ jsxs("div", { "data-authos-user-menu": "", children: [
1086
+ /* @__PURE__ */ jsxs("div", { "data-authos-user-info": "", children: [
1087
+ /* @__PURE__ */ jsx("span", { "data-authos-email": "", children: user.email }),
1088
+ user.is_platform_owner && /* @__PURE__ */ jsx("span", { "data-authos-badge": "", children: "Platform Owner" })
573
1089
  ] }),
574
- /* @__PURE__ */ jsx("hr", { "data-authos-divider": true }),
1090
+ /* @__PURE__ */ jsx("div", { "data-authos-divider": "" }),
575
1091
  /* @__PURE__ */ jsx(
576
1092
  "button",
577
1093
  {
578
1094
  type: "button",
579
1095
  onClick: handleLogout,
580
1096
  disabled: isLoggingOut,
581
- "data-authos-logout": true,
1097
+ "data-authos-logout": "",
582
1098
  children: isLoggingOut ? "Signing out..." : "Sign out"
583
1099
  }
584
1100
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drmhse/authos-react",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "description": "React and Next.js adapter for AuthOS authentication",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",