shogun-button-react 1.3.2 → 1.3.5

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/CHANGELOG.md ADDED
@@ -0,0 +1,54 @@
1
+ # Changelog
2
+
3
+ ## Version 1.3.4 (Latest)
4
+
5
+ ### 🐛 Bug Fixes
6
+ - **Export Gun Pair Fix**: Fixed issue where "Export Pair" option was not accessible from user dropdown - now works correctly without requiring disconnect
7
+ - **Modal Logic Improvement**: Enhanced modal rendering logic to allow export functionality when user is already authenticated
8
+ - **UX Enhancement**: Improved back button behavior in export modal - now properly closes modal when user is logged in instead of showing unnecessary auth options
9
+
10
+ ### 🔧 Technical Changes
11
+ - Modified component render logic to show modal even when user is logged in
12
+ - Improved export form navigation for better user experience
13
+ - Reordered dropdown menu items for better flow (Export Pair before Disconnect)
14
+
15
+ ## Version 1.3.3
16
+
17
+ ### ✨ New Features
18
+ - **Import Gun Pair Login**: Aggiunta possibilità di effettuare login tramite importazione di un Gun pair esistente
19
+ - **Export Gun Pair**: Funzionalità per esportare il proprio Gun pair con opzione di crittografia tramite password
20
+ - **Improved UX**: Migliorata l'interfaccia utente con feedback visivi e messaggi informativi
21
+
22
+ ### 🔧 Improvements
23
+ - **Navigation Fix**: Il toggle "Don't have account? Sign up" ora porta alla selezione dei metodi di autenticazione invece che direttamente al form password
24
+ - **Visual Feedback**: Sostituiti gli alert con feedback visivi eleganti per export/import
25
+ - **Better Icons**: Aggiunte icone SVG personalizzate per import/export
26
+ - **Auto-copy**: L'export del pair viene automaticamente copiato negli appunti (quando supportato dal browser)
27
+ - **Enhanced Security**: Messaggi informativi per guidare l'utente nell'uso sicuro delle funzionalità
28
+
29
+ ### 🛠 Technical Changes
30
+ - Rimosso l'uso del metodo `on` non disponibile in ShogunCore
31
+ - Definiti tipi locali per `AuthResult` per compatibilità
32
+ - Migliorata gestione degli stati nel provider
33
+ - Aggiunto reset completo degli stati quando si chiude il modal
34
+
35
+ ### 🎨 UI/UX Enhancements
36
+ - Box informativi colorati per import/export
37
+ - Feedback di successo con timer automatico
38
+ - Indicatori di caricamento migliorati
39
+ - Messaggi di fallback per browser senza supporto clipboard
40
+
41
+ ## Version 1.3.2
42
+
43
+ ### Features
44
+ - Basic Gun pair export/import functionality
45
+ - Multi-authentication support (Password, MetaMask, WebAuthn, Nostr, OAuth)
46
+ - Dark mode support
47
+ - Responsive design
48
+
49
+ ## Version 1.3.1
50
+
51
+ ### Features
52
+ - Initial release
53
+ - Basic authentication flow
54
+ - Provider integration
@@ -34,39 +34,17 @@ export function ShogunButtonProvider({ children, sdk, options, onLoginSuccess, o
34
34
  var _a, _b;
35
35
  if (!sdk)
36
36
  return;
37
- const handleLogin = (authResult) => {
38
- var _a, _b;
39
- const pub = authResult.pub || ((_b = (_a = sdk.gun.user()) === null || _a === void 0 ? void 0 : _a.is) === null || _b === void 0 ? void 0 : _b.pub);
40
- if (pub) {
41
- setIsLoggedIn(true);
42
- setUserPub(pub);
43
- setUsername(authResult.alias || pub.slice(0, 8) + '...');
44
- if (onLoginSuccess && authResult.method !== 'recall') {
45
- onLoginSuccess({
46
- userPub: pub,
47
- username: authResult.alias || pub.slice(0, 8) + '...',
48
- authMethod: authResult.method,
49
- });
50
- }
51
- }
52
- };
53
- const handleLogout = () => {
54
- setIsLoggedIn(false);
55
- setUserPub(null);
56
- setUsername(null);
57
- };
37
+ // Verifichiamo se l'utente è già loggato all'inizializzazione
58
38
  if (sdk.isLoggedIn()) {
59
39
  const pub = (_b = (_a = sdk.gun.user()) === null || _a === void 0 ? void 0 : _a.is) === null || _b === void 0 ? void 0 : _b.pub;
60
40
  if (pub) {
61
- handleLogin({ pub, method: 'recall' });
41
+ setIsLoggedIn(true);
42
+ setUserPub(pub);
43
+ setUsername(pub.slice(0, 8) + '...');
62
44
  }
63
45
  }
64
- sdk.on('auth:login', handleLogin);
65
- sdk.on('auth:logout', handleLogout);
66
- return () => {
67
- sdk.off('auth:login', handleLogin);
68
- sdk.off('auth:logout', handleLogout);
69
- };
46
+ // Poiché il metodo 'on' non esiste su ShogunCore,
47
+ // gestiamo gli stati direttamente nei metodi di login/logout
70
48
  }, [sdk, onLoginSuccess]);
71
49
  // RxJS observe method
72
50
  const observe = (path) => {
@@ -77,6 +55,7 @@ export function ShogunButtonProvider({ children, sdk, options, onLoginSuccess, o
77
55
  };
78
56
  // Unified login
79
57
  const login = async (method, ...args) => {
58
+ var _a, _b;
80
59
  try {
81
60
  if (!sdk) {
82
61
  throw new Error("SDK not initialized");
@@ -161,12 +140,14 @@ export function ShogunButtonProvider({ children, sdk, options, onLoginSuccess, o
161
140
  throw new Error("Unsupported login method");
162
141
  }
163
142
  if (result.success) {
143
+ const userPub = result.userPub || ((_b = (_a = sdk.gun.user()) === null || _a === void 0 ? void 0 : _a.is) === null || _b === void 0 ? void 0 : _b.pub) || "";
144
+ const displayName = result.alias || username || userPub.slice(0, 8) + '...';
164
145
  setIsLoggedIn(true);
165
- setUserPub(result.userPub || "");
166
- setUsername(username || "");
146
+ setUserPub(userPub);
147
+ setUsername(displayName);
167
148
  onLoginSuccess === null || onLoginSuccess === void 0 ? void 0 : onLoginSuccess({
168
- userPub: result.userPub || "",
169
- username: username || "",
149
+ userPub: userPub,
150
+ username: displayName,
170
151
  authMethod: authMethod,
171
152
  });
172
153
  }
@@ -182,6 +163,7 @@ export function ShogunButtonProvider({ children, sdk, options, onLoginSuccess, o
182
163
  };
183
164
  // Unified signup
184
165
  const signUp = async (method, ...args) => {
166
+ var _a, _b;
185
167
  try {
186
168
  if (!sdk) {
187
169
  throw new Error("SDK not initialized");
@@ -244,13 +226,14 @@ export function ShogunButtonProvider({ children, sdk, options, onLoginSuccess, o
244
226
  throw new Error("Unsupported signup method");
245
227
  }
246
228
  if (result.success) {
229
+ const userPub = result.userPub || ((_b = (_a = sdk.gun.user()) === null || _a === void 0 ? void 0 : _a.is) === null || _b === void 0 ? void 0 : _b.pub) || "";
230
+ const displayName = result.alias || username || userPub.slice(0, 8) + '...';
247
231
  setIsLoggedIn(true);
248
- const userPub = result.userPub || "";
249
232
  setUserPub(userPub);
250
- setUsername(username || "");
233
+ setUsername(displayName);
251
234
  onSignupSuccess === null || onSignupSuccess === void 0 ? void 0 : onSignupSuccess({
252
235
  userPub: userPub,
253
- username: username || "",
236
+ username: displayName,
254
237
  authMethod: authMethod,
255
238
  });
256
239
  }
@@ -270,6 +253,9 @@ export function ShogunButtonProvider({ children, sdk, options, onLoginSuccess, o
270
253
  setIsLoggedIn(false);
271
254
  setUserPub(null);
272
255
  setUsername(null);
256
+ sessionStorage.removeItem("gun/pair");
257
+ sessionStorage.removeItem("gun/session");
258
+ sessionStorage.removeItem("pair");
273
259
  };
274
260
  // Implementazione del metodo setProvider
275
261
  const setProvider = (provider) => {
@@ -304,7 +290,6 @@ export function ShogunButtonProvider({ children, sdk, options, onLoginSuccess, o
304
290
  };
305
291
  // Export Gun pair functionality
306
292
  const exportGunPair = async (password) => {
307
- var _a;
308
293
  if (!sdk) {
309
294
  throw new Error("SDK not initialized");
310
295
  }
@@ -312,8 +297,7 @@ export function ShogunButtonProvider({ children, sdk, options, onLoginSuccess, o
312
297
  throw new Error("User not authenticated");
313
298
  }
314
299
  try {
315
- const user = sdk.gun.user();
316
- const pair = (_a = user === null || user === void 0 ? void 0 : user._) === null || _a === void 0 ? void 0 : _a.sea;
300
+ const pair = sessionStorage.getItem("gun/pair") || sessionStorage.getItem("pair");
317
301
  if (!pair) {
318
302
  throw new Error("No Gun pair available for current user");
319
303
  }
@@ -417,6 +401,16 @@ const LockIcon = () => (React.createElement("svg", { xmlns: "http://www.w3.org/2
417
401
  const CloseIcon = () => (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
418
402
  React.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
419
403
  React.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })));
404
+ const ImportIcon = () => (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
405
+ React.createElement("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
406
+ React.createElement("polyline", { points: "14,2 14,8 20,8" }),
407
+ React.createElement("line", { x1: "16", y1: "13", x2: "8", y2: "13" }),
408
+ React.createElement("line", { x1: "12", y1: "17", x2: "12", y2: "9" })));
409
+ const ExportIcon = () => (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
410
+ React.createElement("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
411
+ React.createElement("polyline", { points: "14,2 14,8 20,8" }),
412
+ React.createElement("line", { x1: "12", y1: "11", x2: "12", y2: "21" }),
413
+ React.createElement("polyline", { points: "16,15 12,11 8,15" })));
420
414
  // Component for Shogun login button
421
415
  export const ShogunButton = (() => {
422
416
  const Button = () => {
@@ -439,6 +433,8 @@ export const ShogunButton = (() => {
439
433
  const [importPassword, setImportPassword] = useState("");
440
434
  const [importPairData, setImportPairData] = useState("");
441
435
  const [exportedPair, setExportedPair] = useState("");
436
+ const [showCopySuccess, setShowCopySuccess] = useState(false);
437
+ const [showImportSuccess, setShowImportSuccess] = useState(false);
442
438
  const dropdownRef = useRef(null);
443
439
  // Handle click outside to close dropdown
444
440
  useEffect(() => {
@@ -455,7 +451,7 @@ export const ShogunButton = (() => {
455
451
  }
456
452
  }, [dropdownOpen]);
457
453
  // If already logged in, show only logout button
458
- if (isLoggedIn && username) {
454
+ if (isLoggedIn && username && !modalIsOpen) {
459
455
  return (React.createElement("div", { className: "shogun-logged-in-container" },
460
456
  React.createElement("div", { className: "shogun-dropdown", ref: dropdownRef },
461
457
  React.createElement("button", { className: "shogun-button shogun-logged-in", onClick: () => setDropdownOpen(!dropdownOpen) },
@@ -470,16 +466,16 @@ export const ShogunButton = (() => {
470
466
  React.createElement("span", { className: "shogun-username-full" }, username.length > 20
471
467
  ? `${username.substring(0, 10)}...${username.substring(username.length - 6)}`
472
468
  : username))),
473
- React.createElement("div", { className: "shogun-dropdown-item", onClick: logout },
474
- React.createElement(LogoutIcon, null),
475
- React.createElement("span", null, "Disconnect")),
476
469
  React.createElement("div", { className: "shogun-dropdown-item", onClick: () => {
477
470
  setDropdownOpen(false);
478
471
  setAuthView("export");
479
472
  setModalIsOpen(true);
480
473
  } },
481
- React.createElement("span", null, "\uD83D\uDCE4"),
482
- React.createElement("span", null, "Export Pair")))))));
474
+ React.createElement(ExportIcon, null),
475
+ React.createElement("span", null, "Export Pair")),
476
+ React.createElement("div", { className: "shogun-dropdown-item", onClick: logout },
477
+ React.createElement(LogoutIcon, null),
478
+ React.createElement("span", null, "Disconnect")))))));
483
479
  }
484
480
  // Event handlers
485
481
  const handleAuth = async (method, ...args) => {
@@ -540,11 +536,7 @@ export const ShogunButton = (() => {
540
536
  setError("WebAuthn is not supported in your browser");
541
537
  return;
542
538
  }
543
- if (!formUsername) {
544
- setError("Username required for WebAuthn");
545
- return;
546
- }
547
- handleAuth("webauthn", formUsername);
539
+ setAuthView("webauthn-username");
548
540
  };
549
541
  const handleNostrAuth = () => handleAuth("nostr");
550
542
  const handleOAuth = (provider) => handleAuth("oauth", provider);
@@ -582,10 +574,8 @@ export const ShogunButton = (() => {
582
574
  // Copy to clipboard
583
575
  if (navigator.clipboard) {
584
576
  await navigator.clipboard.writeText(pairData);
585
- alert("Pair exported and copied to clipboard!");
586
- }
587
- else {
588
- alert("Pair exported! Please copy it manually from the text area.");
577
+ setShowCopySuccess(true);
578
+ setTimeout(() => setShowCopySuccess(false), 3000);
589
579
  }
590
580
  }
591
581
  catch (e) {
@@ -604,8 +594,12 @@ export const ShogunButton = (() => {
604
594
  }
605
595
  const success = await importGunPair(importPairData, importPassword || undefined);
606
596
  if (success) {
607
- setModalIsOpen(false);
608
- alert("Pair imported successfully! You are now logged in.");
597
+ setShowImportSuccess(true);
598
+ // Chiudiamo il modal con un piccolo delay per permettere all'utente di vedere il successo
599
+ setTimeout(() => {
600
+ setModalIsOpen(false);
601
+ setShowImportSuccess(false);
602
+ }, 1500);
609
603
  }
610
604
  else {
611
605
  throw new Error("Failed to import pair");
@@ -627,6 +621,13 @@ export const ShogunButton = (() => {
627
621
  setError("");
628
622
  setLoading(false);
629
623
  setAuthView("options");
624
+ setExportPassword("");
625
+ setImportPassword("");
626
+ setImportPairData("");
627
+ setExportedPair("");
628
+ setShowCopySuccess(false);
629
+ setShowImportSuccess(false);
630
+ setRecoveredHint("");
630
631
  };
631
632
  const openModal = () => {
632
633
  resetForm();
@@ -638,7 +639,7 @@ export const ShogunButton = (() => {
638
639
  };
639
640
  const toggleMode = () => {
640
641
  resetForm();
641
- setAuthView("password");
642
+ setAuthView("options"); // Porta alla selezione dei metodi invece che direttamente al form password
642
643
  setFormMode((prev) => (prev === "login" ? "signup" : "login"));
643
644
  };
644
645
  // Add buttons for both login and signup for alternative auth methods
@@ -648,13 +649,7 @@ export const ShogunButton = (() => {
648
649
  React.createElement(WalletIcon, null),
649
650
  formMode === "login" ? "Login with MetaMask" : "Signup with MetaMask"))),
650
651
  options.showWebauthn !== false && (sdk === null || sdk === void 0 ? void 0 : sdk.hasPlugin("webauthn")) && (React.createElement("div", { className: "shogun-auth-option-group" },
651
- React.createElement("button", { type: "button", className: "shogun-auth-option-button", onClick: () => {
652
- if (!formUsername) {
653
- setError("Username required for WebAuthn");
654
- return;
655
- }
656
- handleAuth("webauthn", formUsername);
657
- }, disabled: loading },
652
+ React.createElement("button", { type: "button", className: "shogun-auth-option-button", onClick: handleWebAuthnAuth, disabled: loading },
658
653
  React.createElement(WebAuthnIcon, null),
659
654
  formMode === "login" ? "Login with WebAuthn" : "Signup with WebAuthn"))),
660
655
  options.showNostr !== false && (sdk === null || sdk === void 0 ? void 0 : sdk.hasPlugin("nostr")) && (React.createElement("div", { className: "shogun-auth-option-group" },
@@ -671,7 +666,7 @@ export const ShogunButton = (() => {
671
666
  React.createElement(LockIcon, null),
672
667
  formMode === "login" ? "Login with Password" : "Signup with Password"),
673
668
  formMode === "login" && (React.createElement("button", { type: "button", className: "shogun-auth-option-button", onClick: () => setAuthView("import"), disabled: loading },
674
- React.createElement("span", null, "\uD83D\uDCE5"),
669
+ React.createElement(ImportIcon, null),
675
670
  "Import Gun Pair"))));
676
671
  const renderPasswordForm = () => (React.createElement("form", { onSubmit: handleSubmit, className: "shogun-auth-form" },
677
672
  React.createElement("div", { className: "shogun-form-group" },
@@ -715,6 +710,22 @@ export const ShogunButton = (() => {
715
710
  ? "Don't have an account? Sign up"
716
711
  : "Already have an account? Log in"),
717
712
  formMode === "login" && (React.createElement("button", { type: "button", className: "shogun-toggle-mode", onClick: () => setAuthView("recover"), disabled: loading }, "Forgot password?")))));
713
+ const renderWebAuthnUsernameForm = () => (React.createElement("div", { className: "shogun-auth-form" },
714
+ React.createElement("h3", null, formMode === "login" ? "Login with WebAuthn" : "Sign Up with WebAuthn"),
715
+ React.createElement("div", { style: { backgroundColor: '#f0f9ff', padding: '12px', borderRadius: '8px', marginBottom: '16px', border: '1px solid #0ea5e9' } },
716
+ React.createElement("p", { style: { fontSize: '14px', color: '#0c4a6e', margin: '0', fontWeight: '500' } }, "\uD83D\uDD11 WebAuthn Authentication"),
717
+ React.createElement("p", { style: { fontSize: '13px', color: '#075985', margin: '4px 0 0 0' } },
718
+ "Please enter your username to continue with WebAuthn ",
719
+ formMode === "login" ? "login" : "registration",
720
+ ".")),
721
+ React.createElement("div", { className: "shogun-form-group" },
722
+ React.createElement("label", { htmlFor: "username" },
723
+ React.createElement(UserIcon, null),
724
+ React.createElement("span", null, "Username")),
725
+ React.createElement("input", { type: "text", id: "username", value: formUsername, onChange: (e) => setFormUsername(e.target.value), disabled: loading, required: true, placeholder: "Enter your username", autoFocus: true })),
726
+ React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: () => handleAuth("webauthn", formUsername), disabled: loading || !formUsername.trim() }, loading ? "Processing..." : `Continue with WebAuthn`),
727
+ React.createElement("div", { className: "shogun-form-footer" },
728
+ React.createElement("button", { type: "button", className: "shogun-back-button", onClick: () => setAuthView("options"), disabled: loading }, "\u2190 Back to Options"))));
718
729
  const renderRecoveryForm = () => (React.createElement("div", { className: "shogun-auth-form" },
719
730
  React.createElement("div", { className: "shogun-form-group" },
720
731
  React.createElement("label", { htmlFor: "username" },
@@ -742,7 +753,9 @@ export const ShogunButton = (() => {
742
753
  } }, "Back to Login")));
743
754
  const renderExportForm = () => (React.createElement("div", { className: "shogun-auth-form" },
744
755
  React.createElement("h3", null, "Export Gun Pair"),
745
- React.createElement("p", { style: { fontSize: '14px', color: '#666', marginBottom: '16px' } }, "Export your Gun pair to backup your account. You can use this to login from another device."),
756
+ React.createElement("div", { style: { backgroundColor: '#f0f9ff', padding: '12px', borderRadius: '8px', marginBottom: '16px', border: '1px solid #0ea5e9' } },
757
+ React.createElement("p", { style: { fontSize: '14px', color: '#0c4a6e', margin: '0', fontWeight: '500' } }, "\uD83D\uDD12 Backup Your Account"),
758
+ React.createElement("p", { style: { fontSize: '13px', color: '#075985', margin: '4px 0 0 0' } }, "Export your Gun pair to backup your account. You can use this to login from another device or restore access if needed.")),
746
759
  React.createElement("div", { className: "shogun-form-group" },
747
760
  React.createElement("label", { htmlFor: "exportPassword" },
748
761
  React.createElement(LockIcon, null),
@@ -750,6 +763,15 @@ export const ShogunButton = (() => {
750
763
  React.createElement("input", { type: "password", id: "exportPassword", value: exportPassword, onChange: (e) => setExportPassword(e.target.value), disabled: loading, placeholder: "Leave empty to export unencrypted" })),
751
764
  exportedPair && (React.createElement("div", { className: "shogun-form-group" },
752
765
  React.createElement("label", null, "Your Gun Pair (copy this safely):"),
766
+ showCopySuccess && (React.createElement("div", { style: {
767
+ backgroundColor: '#dcfce7',
768
+ color: '#166534',
769
+ padding: '8px 12px',
770
+ borderRadius: '4px',
771
+ marginBottom: '8px',
772
+ fontSize: '14px',
773
+ border: '1px solid #22c55e'
774
+ } }, "\u2705 Copied to clipboard successfully!")),
753
775
  React.createElement("textarea", { value: exportedPair, readOnly: true, rows: 6, style: {
754
776
  fontFamily: 'monospace',
755
777
  fontSize: '12px',
@@ -757,20 +779,31 @@ export const ShogunButton = (() => {
757
779
  padding: '8px',
758
780
  border: '1px solid #ccc',
759
781
  borderRadius: '4px'
760
- } }))),
782
+ } }),
783
+ !navigator.clipboard && (React.createElement("p", { style: { fontSize: '12px', color: '#666', marginTop: '8px' } }, "\u26A0\uFE0F Auto-copy not available. Please manually copy the text above.")))),
761
784
  React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: handleExportPair, disabled: loading }, loading ? "Exporting..." : "Export Pair"),
762
785
  React.createElement("div", { className: "shogun-form-footer" },
763
786
  React.createElement("button", { className: "shogun-toggle-mode", onClick: () => {
764
- setAuthView("options");
765
- setExportPassword("");
766
- setExportedPair("");
787
+ if (isLoggedIn) {
788
+ // If user is logged in, close the modal instead of going to options
789
+ setModalIsOpen(false);
790
+ setExportPassword("");
791
+ setExportedPair("");
792
+ }
793
+ else {
794
+ setAuthView("options");
795
+ setExportPassword("");
796
+ setExportedPair("");
797
+ }
767
798
  }, disabled: loading }, "Back"))));
768
799
  const renderImportForm = () => (React.createElement("div", { className: "shogun-auth-form" },
769
800
  React.createElement("h3", null, "Import Gun Pair"),
770
- React.createElement("p", { style: { fontSize: '14px', color: '#666', marginBottom: '16px' } }, "Import a Gun pair to login with your existing account from another device."),
801
+ React.createElement("div", { style: { backgroundColor: '#fef3c7', padding: '12px', borderRadius: '8px', marginBottom: '16px', border: '1px solid #f59e0b' } },
802
+ React.createElement("p", { style: { fontSize: '14px', color: '#92400e', margin: '0', fontWeight: '500' } }, "\uD83D\uDD11 Restore Your Account"),
803
+ React.createElement("p", { style: { fontSize: '13px', color: '#a16207', margin: '4px 0 0 0' } }, "Import a Gun pair to login with your existing account from another device. Make sure you have your backup data ready.")),
771
804
  React.createElement("div", { className: "shogun-form-group" },
772
805
  React.createElement("label", { htmlFor: "importPairData" },
773
- React.createElement("span", null, "\uD83D\uDCC4"),
806
+ React.createElement(ImportIcon, null),
774
807
  React.createElement("span", null, "Gun Pair Data")),
775
808
  React.createElement("textarea", { id: "importPairData", value: importPairData, onChange: (e) => setImportPairData(e.target.value), disabled: loading, placeholder: "Paste your Gun pair JSON here...", rows: 6, style: {
776
809
  fontFamily: 'monospace',
@@ -785,7 +818,17 @@ export const ShogunButton = (() => {
785
818
  React.createElement(LockIcon, null),
786
819
  React.createElement("span", null, "Decryption Password (if encrypted)")),
787
820
  React.createElement("input", { type: "password", id: "importPassword", value: importPassword, onChange: (e) => setImportPassword(e.target.value), disabled: loading, placeholder: "Enter password if pair was encrypted" })),
788
- React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: handleImportPair, disabled: loading }, loading ? "Importing..." : "Import and Login"),
821
+ showImportSuccess && (React.createElement("div", { style: {
822
+ backgroundColor: '#dcfce7',
823
+ color: '#166534',
824
+ padding: '12px',
825
+ borderRadius: '8px',
826
+ marginBottom: '16px',
827
+ fontSize: '14px',
828
+ border: '1px solid #22c55e',
829
+ textAlign: 'center'
830
+ } }, "\u2705 Pair imported successfully! Logging you in...")),
831
+ React.createElement("button", { type: "button", className: "shogun-submit-button", onClick: handleImportPair, disabled: loading || showImportSuccess }, loading ? "Importing..." : showImportSuccess ? "Success!" : "Import and Login"),
789
832
  React.createElement("div", { className: "shogun-form-footer" },
790
833
  React.createElement("button", { className: "shogun-toggle-mode", onClick: () => {
791
834
  setAuthView("options");
@@ -808,9 +851,11 @@ export const ShogunButton = (() => {
808
851
  ? "Export Gun Pair"
809
852
  : authView === "import"
810
853
  ? "Import Gun Pair"
811
- : formMode === "login"
812
- ? "Login"
813
- : "Sign Up"),
854
+ : authView === "webauthn-username"
855
+ ? "WebAuthn"
856
+ : formMode === "login"
857
+ ? "Login"
858
+ : "Sign Up"),
814
859
  React.createElement("button", { className: "shogun-close-button", onClick: closeModal, "aria-label": "Close" },
815
860
  React.createElement(CloseIcon, null))),
816
861
  React.createElement("div", { className: "shogun-modal-content" },
@@ -827,7 +872,8 @@ export const ShogunButton = (() => {
827
872
  authView === "recover" && renderRecoveryForm(),
828
873
  authView === "showHint" && renderHint(),
829
874
  authView === "export" && renderExportForm(),
830
- authView === "import" && renderImportForm()))))));
875
+ authView === "import" && renderImportForm(),
876
+ authView === "webauthn-username" && renderWebAuthnUsernameForm()))))));
831
877
  };
832
878
  Button.displayName = "ShogunButton";
833
879
  return Object.assign(Button, {