@emblemvault/emblem-auth-react 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,1146 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var emblemAuthSdk = require('emblem-auth-sdk');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ var globalSDKInstance = null;
8
+ var isSDKInitializing = false;
9
+ var EmblemAuthContext = react.createContext(void 0);
10
+ function EmblemAuthProvider({
11
+ children,
12
+ appId,
13
+ apiUrl,
14
+ modalUrl,
15
+ debug = false
16
+ }) {
17
+ const [session, setSession] = react.useState(null);
18
+ const [isAuthenticated, setIsAuthenticated] = react.useState(false);
19
+ const [isLoading, setIsLoading] = react.useState(false);
20
+ const [error, setError] = react.useState(null);
21
+ const [vaultInfo, setVaultInfo] = react.useState(null);
22
+ const [authSDK, setAuthSDK] = react.useState(globalSDKInstance);
23
+ const initialized = react.useRef(false);
24
+ const log = react.useCallback(
25
+ (message, ...args) => {
26
+ if (debug) {
27
+ console.log(`[EmblemAuth] ${message}`, ...args);
28
+ }
29
+ },
30
+ [debug]
31
+ );
32
+ const fetchVaultInfo = react.useCallback(
33
+ async (sdk) => {
34
+ try {
35
+ const info = await sdk.getVaultInfo();
36
+ if (info) {
37
+ setVaultInfo(info);
38
+ log("Vault info loaded:", info);
39
+ }
40
+ } catch (err) {
41
+ log("Failed to fetch vault info:", err);
42
+ }
43
+ },
44
+ [log]
45
+ );
46
+ const handleAuthSuccess = react.useCallback(
47
+ (newSession, sdk) => {
48
+ log("Auth success - session:", newSession);
49
+ setSession(newSession);
50
+ setIsAuthenticated(true);
51
+ setIsLoading(false);
52
+ setError(null);
53
+ fetchVaultInfo(sdk);
54
+ },
55
+ [log, fetchVaultInfo]
56
+ );
57
+ const handleAuthError = react.useCallback(
58
+ (err) => {
59
+ log("Auth error:", err);
60
+ setError(err);
61
+ setIsLoading(false);
62
+ setIsAuthenticated(false);
63
+ setSession(null);
64
+ },
65
+ [log]
66
+ );
67
+ const handleSessionExpired = react.useCallback(() => {
68
+ log("Session expired");
69
+ setSession(null);
70
+ setIsAuthenticated(false);
71
+ setVaultInfo(null);
72
+ }, [log]);
73
+ react.useEffect(() => {
74
+ if (initialized.current || globalSDKInstance || isSDKInitializing) {
75
+ if (globalSDKInstance && !authSDK) {
76
+ setAuthSDK(globalSDKInstance);
77
+ const existingSession2 = globalSDKInstance.getSession();
78
+ if (existingSession2) {
79
+ handleAuthSuccess(existingSession2, globalSDKInstance);
80
+ }
81
+ }
82
+ return;
83
+ }
84
+ initialized.current = true;
85
+ isSDKInitializing = true;
86
+ log("Initializing SDK with appId:", appId);
87
+ const sdk = new emblemAuthSdk.EmblemAuthSDK({
88
+ appId,
89
+ apiUrl,
90
+ modalUrl,
91
+ onSuccess: (newSession) => {
92
+ handleAuthSuccess(newSession, sdk);
93
+ },
94
+ onError: (err) => {
95
+ handleAuthError(err);
96
+ }
97
+ });
98
+ globalSDKInstance = sdk;
99
+ isSDKInitializing = false;
100
+ setAuthSDK(sdk);
101
+ const existingSession = sdk.getSession();
102
+ if (existingSession) {
103
+ log("Found existing session");
104
+ handleAuthSuccess(existingSession, sdk);
105
+ }
106
+ const handleSessionUpdate = (updatedSession) => {
107
+ if (updatedSession) {
108
+ setSession(updatedSession);
109
+ setIsAuthenticated(true);
110
+ } else {
111
+ handleSessionExpired();
112
+ }
113
+ };
114
+ sdk.on("session", handleSessionUpdate);
115
+ sdk.on("sessionExpired", handleSessionExpired);
116
+ return () => {
117
+ sdk.off("session", handleSessionUpdate);
118
+ sdk.off("sessionExpired", handleSessionExpired);
119
+ };
120
+ }, [appId, apiUrl, modalUrl, log, handleAuthSuccess, handleAuthError, handleSessionExpired, authSDK]);
121
+ const openAuthModal = react.useCallback(async () => {
122
+ if (!authSDK) {
123
+ setError(new Error("Auth SDK not initialized"));
124
+ return;
125
+ }
126
+ log("Opening auth modal");
127
+ setIsLoading(true);
128
+ setError(null);
129
+ try {
130
+ await authSDK.openAuthModal();
131
+ } catch (err) {
132
+ setIsLoading(false);
133
+ setError(err instanceof Error ? err : new Error("Failed to open auth modal"));
134
+ }
135
+ }, [authSDK, log]);
136
+ const logout = react.useCallback(() => {
137
+ if (!authSDK) return;
138
+ log("Logging out");
139
+ authSDK.logout();
140
+ setSession(null);
141
+ setIsAuthenticated(false);
142
+ setVaultInfo(null);
143
+ setError(null);
144
+ }, [authSDK, log]);
145
+ const refreshSession = react.useCallback(async () => {
146
+ if (!authSDK) return null;
147
+ log("Refreshing session");
148
+ try {
149
+ const refreshedSession = await authSDK.refreshSession();
150
+ if (refreshedSession) {
151
+ setSession(refreshedSession);
152
+ setIsAuthenticated(true);
153
+ return refreshedSession;
154
+ }
155
+ return null;
156
+ } catch (err) {
157
+ log("Failed to refresh session:", err);
158
+ setError(err instanceof Error ? err : new Error("Failed to refresh session"));
159
+ return null;
160
+ }
161
+ }, [authSDK, log]);
162
+ const vaultId = session?.user?.vaultId ?? null;
163
+ const walletAddress = session?.user?.evmAddress ?? null;
164
+ const value = {
165
+ // State
166
+ session,
167
+ isAuthenticated,
168
+ isLoading,
169
+ error,
170
+ vaultInfo,
171
+ // Derived
172
+ vaultId,
173
+ walletAddress,
174
+ // Actions
175
+ openAuthModal,
176
+ logout,
177
+ refreshSession,
178
+ // For Hustle integration
179
+ authSDK
180
+ };
181
+ return /* @__PURE__ */ jsxRuntime.jsx(EmblemAuthContext.Provider, { value, children });
182
+ }
183
+ function useEmblemAuth() {
184
+ const context = react.useContext(EmblemAuthContext);
185
+ if (context === void 0) {
186
+ throw new Error("useEmblemAuth must be used within an EmblemAuthProvider");
187
+ }
188
+ return context;
189
+ }
190
+ function useEmblemAuthOptional() {
191
+ const context = react.useContext(EmblemAuthContext);
192
+ return context ?? null;
193
+ }
194
+ function resetAuthSDK() {
195
+ globalSDKInstance = null;
196
+ isSDKInitializing = false;
197
+ }
198
+
199
+ // src/styles/tokens.ts
200
+ var defaults = {
201
+ colors: {
202
+ // Backgrounds
203
+ bgPrimary: "#0b0d10",
204
+ bgSecondary: "#12161b",
205
+ bgTertiary: "#1a1f25",
206
+ bgHover: "#252b33",
207
+ bgOverlay: "rgba(0, 0, 0, 0.7)",
208
+ // Borders
209
+ borderPrimary: "#222b35",
210
+ borderSecondary: "#333",
211
+ borderHover: "#444",
212
+ // Text
213
+ textPrimary: "#e6eef8",
214
+ textSecondary: "#8892a4",
215
+ textTertiary: "#6b7280",
216
+ textInverse: "#fff",
217
+ // Accent - Primary (blue)
218
+ accentPrimary: "#4c9aff",
219
+ accentPrimaryHover: "#7bb6ff",
220
+ accentPrimaryBg: "rgba(76, 154, 255, 0.1)",
221
+ // Accent - Success (green)
222
+ accentSuccess: "#10b981",
223
+ accentSuccessHover: "#34d399",
224
+ accentSuccessBg: "rgba(16, 185, 129, 0.1)",
225
+ // Accent - Warning (yellow/orange)
226
+ accentWarning: "#f59e0b",
227
+ accentWarningBg: "rgba(245, 158, 11, 0.1)",
228
+ // Accent - Error (red)
229
+ accentError: "#dc2626",
230
+ accentErrorHover: "#ef4444",
231
+ accentErrorBg: "rgba(239, 68, 68, 0.1)",
232
+ // Messages
233
+ msgUser: "#1e3a5f",
234
+ msgAssistant: "#1a2633"
235
+ },
236
+ typography: {
237
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
238
+ fontFamilyMono: '"SF Mono", Monaco, monospace',
239
+ fontSizeXs: "11px",
240
+ fontSizeSm: "13px",
241
+ fontSizeMd: "14px",
242
+ fontSizeLg: "16px",
243
+ fontSizeXl: "18px",
244
+ fontWeightNormal: "400",
245
+ fontWeightMedium: "500",
246
+ fontWeightSemibold: "600",
247
+ lineHeightTight: "1.3",
248
+ lineHeightNormal: "1.5",
249
+ lineHeightRelaxed: "1.7"
250
+ },
251
+ spacing: {
252
+ xs: "4px",
253
+ sm: "8px",
254
+ md: "12px",
255
+ lg: "16px",
256
+ xl: "20px",
257
+ xxl: "24px"
258
+ },
259
+ radius: {
260
+ sm: "4px",
261
+ md: "6px",
262
+ lg: "8px",
263
+ xl: "12px",
264
+ pill: "20px",
265
+ full: "50%"
266
+ },
267
+ shadows: {
268
+ sm: "0 2px 8px rgba(0,0,0,0.2)",
269
+ md: "0 4px 16px rgba(0,0,0,0.3)",
270
+ lg: "0 8px 32px rgba(0,0,0,0.4)",
271
+ xl: "0 16px 48px rgba(0,0,0,0.5)"
272
+ },
273
+ // Glow effects (for enhanced themes)
274
+ glows: {
275
+ primary: "rgba(76, 154, 255, 0.4)",
276
+ success: "rgba(16, 185, 129, 0.4)",
277
+ error: "rgba(239, 68, 68, 0.4)",
278
+ ambient: "rgba(76, 154, 255, 0.08)"
279
+ },
280
+ transitions: {
281
+ fast: "0.15s ease",
282
+ normal: "0.2s ease",
283
+ slow: "0.3s ease"
284
+ },
285
+ zIndex: {
286
+ dropdown: "100",
287
+ modal: "1000",
288
+ fullscreen: "1000",
289
+ modalOverFullscreen: "10000"
290
+ }
291
+ };
292
+ function toVarName(category, key) {
293
+ const kebab = key.replace(/([A-Z])/g, "-$1").toLowerCase();
294
+ return `--hustle-${category}-${kebab}`;
295
+ }
296
+ function generateCSSVariables() {
297
+ const lines = [":root {"];
298
+ for (const [key, value] of Object.entries(defaults.colors)) {
299
+ lines.push(` ${toVarName("color", key)}: ${value};`);
300
+ }
301
+ for (const [key, value] of Object.entries(defaults.typography)) {
302
+ lines.push(` ${toVarName("font", key)}: ${value};`);
303
+ }
304
+ for (const [key, value] of Object.entries(defaults.spacing)) {
305
+ lines.push(` ${toVarName("space", key)}: ${value};`);
306
+ }
307
+ for (const [key, value] of Object.entries(defaults.radius)) {
308
+ lines.push(` ${toVarName("radius", key)}: ${value};`);
309
+ }
310
+ for (const [key, value] of Object.entries(defaults.shadows)) {
311
+ lines.push(` ${toVarName("shadow", key)}: ${value};`);
312
+ }
313
+ for (const [key, value] of Object.entries(defaults.glows)) {
314
+ lines.push(` ${toVarName("glow", key)}: ${value};`);
315
+ }
316
+ for (const [key, value] of Object.entries(defaults.transitions)) {
317
+ lines.push(` ${toVarName("transition", key)}: ${value};`);
318
+ }
319
+ for (const [key, value] of Object.entries(defaults.zIndex)) {
320
+ lines.push(` ${toVarName("z", key)}: ${value};`);
321
+ }
322
+ lines.push("}");
323
+ return lines.join("\n");
324
+ }
325
+ generateCSSVariables();
326
+ function createColorTokens() {
327
+ const result = {};
328
+ for (const [key, defaultValue] of Object.entries(defaults.colors)) {
329
+ result[key] = `var(${toVarName("color", key)}, ${defaultValue})`;
330
+ }
331
+ return result;
332
+ }
333
+ function createTypographyTokens() {
334
+ const result = {};
335
+ for (const [key, defaultValue] of Object.entries(defaults.typography)) {
336
+ result[key] = `var(${toVarName("font", key)}, ${defaultValue})`;
337
+ }
338
+ return result;
339
+ }
340
+ function createSpacingTokens() {
341
+ const result = {};
342
+ for (const [key, defaultValue] of Object.entries(defaults.spacing)) {
343
+ result[key] = `var(${toVarName("space", key)}, ${defaultValue})`;
344
+ }
345
+ return result;
346
+ }
347
+ function createRadiusTokens() {
348
+ const result = {};
349
+ for (const [key, defaultValue] of Object.entries(defaults.radius)) {
350
+ result[key] = `var(${toVarName("radius", key)}, ${defaultValue})`;
351
+ }
352
+ return result;
353
+ }
354
+ function createShadowTokens() {
355
+ const result = {};
356
+ for (const [key, defaultValue] of Object.entries(defaults.shadows)) {
357
+ result[key] = `var(${toVarName("shadow", key)}, ${defaultValue})`;
358
+ }
359
+ return result;
360
+ }
361
+ function createGlowTokens() {
362
+ const result = {};
363
+ for (const [key, defaultValue] of Object.entries(defaults.glows)) {
364
+ result[key] = `var(${toVarName("glow", key)}, ${defaultValue})`;
365
+ }
366
+ return result;
367
+ }
368
+ function createTransitionTokens() {
369
+ const result = {};
370
+ for (const [key, defaultValue] of Object.entries(defaults.transitions)) {
371
+ result[key] = `var(${toVarName("transition", key)}, ${defaultValue})`;
372
+ }
373
+ return result;
374
+ }
375
+ function createZIndexTokens() {
376
+ const result = {};
377
+ for (const [key, defaultValue] of Object.entries(defaults.zIndex)) {
378
+ result[key] = parseInt(defaultValue, 10);
379
+ }
380
+ return result;
381
+ }
382
+ var tokens = {
383
+ colors: createColorTokens(),
384
+ typography: createTypographyTokens(),
385
+ spacing: createSpacingTokens(),
386
+ radius: createRadiusTokens(),
387
+ shadows: createShadowTokens(),
388
+ glows: createGlowTokens(),
389
+ transitions: createTransitionTokens(),
390
+ zIndex: createZIndexTokens()
391
+ };
392
+ var presets = {
393
+ base: {
394
+ fontFamily: tokens.typography.fontFamily,
395
+ fontSize: tokens.typography.fontSizeMd,
396
+ lineHeight: tokens.typography.lineHeightNormal,
397
+ color: tokens.colors.textPrimary
398
+ },
399
+ card: {
400
+ background: tokens.colors.bgSecondary,
401
+ border: `1px solid ${tokens.colors.borderPrimary}`,
402
+ borderRadius: tokens.radius.xl
403
+ },
404
+ input: {
405
+ background: tokens.colors.bgTertiary,
406
+ border: `1px solid ${tokens.colors.borderSecondary}`,
407
+ borderRadius: tokens.radius.lg,
408
+ color: tokens.colors.textPrimary,
409
+ fontSize: tokens.typography.fontSizeMd,
410
+ padding: `${tokens.spacing.md} ${tokens.spacing.lg}`,
411
+ transition: `border-color ${tokens.transitions.normal}`
412
+ },
413
+ button: {
414
+ display: "inline-flex",
415
+ alignItems: "center",
416
+ justifyContent: "center",
417
+ gap: tokens.spacing.sm,
418
+ padding: `${tokens.spacing.sm} ${tokens.spacing.lg}`,
419
+ borderRadius: tokens.radius.lg,
420
+ fontSize: tokens.typography.fontSizeMd,
421
+ fontWeight: tokens.typography.fontWeightMedium,
422
+ cursor: "pointer",
423
+ transition: `all ${tokens.transitions.normal}`,
424
+ border: `1px solid ${tokens.colors.borderSecondary}`,
425
+ outline: "none"
426
+ },
427
+ buttonPrimary: {
428
+ background: tokens.colors.accentPrimary,
429
+ color: tokens.colors.textInverse,
430
+ borderColor: tokens.colors.accentPrimary
431
+ },
432
+ buttonSecondary: {
433
+ background: tokens.colors.bgTertiary,
434
+ color: tokens.colors.textPrimary,
435
+ borderColor: tokens.colors.borderSecondary
436
+ },
437
+ buttonIcon: {
438
+ width: "36px",
439
+ height: "36px",
440
+ padding: 0,
441
+ // background inherited from global button styles
442
+ color: tokens.colors.textSecondary
443
+ },
444
+ mono: {
445
+ fontFamily: tokens.typography.fontFamilyMono,
446
+ fontSize: tokens.typography.fontSizeSm
447
+ },
448
+ label: {
449
+ fontSize: tokens.typography.fontSizeXs,
450
+ color: tokens.colors.textTertiary,
451
+ marginBottom: tokens.spacing.xs
452
+ }
453
+ };
454
+ var animations = `
455
+ @keyframes hustle-spin {
456
+ to { transform: rotate(360deg); }
457
+ }
458
+ @keyframes hustle-pulse {
459
+ 0%, 100% { opacity: 1; }
460
+ 50% { opacity: 0.5; }
461
+ }
462
+ @keyframes hustle-glow {
463
+ 0%, 100% {
464
+ opacity: 1;
465
+ text-shadow: 0 0 4px ${defaults.colors.accentPrimaryBg};
466
+ }
467
+ 50% {
468
+ opacity: 0.6;
469
+ text-shadow: 0 0 8px ${defaults.colors.accentPrimary};
470
+ }
471
+ }
472
+ `;
473
+ function truncateAddress(address) {
474
+ if (!address || address.length < 10) return address || "";
475
+ return `${address.slice(0, 6)}...${address.slice(-4)}`;
476
+ }
477
+ async function copyToClipboard(text) {
478
+ try {
479
+ await navigator.clipboard.writeText(text);
480
+ return true;
481
+ } catch {
482
+ return false;
483
+ }
484
+ }
485
+ var styles = {
486
+ wrapper: {
487
+ position: "relative",
488
+ display: "inline-flex",
489
+ alignItems: "center",
490
+ gap: tokens.spacing.sm
491
+ },
492
+ button: {
493
+ ...presets.button,
494
+ padding: `${tokens.spacing.sm} ${tokens.spacing.xl}`
495
+ },
496
+ disconnected: {
497
+ background: tokens.colors.bgTertiary,
498
+ color: tokens.colors.textPrimary,
499
+ borderColor: tokens.colors.borderSecondary
500
+ },
501
+ disconnectedHover: {
502
+ background: tokens.colors.bgHover,
503
+ borderColor: tokens.colors.borderHover
504
+ },
505
+ connected: {
506
+ background: "transparent",
507
+ color: tokens.colors.accentSuccess,
508
+ borderColor: tokens.colors.accentSuccess,
509
+ borderRadius: tokens.radius.pill
510
+ },
511
+ connectedHover: {
512
+ background: tokens.colors.accentSuccessBg
513
+ },
514
+ loading: {
515
+ background: tokens.colors.borderSecondary,
516
+ color: tokens.colors.textSecondary,
517
+ cursor: "wait"
518
+ },
519
+ disabled: {
520
+ background: tokens.colors.borderSecondary,
521
+ color: tokens.colors.textTertiary,
522
+ cursor: "not-allowed",
523
+ opacity: 0.5
524
+ },
525
+ icon: {
526
+ fontSize: tokens.typography.fontSizeLg
527
+ },
528
+ spinner: {
529
+ display: "inline-block",
530
+ width: "14px",
531
+ height: "14px",
532
+ border: "2px solid currentColor",
533
+ borderTopColor: "transparent",
534
+ borderRadius: tokens.radius.full,
535
+ animation: "hustle-spin 0.8s linear infinite"
536
+ },
537
+ address: {
538
+ ...presets.mono,
539
+ color: tokens.colors.textPrimary
540
+ },
541
+ dot: {
542
+ color: tokens.colors.textSecondary
543
+ },
544
+ check: {
545
+ color: tokens.colors.accentSuccess
546
+ },
547
+ arrow: {
548
+ fontSize: "10px",
549
+ color: tokens.colors.textSecondary,
550
+ marginLeft: tokens.spacing.xs
551
+ },
552
+ // Disconnect button
553
+ disconnectBtn: {
554
+ display: "flex",
555
+ alignItems: "center",
556
+ justifyContent: "center",
557
+ width: "36px",
558
+ height: "36px",
559
+ background: "transparent",
560
+ border: `1px solid ${tokens.colors.borderSecondary}`,
561
+ borderRadius: tokens.radius.lg,
562
+ color: tokens.colors.textSecondary,
563
+ cursor: "pointer",
564
+ fontSize: "16px",
565
+ transition: `all ${tokens.transitions.normal}`
566
+ },
567
+ disconnectBtnHover: {
568
+ borderColor: tokens.colors.accentError,
569
+ color: tokens.colors.accentError
570
+ },
571
+ // Vault info dropdown
572
+ dropdown: {
573
+ position: "absolute",
574
+ top: "100%",
575
+ left: 0,
576
+ marginTop: tokens.spacing.xs,
577
+ background: tokens.colors.bgPrimary,
578
+ border: `1px solid ${tokens.colors.accentSuccess}`,
579
+ borderRadius: tokens.radius.xl,
580
+ padding: tokens.spacing.lg,
581
+ minWidth: "300px",
582
+ zIndex: tokens.zIndex.dropdown,
583
+ boxShadow: `0 8px 32px rgba(0,0,0,0.4), 0 0 0 1px ${tokens.colors.accentSuccessBg}`
584
+ },
585
+ dropdownHeader: {
586
+ fontSize: tokens.typography.fontSizeXs,
587
+ fontWeight: tokens.typography.fontWeightSemibold,
588
+ color: tokens.colors.textSecondary,
589
+ letterSpacing: "0.5px",
590
+ marginBottom: tokens.spacing.lg,
591
+ textTransform: "uppercase"
592
+ },
593
+ dropdownRow: {
594
+ marginBottom: tokens.spacing.md
595
+ },
596
+ dropdownLabel: {
597
+ display: "block",
598
+ fontSize: tokens.typography.fontSizeXs,
599
+ color: tokens.colors.textTertiary,
600
+ marginBottom: tokens.spacing.xs
601
+ },
602
+ dropdownValueRow: {
603
+ display: "flex",
604
+ alignItems: "center",
605
+ justifyContent: "space-between",
606
+ gap: tokens.spacing.sm
607
+ },
608
+ dropdownValue: {
609
+ fontSize: tokens.typography.fontSizeMd,
610
+ color: tokens.colors.textPrimary,
611
+ fontWeight: tokens.typography.fontWeightMedium,
612
+ flex: 1
613
+ },
614
+ dropdownValueMono: {
615
+ ...presets.mono,
616
+ wordBreak: "break-all"
617
+ },
618
+ copyBtn: {
619
+ background: "transparent",
620
+ border: `1px solid ${tokens.colors.borderSecondary}`,
621
+ color: tokens.colors.textSecondary,
622
+ padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`,
623
+ borderRadius: tokens.radius.sm,
624
+ cursor: "pointer",
625
+ fontSize: tokens.typography.fontSizeXs,
626
+ transition: `all ${tokens.transitions.normal}`,
627
+ whiteSpace: "nowrap"
628
+ },
629
+ copyBtnHover: {
630
+ background: tokens.colors.bgHover,
631
+ borderColor: tokens.colors.accentPrimary,
632
+ color: tokens.colors.accentPrimary
633
+ },
634
+ copyBtnCopied: {
635
+ background: tokens.colors.accentSuccess,
636
+ borderColor: tokens.colors.accentSuccess,
637
+ color: tokens.colors.textInverse
638
+ }
639
+ };
640
+ function ConnectButton({
641
+ className = "",
642
+ style,
643
+ connectLabel = "Connect",
644
+ loadingLabel = "Connecting...",
645
+ onConnect,
646
+ onDisconnect,
647
+ showVaultInfo = true,
648
+ disabled = false
649
+ }) {
650
+ const {
651
+ isAuthenticated,
652
+ isLoading,
653
+ walletAddress,
654
+ vaultId,
655
+ openAuthModal,
656
+ logout
657
+ } = useEmblemAuth();
658
+ const [isHovered, setIsHovered] = react.useState(false);
659
+ const [showDropdown, setShowDropdown] = react.useState(false);
660
+ const [disconnectHovered, setDisconnectHovered] = react.useState(false);
661
+ const [copiedField, setCopiedField] = react.useState(null);
662
+ const [copyHovered, setCopyHovered] = react.useState(null);
663
+ const handleClick = react.useCallback(async () => {
664
+ if (disabled) return;
665
+ if (!isAuthenticated && !isLoading) {
666
+ await openAuthModal();
667
+ onConnect?.();
668
+ }
669
+ }, [disabled, isAuthenticated, isLoading, openAuthModal, onConnect]);
670
+ const handleDisconnect = react.useCallback(() => {
671
+ logout();
672
+ onDisconnect?.();
673
+ setShowDropdown(false);
674
+ }, [logout, onDisconnect]);
675
+ const handleCopy = react.useCallback(async (field, value) => {
676
+ const success = await copyToClipboard(value);
677
+ if (success) {
678
+ setCopiedField(field);
679
+ setTimeout(() => setCopiedField(null), 1500);
680
+ }
681
+ }, []);
682
+ let buttonStyle = { ...styles.button };
683
+ let content = connectLabel;
684
+ if (disabled) {
685
+ buttonStyle = { ...buttonStyle, ...styles.disconnected, ...styles.disabled };
686
+ } else if (isLoading) {
687
+ buttonStyle = { ...buttonStyle, ...styles.disconnected, ...styles.loading };
688
+ content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
689
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.spinner }),
690
+ loadingLabel
691
+ ] });
692
+ } else if (isAuthenticated) {
693
+ buttonStyle = { ...buttonStyle, ...styles.connected };
694
+ if (isHovered || showDropdown) {
695
+ buttonStyle = { ...buttonStyle, ...styles.connectedHover };
696
+ }
697
+ const truncated = truncateAddress(walletAddress || "");
698
+ content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
699
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.check, children: "\u2713" }),
700
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Connected" }),
701
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.dot, children: "\u2022" }),
702
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.address, children: truncated }),
703
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.arrow, children: "\u25BE" })
704
+ ] });
705
+ } else {
706
+ buttonStyle = { ...buttonStyle, ...styles.disconnected };
707
+ if (isHovered) {
708
+ buttonStyle = { ...buttonStyle, ...styles.disconnectedHover };
709
+ }
710
+ content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
711
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.icon, children: "\u2192" }),
712
+ connectLabel
713
+ ] });
714
+ }
715
+ if (style) {
716
+ buttonStyle = { ...buttonStyle, ...style };
717
+ }
718
+ const renderCopyBtn = (field, value) => {
719
+ const isCopied = copiedField === field;
720
+ const isHover = copyHovered === field;
721
+ return /* @__PURE__ */ jsxRuntime.jsx(
722
+ "button",
723
+ {
724
+ type: "button",
725
+ onClick: (e) => {
726
+ e.stopPropagation();
727
+ handleCopy(field, value);
728
+ },
729
+ style: {
730
+ ...styles.copyBtn,
731
+ ...isCopied ? styles.copyBtnCopied : isHover ? styles.copyBtnHover : {}
732
+ },
733
+ onMouseEnter: () => setCopyHovered(field),
734
+ onMouseLeave: () => setCopyHovered(null),
735
+ children: isCopied ? "Copied!" : "Copy"
736
+ }
737
+ );
738
+ };
739
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
740
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: animations }),
741
+ /* @__PURE__ */ jsxRuntime.jsxs(
742
+ "div",
743
+ {
744
+ style: styles.wrapper,
745
+ onMouseEnter: () => isAuthenticated && showVaultInfo && setShowDropdown(true),
746
+ onMouseLeave: () => setShowDropdown(false),
747
+ children: [
748
+ /* @__PURE__ */ jsxRuntime.jsx(
749
+ "button",
750
+ {
751
+ type: "button",
752
+ onClick: handleClick,
753
+ disabled: disabled || isLoading,
754
+ className,
755
+ style: buttonStyle,
756
+ onMouseEnter: () => setIsHovered(true),
757
+ onMouseLeave: () => setIsHovered(false),
758
+ children: content
759
+ }
760
+ ),
761
+ isAuthenticated && /* @__PURE__ */ jsxRuntime.jsx(
762
+ "button",
763
+ {
764
+ type: "button",
765
+ onClick: handleDisconnect,
766
+ style: {
767
+ ...styles.disconnectBtn,
768
+ ...disconnectHovered ? styles.disconnectBtnHover : {}
769
+ },
770
+ onMouseEnter: () => setDisconnectHovered(true),
771
+ onMouseLeave: () => setDisconnectHovered(false),
772
+ title: "Disconnect",
773
+ children: "\u23FB"
774
+ }
775
+ ),
776
+ isAuthenticated && showVaultInfo && showDropdown && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.dropdown, children: [
777
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.dropdownHeader, children: "Vault Information" }),
778
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.dropdownRow, children: [
779
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.dropdownLabel, children: "Vault ID" }),
780
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.dropdownValueRow, children: [
781
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles.dropdownValue, children: [
782
+ "#",
783
+ vaultId
784
+ ] }),
785
+ renderCopyBtn("vaultId", vaultId || "")
786
+ ] })
787
+ ] }),
788
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles.dropdownRow, marginBottom: 0 }, children: [
789
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.dropdownLabel, children: "Connected Wallet" }),
790
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.dropdownValueRow, children: [
791
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...styles.dropdownValue, ...styles.dropdownValueMono }, children: walletAddress }),
792
+ renderCopyBtn("wallet", walletAddress || "")
793
+ ] })
794
+ ] })
795
+ ] })
796
+ ]
797
+ }
798
+ )
799
+ ] });
800
+ }
801
+ async function copyToClipboard2(text) {
802
+ try {
803
+ await navigator.clipboard.writeText(text);
804
+ return true;
805
+ } catch {
806
+ return false;
807
+ }
808
+ }
809
+ var s = {
810
+ container: {
811
+ position: "relative",
812
+ display: "inline-flex",
813
+ alignItems: "center",
814
+ gap: tokens.spacing.sm,
815
+ fontFamily: tokens.typography.fontFamily
816
+ },
817
+ disconnected: {
818
+ display: "inline-flex",
819
+ alignItems: "center",
820
+ gap: tokens.spacing.sm,
821
+ color: tokens.colors.textSecondary,
822
+ fontSize: tokens.typography.fontSizeMd
823
+ },
824
+ dot: {
825
+ display: "inline-block",
826
+ width: "8px",
827
+ height: "8px",
828
+ borderRadius: tokens.radius.full,
829
+ backgroundColor: tokens.colors.textTertiary
830
+ },
831
+ dotConnected: {
832
+ backgroundColor: tokens.colors.accentSuccess
833
+ },
834
+ spinner: {
835
+ display: "inline-block",
836
+ width: "12px",
837
+ height: "12px",
838
+ border: `2px solid ${tokens.colors.textSecondary}`,
839
+ borderTopColor: "transparent",
840
+ borderRadius: tokens.radius.full,
841
+ animation: "hustle-spin 0.8s linear infinite"
842
+ },
843
+ logoutBtn: {
844
+ ...presets.buttonIcon,
845
+ border: `1px solid ${tokens.colors.borderSecondary}`,
846
+ borderRadius: tokens.radius.lg,
847
+ transition: `all ${tokens.transitions.normal}`
848
+ },
849
+ logoutBtnHover: {
850
+ borderColor: tokens.colors.accentError,
851
+ color: tokens.colors.accentError
852
+ },
853
+ vaultInfoWrapper: {
854
+ position: "relative"
855
+ },
856
+ vaultInfo: {
857
+ position: "absolute",
858
+ top: "100%",
859
+ right: 0,
860
+ marginTop: tokens.spacing.sm,
861
+ background: tokens.colors.bgSecondary,
862
+ border: `1px solid ${tokens.colors.borderPrimary}`,
863
+ borderRadius: tokens.radius.xl,
864
+ padding: tokens.spacing.lg,
865
+ minWidth: "380px",
866
+ zIndex: tokens.zIndex.dropdown,
867
+ boxShadow: tokens.shadows.lg
868
+ },
869
+ vaultInfoHeader: {
870
+ fontSize: tokens.typography.fontSizeXs,
871
+ fontWeight: tokens.typography.fontWeightSemibold,
872
+ color: tokens.colors.textSecondary,
873
+ letterSpacing: "0.5px",
874
+ marginBottom: tokens.spacing.lg,
875
+ textTransform: "uppercase"
876
+ },
877
+ vaultInfoRow: {
878
+ marginBottom: tokens.spacing.md
879
+ },
880
+ vaultLabel: {
881
+ display: "block",
882
+ fontSize: "12px",
883
+ color: tokens.colors.textTertiary,
884
+ marginBottom: tokens.spacing.xs
885
+ },
886
+ vaultValueRow: {
887
+ display: "flex",
888
+ alignItems: "center",
889
+ justifyContent: "space-between",
890
+ gap: tokens.spacing.sm
891
+ },
892
+ vaultValue: {
893
+ fontSize: tokens.typography.fontSizeMd,
894
+ color: tokens.colors.textPrimary,
895
+ fontWeight: tokens.typography.fontWeightMedium,
896
+ flex: 1
897
+ },
898
+ vaultValueMono: {
899
+ ...presets.mono,
900
+ wordBreak: "break-all"
901
+ },
902
+ copyBtn: {
903
+ background: "transparent",
904
+ border: `1px solid ${tokens.colors.borderSecondary}`,
905
+ color: tokens.colors.textSecondary,
906
+ padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`,
907
+ borderRadius: tokens.radius.sm,
908
+ cursor: "pointer",
909
+ fontSize: tokens.typography.fontSizeXs,
910
+ transition: `all ${tokens.transitions.normal}`,
911
+ whiteSpace: "nowrap"
912
+ },
913
+ copyBtnHover: {
914
+ background: tokens.colors.bgHover,
915
+ borderColor: tokens.colors.accentPrimary,
916
+ color: tokens.colors.accentPrimary
917
+ },
918
+ copyBtnCopied: {
919
+ background: tokens.colors.accentSuccess,
920
+ borderColor: tokens.colors.accentSuccess,
921
+ color: tokens.colors.textInverse
922
+ }
923
+ };
924
+ function AuthStatus({
925
+ className = "",
926
+ style,
927
+ showVaultInfo = false,
928
+ showLogout = false
929
+ }) {
930
+ const {
931
+ isAuthenticated,
932
+ isLoading,
933
+ walletAddress,
934
+ vaultId,
935
+ vaultInfo,
936
+ logout
937
+ } = useEmblemAuth();
938
+ const [isHovered, setIsHovered] = react.useState(false);
939
+ const [logoutHovered, setLogoutHovered] = react.useState(false);
940
+ const [copiedField, setCopiedField] = react.useState(null);
941
+ const [copyHovered, setCopyHovered] = react.useState(null);
942
+ const handleCopy = react.useCallback(async (field, value) => {
943
+ const success = await copyToClipboard2(value);
944
+ if (success) {
945
+ setCopiedField(field);
946
+ setTimeout(() => setCopiedField(null), 1500);
947
+ }
948
+ }, []);
949
+ if (!isAuthenticated) {
950
+ if (isLoading) {
951
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
952
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: animations }),
953
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...s.disconnected, ...style }, children: [
954
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: s.spinner }),
955
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Connecting..." })
956
+ ] })
957
+ ] });
958
+ }
959
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...s.disconnected, ...style }, children: [
960
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: s.dot }),
961
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Not connected" })
962
+ ] });
963
+ }
964
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
965
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: animations }),
966
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...s.container, ...style }, children: [
967
+ /* @__PURE__ */ jsxRuntime.jsxs(
968
+ "div",
969
+ {
970
+ style: s.vaultInfoWrapper,
971
+ onMouseEnter: () => showVaultInfo && setIsHovered(true),
972
+ onMouseLeave: () => showVaultInfo && setIsHovered(false),
973
+ children: [
974
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...s.dot, ...s.dotConnected }, title: "Connected" }),
975
+ showVaultInfo && isHovered && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: s.vaultInfo, children: [
976
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: s.vaultInfoHeader, children: "Vault Information" }),
977
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: s.vaultInfoRow, children: [
978
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: s.vaultLabel, children: "Vault ID" }),
979
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: s.vaultValueRow, children: [
980
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: s.vaultValue, children: [
981
+ "#",
982
+ vaultId
983
+ ] }),
984
+ /* @__PURE__ */ jsxRuntime.jsx(
985
+ CopyButton,
986
+ {
987
+ field: "vaultId",
988
+ value: vaultId || "",
989
+ copiedField,
990
+ copyHovered,
991
+ setCopyHovered,
992
+ onCopy: handleCopy
993
+ }
994
+ )
995
+ ] })
996
+ ] }),
997
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: s.vaultInfoRow, children: [
998
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: s.vaultLabel, children: "Connected Wallet" }),
999
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: s.vaultValueRow, children: [
1000
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...s.vaultValue, ...s.vaultValueMono }, children: walletAddress }),
1001
+ /* @__PURE__ */ jsxRuntime.jsx(
1002
+ CopyButton,
1003
+ {
1004
+ field: "wallet",
1005
+ value: walletAddress || "",
1006
+ copiedField,
1007
+ copyHovered,
1008
+ setCopyHovered,
1009
+ onCopy: handleCopy
1010
+ }
1011
+ )
1012
+ ] })
1013
+ ] }),
1014
+ vaultInfo?.evmAddress && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: s.vaultInfoRow, children: [
1015
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: s.vaultLabel, children: "Vault EVM Address" }),
1016
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: s.vaultValueRow, children: [
1017
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...s.vaultValue, ...s.vaultValueMono }, children: vaultInfo.evmAddress }),
1018
+ /* @__PURE__ */ jsxRuntime.jsx(
1019
+ CopyButton,
1020
+ {
1021
+ field: "evmAddress",
1022
+ value: vaultInfo.evmAddress,
1023
+ copiedField,
1024
+ copyHovered,
1025
+ setCopyHovered,
1026
+ onCopy: handleCopy
1027
+ }
1028
+ )
1029
+ ] })
1030
+ ] }),
1031
+ vaultInfo?.solanaAddress && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: s.vaultInfoRow, children: [
1032
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: s.vaultLabel, children: "Vault Solana Address" }),
1033
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: s.vaultValueRow, children: [
1034
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...s.vaultValue, ...s.vaultValueMono }, children: vaultInfo.solanaAddress }),
1035
+ /* @__PURE__ */ jsxRuntime.jsx(
1036
+ CopyButton,
1037
+ {
1038
+ field: "solAddress",
1039
+ value: vaultInfo.solanaAddress,
1040
+ copiedField,
1041
+ copyHovered,
1042
+ setCopyHovered,
1043
+ onCopy: handleCopy
1044
+ }
1045
+ )
1046
+ ] })
1047
+ ] })
1048
+ ] })
1049
+ ]
1050
+ }
1051
+ ),
1052
+ showLogout && /* @__PURE__ */ jsxRuntime.jsx(
1053
+ "button",
1054
+ {
1055
+ type: "button",
1056
+ onClick: logout,
1057
+ style: {
1058
+ ...s.logoutBtn,
1059
+ ...logoutHovered ? s.logoutBtnHover : {}
1060
+ },
1061
+ onMouseEnter: () => setLogoutHovered(true),
1062
+ onMouseLeave: () => setLogoutHovered(false),
1063
+ title: "Disconnect",
1064
+ children: "\u23FB"
1065
+ }
1066
+ )
1067
+ ] })
1068
+ ] });
1069
+ }
1070
+ function CopyButton({ field, value, copiedField, copyHovered, setCopyHovered, onCopy }) {
1071
+ const isCopied = copiedField === field;
1072
+ const isHovered = copyHovered === field;
1073
+ return /* @__PURE__ */ jsxRuntime.jsx(
1074
+ "button",
1075
+ {
1076
+ type: "button",
1077
+ onClick: () => onCopy(field, value),
1078
+ style: {
1079
+ ...s.copyBtn,
1080
+ ...isCopied ? s.copyBtnCopied : isHovered ? s.copyBtnHover : {}
1081
+ },
1082
+ onMouseEnter: () => setCopyHovered(field),
1083
+ onMouseLeave: () => setCopyHovered(null),
1084
+ children: isCopied ? "Copied!" : "Copy"
1085
+ }
1086
+ );
1087
+ }
1088
+
1089
+ // src/utils/index.ts
1090
+ function truncateAddress2(address, startChars = 6, endChars = 4) {
1091
+ if (!address) return "";
1092
+ if (address.length <= startChars + endChars) return address;
1093
+ return `${address.slice(0, startChars)}...${address.slice(-endChars)}`;
1094
+ }
1095
+ async function copyToClipboard3(text) {
1096
+ try {
1097
+ await navigator.clipboard.writeText(text);
1098
+ return true;
1099
+ } catch {
1100
+ try {
1101
+ const textarea = document.createElement("textarea");
1102
+ textarea.value = text;
1103
+ textarea.style.position = "fixed";
1104
+ textarea.style.opacity = "0";
1105
+ document.body.appendChild(textarea);
1106
+ textarea.select();
1107
+ const success = document.execCommand("copy");
1108
+ document.body.removeChild(textarea);
1109
+ return success;
1110
+ } catch {
1111
+ return false;
1112
+ }
1113
+ }
1114
+ }
1115
+ function generateId(prefix = "id") {
1116
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
1117
+ }
1118
+ function decodeJwtPayload(token) {
1119
+ try {
1120
+ const parts = token.split(".");
1121
+ if (parts.length !== 3) return null;
1122
+ const payload = JSON.parse(atob(parts[1]));
1123
+ return payload;
1124
+ } catch {
1125
+ return null;
1126
+ }
1127
+ }
1128
+ function isJwtExpired(token) {
1129
+ const payload = decodeJwtPayload(token);
1130
+ if (!payload || typeof payload.exp !== "number") return true;
1131
+ return Date.now() >= payload.exp * 1e3;
1132
+ }
1133
+
1134
+ exports.AuthStatus = AuthStatus;
1135
+ exports.ConnectButton = ConnectButton;
1136
+ exports.EmblemAuthProvider = EmblemAuthProvider;
1137
+ exports.copyToClipboard = copyToClipboard3;
1138
+ exports.decodeJwtPayload = decodeJwtPayload;
1139
+ exports.generateId = generateId;
1140
+ exports.isJwtExpired = isJwtExpired;
1141
+ exports.resetAuthSDK = resetAuthSDK;
1142
+ exports.truncateAddress = truncateAddress2;
1143
+ exports.useEmblemAuth = useEmblemAuth;
1144
+ exports.useEmblemAuthOptional = useEmblemAuthOptional;
1145
+ //# sourceMappingURL=index.cjs.map
1146
+ //# sourceMappingURL=index.cjs.map