signer-test-sdk-react 0.0.14 → 0.0.15
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/src/AbstraxnProvider.js +1 -2
- package/dist/src/AbstraxnProvider.js.map +1 -1
- package/dist/src/OnboardingUI.d.ts +1 -1
- package/dist/src/OnboardingUI.js +1 -1
- package/dist/src/components/OnboardingUI/OnboardingUI.css +227 -75
- package/dist/src/components/OnboardingUI/OnboardingUIReact.d.ts +3 -3
- package/dist/src/components/OnboardingUI/OnboardingUIReact.js +109 -55
- package/dist/src/components/OnboardingUI/OnboardingUIReact.js.map +1 -1
- package/dist/src/components/OnboardingUI/OnboardingUIWeb.d.ts +1 -2
- package/dist/src/components/OnboardingUI/OnboardingUIWeb.js +953 -861
- package/dist/src/components/OnboardingUI/OnboardingUIWeb.js.map +1 -1
- package/dist/src/components/OnboardingUI/components/EmailForm.d.ts +3 -3
- package/dist/src/components/OnboardingUI/components/EmailForm.js +13 -5
- package/dist/src/components/OnboardingUI/components/EmailForm.js.map +1 -1
- package/dist/src/components/OnboardingUI/components/Modal.d.ts +0 -1
- package/dist/src/components/OnboardingUI/components/Modal.js +4 -11
- package/dist/src/components/OnboardingUI/components/Modal.js.map +1 -1
- package/dist/src/components/OnboardingUI/components/OtpForm.d.ts +4 -3
- package/dist/src/components/OnboardingUI/components/OtpForm.js +19 -22
- package/dist/src/components/OnboardingUI/components/OtpForm.js.map +1 -1
- package/dist/src/types.d.ts +11 -16
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isValidEmail } from "signer-test-sdk-core";
|
|
1
2
|
// CSS styles embedded as string
|
|
2
3
|
const ONBOARDING_UI_STYLES = `
|
|
3
4
|
.onboarding-container {
|
|
@@ -101,44 +102,6 @@ const ONBOARDING_UI_STYLES = `
|
|
|
101
102
|
transform: scale(0.95);
|
|
102
103
|
}
|
|
103
104
|
|
|
104
|
-
.onboarding-modal-close {
|
|
105
|
-
position: absolute;
|
|
106
|
-
top: 24px;
|
|
107
|
-
right: 24px;
|
|
108
|
-
width: 32px;
|
|
109
|
-
height: 32px;
|
|
110
|
-
border: none;
|
|
111
|
-
background-color: #f3f4f6;
|
|
112
|
-
border-radius: 8px;
|
|
113
|
-
cursor: pointer;
|
|
114
|
-
display: flex;
|
|
115
|
-
align-items: center;
|
|
116
|
-
justify-content: center;
|
|
117
|
-
font-size: 18px;
|
|
118
|
-
line-height: 1;
|
|
119
|
-
color: #6b7280;
|
|
120
|
-
transition: all 0.2s ease;
|
|
121
|
-
z-index: 10;
|
|
122
|
-
padding: 0;
|
|
123
|
-
font-weight: 400;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.onboarding-modal-close:hover {
|
|
127
|
-
background-color: #e5e7eb;
|
|
128
|
-
color: #374151;
|
|
129
|
-
transform: scale(1.05);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
.onboarding-theme-dark .onboarding-modal-close {
|
|
133
|
-
background-color: #374151;
|
|
134
|
-
color: #9ca3af;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.onboarding-theme-dark .onboarding-modal-close:hover {
|
|
138
|
-
background-color: #4b5563;
|
|
139
|
-
color: #ffffff;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
105
|
/* Modal container adjustments */
|
|
143
106
|
.onboarding-modal-content .onboarding-container {
|
|
144
107
|
min-height: auto;
|
|
@@ -159,7 +122,7 @@ const ONBOARDING_UI_STYLES = `
|
|
|
159
122
|
width: 420px;
|
|
160
123
|
max-width: 420px;
|
|
161
124
|
min-width: 420px;
|
|
162
|
-
padding:
|
|
125
|
+
padding: 20px;
|
|
163
126
|
border-radius: 16px;
|
|
164
127
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
165
128
|
background-color: inherit;
|
|
@@ -191,7 +154,7 @@ const ONBOARDING_UI_STYLES = `
|
|
|
191
154
|
|
|
192
155
|
@media (max-width: 480px) {
|
|
193
156
|
.onboarding-card {
|
|
194
|
-
padding:
|
|
157
|
+
padding: 24px 20px;
|
|
195
158
|
border-radius: 0;
|
|
196
159
|
max-height: 100vh;
|
|
197
160
|
}
|
|
@@ -211,14 +174,14 @@ const ONBOARDING_UI_STYLES = `
|
|
|
211
174
|
|
|
212
175
|
.onboarding-header {
|
|
213
176
|
text-align: center;
|
|
214
|
-
margin-bottom:
|
|
177
|
+
margin-bottom: 20px;
|
|
215
178
|
}
|
|
216
179
|
|
|
217
180
|
.onboarding-logo-section {
|
|
218
181
|
display: flex;
|
|
219
182
|
flex-direction: column;
|
|
220
183
|
align-items: center;
|
|
221
|
-
margin-bottom:
|
|
184
|
+
margin-bottom: 12px;
|
|
222
185
|
}
|
|
223
186
|
|
|
224
187
|
.onboarding-logo-container {
|
|
@@ -241,9 +204,9 @@ const ONBOARDING_UI_STYLES = `
|
|
|
241
204
|
margin: 0;
|
|
242
205
|
color: inherit;
|
|
243
206
|
text-align: center;
|
|
244
|
-
margin-bottom:
|
|
207
|
+
margin-bottom: 4px;
|
|
245
208
|
letter-spacing: -0.01em;
|
|
246
|
-
line-height: 1.
|
|
209
|
+
line-height: 1.2;
|
|
247
210
|
}
|
|
248
211
|
|
|
249
212
|
@media (max-width: 480px) {
|
|
@@ -266,7 +229,7 @@ const ONBOARDING_UI_STYLES = `
|
|
|
266
229
|
}
|
|
267
230
|
|
|
268
231
|
.onboarding-input-group {
|
|
269
|
-
margin-bottom:
|
|
232
|
+
margin-bottom: 8px;
|
|
270
233
|
}
|
|
271
234
|
|
|
272
235
|
.onboarding-input-label {
|
|
@@ -274,7 +237,7 @@ const ONBOARDING_UI_STYLES = `
|
|
|
274
237
|
font-size: 14px;
|
|
275
238
|
font-weight: 500;
|
|
276
239
|
color: #374151;
|
|
277
|
-
margin-bottom:
|
|
240
|
+
margin-bottom: 4px;
|
|
278
241
|
letter-spacing: -0.01em;
|
|
279
242
|
line-height: 1.5;
|
|
280
243
|
text-align: left;
|
|
@@ -325,11 +288,30 @@ const ONBOARDING_UI_STYLES = `
|
|
|
325
288
|
color: #000000;
|
|
326
289
|
}
|
|
327
290
|
|
|
291
|
+
.onboarding-theme-light .onboarding-input:-webkit-autofill,
|
|
292
|
+
.onboarding-theme-light .onboarding-input:-webkit-autofill:hover,
|
|
293
|
+
.onboarding-theme-light .onboarding-input:-webkit-autofill:focus,
|
|
294
|
+
.onboarding-theme-light .onboarding-input:-webkit-autofill:active {
|
|
295
|
+
-webkit-box-shadow: 0 0 0 30px #ffffff inset !important;
|
|
296
|
+
-webkit-text-fill-color: #111827 !important;
|
|
297
|
+
transition: background-color 5000s ease-in-out 0s;
|
|
298
|
+
}
|
|
299
|
+
|
|
328
300
|
.onboarding-theme-dark .onboarding-input {
|
|
329
301
|
background-color: #374151;
|
|
330
302
|
color: #ffffff;
|
|
331
303
|
}
|
|
332
304
|
|
|
305
|
+
.onboarding-theme-dark .onboarding-input:-webkit-autofill,
|
|
306
|
+
.onboarding-theme-dark .onboarding-input:-webkit-autofill:hover,
|
|
307
|
+
.onboarding-theme-dark .onboarding-input:-webkit-autofill:focus,
|
|
308
|
+
.onboarding-theme-dark .onboarding-input:-webkit-autofill:active {
|
|
309
|
+
-webkit-box-shadow: 0 0 0 30px #374151 inset !important;
|
|
310
|
+
-webkit-text-fill-color: #ffffff !important;
|
|
311
|
+
color: #ffffff !important;
|
|
312
|
+
transition: background-color 5000s ease-in-out 0s;
|
|
313
|
+
}
|
|
314
|
+
|
|
333
315
|
.onboarding-input:focus {
|
|
334
316
|
outline: none;
|
|
335
317
|
}
|
|
@@ -349,7 +331,7 @@ const ONBOARDING_UI_STYLES = `
|
|
|
349
331
|
.onboarding-theme-dark .onboarding-input:focus {
|
|
350
332
|
border-color: #9ca3af;
|
|
351
333
|
box-shadow: 0 0 0 3px rgba(156, 163, 175, 0.2);
|
|
352
|
-
background-color: #
|
|
334
|
+
background-color: #374151;
|
|
353
335
|
color: #ffffff;
|
|
354
336
|
}
|
|
355
337
|
|
|
@@ -441,7 +423,7 @@ const ONBOARDING_UI_STYLES = `
|
|
|
441
423
|
align-items: center;
|
|
442
424
|
justify-content: center;
|
|
443
425
|
gap: 8px;
|
|
444
|
-
margin-bottom:
|
|
426
|
+
margin-bottom: 6px;
|
|
445
427
|
letter-spacing: -0.01em;
|
|
446
428
|
line-height: 1.5;
|
|
447
429
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
@@ -643,7 +625,7 @@ const ONBOARDING_UI_STYLES = `
|
|
|
643
625
|
.onboarding-divider {
|
|
644
626
|
display: flex;
|
|
645
627
|
align-items: center;
|
|
646
|
-
margin:
|
|
628
|
+
margin: 10px 0;
|
|
647
629
|
position: relative;
|
|
648
630
|
}
|
|
649
631
|
|
|
@@ -734,38 +716,54 @@ const ONBOARDING_UI_STYLES = `
|
|
|
734
716
|
}
|
|
735
717
|
|
|
736
718
|
.onboarding-otp-icon-container {
|
|
737
|
-
width:
|
|
738
|
-
height:
|
|
719
|
+
width: 64px;
|
|
720
|
+
height: 64px;
|
|
739
721
|
border-radius: 50%;
|
|
740
722
|
display: flex;
|
|
741
723
|
align-items: center;
|
|
742
724
|
justify-content: center;
|
|
743
|
-
margin-bottom:
|
|
725
|
+
margin-bottom: 24px;
|
|
744
726
|
position: relative;
|
|
727
|
+
background: transparent;
|
|
728
|
+
border: 3px solid #eef2ff;
|
|
745
729
|
}
|
|
746
730
|
|
|
747
|
-
.onboarding-
|
|
748
|
-
|
|
731
|
+
.onboarding-otp-icon-container::after {
|
|
732
|
+
content: '';
|
|
733
|
+
position: absolute;
|
|
734
|
+
top: -3px;
|
|
735
|
+
left: -3px;
|
|
736
|
+
right: -3px;
|
|
737
|
+
bottom: -3px;
|
|
738
|
+
border-radius: 50%;
|
|
739
|
+
border: 3px solid transparent;
|
|
740
|
+
border-top-color: #363ff9;
|
|
741
|
+
animation: onboarding-spin 2s linear infinite;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
@keyframes onboarding-spin {
|
|
745
|
+
0% { transform: rotate(0deg); }
|
|
746
|
+
100% { transform: rotate(360deg); }
|
|
749
747
|
}
|
|
750
748
|
|
|
751
749
|
.onboarding-theme-dark .onboarding-otp-icon-container {
|
|
752
|
-
|
|
750
|
+
border-color: rgba(156, 163, 175, 0.2);
|
|
753
751
|
}
|
|
754
752
|
|
|
755
753
|
.onboarding-otp-icon-inner {
|
|
756
|
-
width:
|
|
757
|
-
height:
|
|
758
|
-
background-color:
|
|
759
|
-
border-radius: 10px;
|
|
754
|
+
width: 100%;
|
|
755
|
+
height: 100%;
|
|
756
|
+
background-color: transparent;
|
|
760
757
|
display: flex;
|
|
761
758
|
align-items: center;
|
|
762
759
|
justify-content: center;
|
|
760
|
+
z-index: 1;
|
|
763
761
|
}
|
|
764
762
|
|
|
765
763
|
.onboarding-otp-icon {
|
|
766
|
-
width:
|
|
767
|
-
height:
|
|
768
|
-
color: #
|
|
764
|
+
width: 28px;
|
|
765
|
+
height: 28px;
|
|
766
|
+
color: #363ff9;
|
|
769
767
|
}
|
|
770
768
|
|
|
771
769
|
.onboarding-otp-title {
|
|
@@ -944,7 +942,7 @@ const ONBOARDING_UI_STYLES = `
|
|
|
944
942
|
}
|
|
945
943
|
|
|
946
944
|
.onboarding-passkey-signup-link {
|
|
947
|
-
text-decoration:
|
|
945
|
+
text-decoration: underline;
|
|
948
946
|
cursor: pointer;
|
|
949
947
|
font-size: 14px;
|
|
950
948
|
font-weight: 500;
|
|
@@ -955,22 +953,14 @@ const ONBOARDING_UI_STYLES = `
|
|
|
955
953
|
}
|
|
956
954
|
|
|
957
955
|
.onboarding-theme-light .onboarding-passkey-signup-link {
|
|
958
|
-
color:
|
|
959
|
-
}
|
|
956
|
+
color: #2170f5;
|
|
957
|
+
}
|
|
960
958
|
|
|
961
|
-
.onboarding-theme-light .onboarding-passkey-signup-link:hover {
|
|
962
|
-
color: #1f2937;
|
|
963
|
-
text-decoration: underline;
|
|
964
|
-
}
|
|
965
959
|
|
|
966
960
|
.onboarding-theme-dark .onboarding-passkey-signup-link {
|
|
967
|
-
color:
|
|
968
|
-
}
|
|
961
|
+
color: #2170f5;
|
|
962
|
+
}
|
|
969
963
|
|
|
970
|
-
.onboarding-theme-dark .onboarding-passkey-signup-link:hover {
|
|
971
|
-
color: #d1d5db;
|
|
972
|
-
text-decoration: underline;
|
|
973
|
-
}
|
|
974
964
|
`;
|
|
975
965
|
/**
|
|
976
966
|
* OnboardingUI Class
|
|
@@ -1002,7 +992,6 @@ export class OnboardingUIWeb {
|
|
|
1002
992
|
errorElement = null;
|
|
1003
993
|
otpGroup = null;
|
|
1004
994
|
otpVerificationScreen = null;
|
|
1005
|
-
closeButton = null;
|
|
1006
995
|
resendButton = null;
|
|
1007
996
|
socialGrid = null;
|
|
1008
997
|
externalWalletContainer = null;
|
|
@@ -1010,8 +999,8 @@ export class OnboardingUIWeb {
|
|
|
1010
999
|
divider = null;
|
|
1011
1000
|
footer = null;
|
|
1012
1001
|
verifyButton = null;
|
|
1013
|
-
email =
|
|
1014
|
-
otp =
|
|
1002
|
+
email = "";
|
|
1003
|
+
otp = "";
|
|
1015
1004
|
otpSent = false;
|
|
1016
1005
|
loading = false;
|
|
1017
1006
|
activeButton = null;
|
|
@@ -1020,15 +1009,14 @@ export class OnboardingUIWeb {
|
|
|
1020
1009
|
externalWalletsEnabled = false;
|
|
1021
1010
|
constructor(config, externalWalletsEnabled = false) {
|
|
1022
1011
|
this.externalWalletsEnabled = externalWalletsEnabled;
|
|
1023
|
-
const defaultTheme = config.theme ||
|
|
1012
|
+
const defaultTheme = config.theme || "light";
|
|
1024
1013
|
this.config = {
|
|
1025
1014
|
theme: defaultTheme,
|
|
1026
1015
|
showFooter: config.showFooter !== false,
|
|
1027
|
-
className: config.className ||
|
|
1016
|
+
className: config.className || "",
|
|
1028
1017
|
modal: config.modal !== false,
|
|
1029
1018
|
closeOnBackdropClick: config.closeOnBackdropClick !== false,
|
|
1030
|
-
|
|
1031
|
-
onboardTitle: config.onboardTitle || 'Sign in',
|
|
1019
|
+
onboardTitle: config.onboardTitle || "Sign In",
|
|
1032
1020
|
handleUrlParams: config.handleUrlParams !== false,
|
|
1033
1021
|
...config,
|
|
1034
1022
|
};
|
|
@@ -1039,10 +1027,10 @@ export class OnboardingUIWeb {
|
|
|
1039
1027
|
*/
|
|
1040
1028
|
showExternalWallets() {
|
|
1041
1029
|
if (this.externalWalletContainer) {
|
|
1042
|
-
this.externalWalletContainer.style.display =
|
|
1030
|
+
this.externalWalletContainer.style.display = "";
|
|
1043
1031
|
}
|
|
1044
1032
|
if (this.externalWalletDivider) {
|
|
1045
|
-
this.externalWalletDivider.style.display =
|
|
1033
|
+
this.externalWalletDivider.style.display = "";
|
|
1046
1034
|
}
|
|
1047
1035
|
}
|
|
1048
1036
|
/**
|
|
@@ -1059,25 +1047,29 @@ export class OnboardingUIWeb {
|
|
|
1059
1047
|
* Check URL parameters for social login callbacks
|
|
1060
1048
|
*/
|
|
1061
1049
|
checkUrlParams() {
|
|
1062
|
-
if (typeof window ===
|
|
1050
|
+
if (typeof window === "undefined")
|
|
1063
1051
|
return;
|
|
1064
1052
|
if (!this.config.handleUrlParams)
|
|
1065
1053
|
return;
|
|
1066
1054
|
const params = new URLSearchParams(window.location.search);
|
|
1067
|
-
const success = params.get(
|
|
1068
|
-
const error = params.get(
|
|
1069
|
-
const accessToken = params.get(
|
|
1070
|
-
const provider = params.get(
|
|
1055
|
+
const success = params.get("success");
|
|
1056
|
+
const error = params.get("error");
|
|
1057
|
+
const accessToken = params.get("accessToken");
|
|
1058
|
+
const provider = params.get("provider") || params.get("authProvider");
|
|
1071
1059
|
// Helper to extract provider from accessToken JWT
|
|
1072
1060
|
const getAuthProviderFromToken = (token) => {
|
|
1073
1061
|
try {
|
|
1074
|
-
const base64Url = token.split(
|
|
1075
|
-
const base64 = base64Url.replace(/-/g,
|
|
1076
|
-
const jsonPayload = decodeURIComponent(window
|
|
1077
|
-
|
|
1078
|
-
|
|
1062
|
+
const base64Url = token.split(".")[1];
|
|
1063
|
+
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
|
1064
|
+
const jsonPayload = decodeURIComponent(window
|
|
1065
|
+
.atob(base64)
|
|
1066
|
+
.split("")
|
|
1067
|
+
.map(function (c) {
|
|
1068
|
+
return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
|
|
1069
|
+
})
|
|
1070
|
+
.join(""));
|
|
1079
1071
|
const payload = JSON.parse(jsonPayload);
|
|
1080
|
-
return (payload.authProvider || payload.provider ||
|
|
1072
|
+
return (payload.authProvider || payload.provider || "").toLowerCase();
|
|
1081
1073
|
}
|
|
1082
1074
|
catch (e) {
|
|
1083
1075
|
return null;
|
|
@@ -1088,10 +1080,14 @@ export class OnboardingUIWeb {
|
|
|
1088
1080
|
if (!detectedProvider && accessToken) {
|
|
1089
1081
|
detectedProvider = getAuthProviderFromToken(accessToken);
|
|
1090
1082
|
}
|
|
1091
|
-
const isOAuthCallback = detectedProvider &&
|
|
1092
|
-
|
|
1083
|
+
const isOAuthCallback = detectedProvider &&
|
|
1084
|
+
(detectedProvider === "google" ||
|
|
1085
|
+
detectedProvider === "discord" ||
|
|
1086
|
+
detectedProvider === "twitter" ||
|
|
1087
|
+
detectedProvider === "x");
|
|
1088
|
+
const hasOAuthParams = isOAuthCallback || (success === "true" && !!accessToken);
|
|
1093
1089
|
// If success=true and it's an OAuth callback (Google, Discord, Twitter), show loading modal with header and footer
|
|
1094
|
-
if (success ===
|
|
1090
|
+
if (success === "true" && hasOAuthParams) {
|
|
1095
1091
|
// Show loading modal immediately - it creates its own overlay
|
|
1096
1092
|
// Use requestAnimationFrame + setTimeout to ensure DOM is ready
|
|
1097
1093
|
requestAnimationFrame(() => {
|
|
@@ -1103,12 +1099,12 @@ export class OnboardingUIWeb {
|
|
|
1103
1099
|
return;
|
|
1104
1100
|
}
|
|
1105
1101
|
// Check login source to decide if we should handle this (for errors)
|
|
1106
|
-
const source = localStorage.getItem(
|
|
1102
|
+
const source = localStorage.getItem("abstraxn_login_source");
|
|
1107
1103
|
const isModal = this.config.modal;
|
|
1108
1104
|
if (source) {
|
|
1109
|
-
if (source ===
|
|
1105
|
+
if (source === "modal" && !isModal)
|
|
1110
1106
|
return; // Modal initiated, I am Inline -> Ignore
|
|
1111
|
-
if (source ===
|
|
1107
|
+
if (source === "inline" && isModal)
|
|
1112
1108
|
return; // Inline initiated, I am Modal -> Ignore
|
|
1113
1109
|
}
|
|
1114
1110
|
else {
|
|
@@ -1141,77 +1137,77 @@ export class OnboardingUIWeb {
|
|
|
1141
1137
|
return;
|
|
1142
1138
|
// Hide loading modal if it exists (for inline components)
|
|
1143
1139
|
this.hideLoadingModal();
|
|
1144
|
-
const card = this.rootElement.querySelector(
|
|
1140
|
+
const card = this.rootElement.querySelector(".onboarding-card");
|
|
1145
1141
|
if (!card)
|
|
1146
1142
|
return;
|
|
1147
1143
|
// Add error mode class to card
|
|
1148
|
-
card.classList.add(
|
|
1149
|
-
card.classList.remove(
|
|
1144
|
+
card.classList.add("onboarding-mode-error");
|
|
1145
|
+
card.classList.remove("onboarding-mode-loading");
|
|
1150
1146
|
// Create or show error container
|
|
1151
|
-
let errorContainer = this.rootElement.querySelector(
|
|
1147
|
+
let errorContainer = this.rootElement.querySelector(".onboarding-error-container");
|
|
1152
1148
|
if (!errorContainer) {
|
|
1153
|
-
errorContainer = this.createElement(
|
|
1154
|
-
className:
|
|
1155
|
-
style:
|
|
1149
|
+
errorContainer = this.createElement("div", {
|
|
1150
|
+
className: "onboarding-error-container",
|
|
1151
|
+
style: "display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 20px 0; text-align: center;",
|
|
1156
1152
|
});
|
|
1157
1153
|
// Error Icon
|
|
1158
|
-
const iconContainer = this.createElement(
|
|
1159
|
-
style:
|
|
1154
|
+
const iconContainer = this.createElement("div", {
|
|
1155
|
+
style: "width: 64px; height: 64px; background-color: #fee2e2; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-bottom: 20px;",
|
|
1160
1156
|
});
|
|
1161
1157
|
// Dark mode adjustment for icon container
|
|
1162
|
-
if (this.config.theme ===
|
|
1163
|
-
iconContainer.style.backgroundColor =
|
|
1164
|
-
}
|
|
1165
|
-
const iconSvg = document.createElementNS(
|
|
1166
|
-
iconSvg.setAttribute(
|
|
1167
|
-
iconSvg.setAttribute(
|
|
1168
|
-
iconSvg.setAttribute(
|
|
1169
|
-
iconSvg.setAttribute(
|
|
1170
|
-
iconSvg.setAttribute(
|
|
1171
|
-
iconSvg.setAttribute(
|
|
1172
|
-
iconSvg.setAttribute(
|
|
1173
|
-
iconSvg.setAttribute(
|
|
1174
|
-
const circle = document.createElementNS(
|
|
1175
|
-
circle.setAttribute(
|
|
1176
|
-
circle.setAttribute(
|
|
1177
|
-
circle.setAttribute(
|
|
1158
|
+
if (this.config.theme === "dark") {
|
|
1159
|
+
iconContainer.style.backgroundColor = "rgba(220, 38, 38, 0.2)";
|
|
1160
|
+
}
|
|
1161
|
+
const iconSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
1162
|
+
iconSvg.setAttribute("width", "32");
|
|
1163
|
+
iconSvg.setAttribute("height", "32");
|
|
1164
|
+
iconSvg.setAttribute("viewBox", "0 0 24 24");
|
|
1165
|
+
iconSvg.setAttribute("fill", "none");
|
|
1166
|
+
iconSvg.setAttribute("stroke", "#dc2626");
|
|
1167
|
+
iconSvg.setAttribute("stroke-width", "2");
|
|
1168
|
+
iconSvg.setAttribute("stroke-linecap", "round");
|
|
1169
|
+
iconSvg.setAttribute("stroke-linejoin", "round");
|
|
1170
|
+
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
1171
|
+
circle.setAttribute("cx", "12");
|
|
1172
|
+
circle.setAttribute("cy", "12");
|
|
1173
|
+
circle.setAttribute("r", "10");
|
|
1178
1174
|
iconSvg.appendChild(circle);
|
|
1179
|
-
const line1 = document.createElementNS(
|
|
1180
|
-
line1.setAttribute(
|
|
1181
|
-
line1.setAttribute(
|
|
1182
|
-
line1.setAttribute(
|
|
1183
|
-
line1.setAttribute(
|
|
1175
|
+
const line1 = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
1176
|
+
line1.setAttribute("x1", "12");
|
|
1177
|
+
line1.setAttribute("y1", "8");
|
|
1178
|
+
line1.setAttribute("x2", "12");
|
|
1179
|
+
line1.setAttribute("y2", "12");
|
|
1184
1180
|
iconSvg.appendChild(line1);
|
|
1185
|
-
const line2 = document.createElementNS(
|
|
1186
|
-
line2.setAttribute(
|
|
1187
|
-
line2.setAttribute(
|
|
1188
|
-
line2.setAttribute(
|
|
1189
|
-
line2.setAttribute(
|
|
1181
|
+
const line2 = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
1182
|
+
line2.setAttribute("x1", "12");
|
|
1183
|
+
line2.setAttribute("y1", "16");
|
|
1184
|
+
line2.setAttribute("x2", "12.01");
|
|
1185
|
+
line2.setAttribute("y2", "16");
|
|
1190
1186
|
iconSvg.appendChild(line2);
|
|
1191
1187
|
iconContainer.appendChild(iconSvg);
|
|
1192
1188
|
errorContainer.appendChild(iconContainer);
|
|
1193
1189
|
// Title
|
|
1194
|
-
const title = this.createElement(
|
|
1195
|
-
textContent:
|
|
1196
|
-
style:
|
|
1190
|
+
const title = this.createElement("h3", {
|
|
1191
|
+
textContent: "Authentication Failed",
|
|
1192
|
+
style: "font-size: 20px; font-weight: 600; margin: 0 0 12px 0; color: inherit;",
|
|
1197
1193
|
});
|
|
1198
1194
|
errorContainer.appendChild(title);
|
|
1199
1195
|
// Message
|
|
1200
|
-
const msg = this.createElement(
|
|
1196
|
+
const msg = this.createElement("p", {
|
|
1201
1197
|
textContent: message,
|
|
1202
|
-
style:
|
|
1198
|
+
style: "font-size: 14px; color: #6b7280; margin: 0 0 24px 0; line-height: 1.5; max-width: 100%; word-break: break-word;",
|
|
1203
1199
|
});
|
|
1204
|
-
if (this.config.theme ===
|
|
1205
|
-
msg.style.color =
|
|
1200
|
+
if (this.config.theme === "dark") {
|
|
1201
|
+
msg.style.color = "#9ca3af";
|
|
1206
1202
|
}
|
|
1207
1203
|
errorContainer.appendChild(msg);
|
|
1208
1204
|
// OK Button
|
|
1209
|
-
const okButton = this.createElement(
|
|
1210
|
-
className:
|
|
1211
|
-
textContent:
|
|
1212
|
-
style:
|
|
1205
|
+
const okButton = this.createElement("button", {
|
|
1206
|
+
className: "onboarding-button onboarding-button-primary",
|
|
1207
|
+
textContent: "OK",
|
|
1208
|
+
style: "width: 100%; max-width: 200px;",
|
|
1213
1209
|
});
|
|
1214
|
-
okButton.addEventListener(
|
|
1210
|
+
okButton.addEventListener("click", () => {
|
|
1215
1211
|
if (this.config.modal) {
|
|
1216
1212
|
this.close();
|
|
1217
1213
|
}
|
|
@@ -1220,7 +1216,7 @@ export class OnboardingUIWeb {
|
|
|
1220
1216
|
}
|
|
1221
1217
|
// Also clear URL params to prevent showing error again on refresh
|
|
1222
1218
|
const url = new URL(window.location.href);
|
|
1223
|
-
url.searchParams.delete(
|
|
1219
|
+
url.searchParams.delete("error");
|
|
1224
1220
|
window.history.replaceState({}, document.title, url.toString());
|
|
1225
1221
|
});
|
|
1226
1222
|
errorContainer.appendChild(okButton);
|
|
@@ -1228,10 +1224,10 @@ export class OnboardingUIWeb {
|
|
|
1228
1224
|
}
|
|
1229
1225
|
else {
|
|
1230
1226
|
// Update message if container exists
|
|
1231
|
-
const msgEl = errorContainer.querySelector(
|
|
1227
|
+
const msgEl = errorContainer.querySelector("p");
|
|
1232
1228
|
if (msgEl)
|
|
1233
1229
|
msgEl.textContent = message;
|
|
1234
|
-
errorContainer.style.display =
|
|
1230
|
+
errorContainer.style.display = "flex";
|
|
1235
1231
|
}
|
|
1236
1232
|
// Move footer to the bottom
|
|
1237
1233
|
if (this.footer) {
|
|
@@ -1251,7 +1247,7 @@ export class OnboardingUIWeb {
|
|
|
1251
1247
|
}
|
|
1252
1248
|
// Hide the main modal overlay to prevent showing wallet options below loading screen
|
|
1253
1249
|
if (this.modalOverlay) {
|
|
1254
|
-
this.modalOverlay.style.display =
|
|
1250
|
+
this.modalOverlay.style.display = "none";
|
|
1255
1251
|
}
|
|
1256
1252
|
// Show loading modal overlay instead (with higher z-index)
|
|
1257
1253
|
this.showLoadingModal();
|
|
@@ -1262,17 +1258,17 @@ export class OnboardingUIWeb {
|
|
|
1262
1258
|
*/
|
|
1263
1259
|
showLoadingModal() {
|
|
1264
1260
|
// Hide any other modals that might be showing (wallet selection, etc.)
|
|
1265
|
-
const otherModals = document.querySelectorAll(
|
|
1261
|
+
const otherModals = document.querySelectorAll(".onboarding-modal-overlay, .external-wallet-modal, .wallet-modal-overlay");
|
|
1266
1262
|
otherModals.forEach((modal) => {
|
|
1267
|
-
if (modal.id !==
|
|
1268
|
-
modal.style.display =
|
|
1263
|
+
if (modal.id !== "onboarding-loading-modal-overlay") {
|
|
1264
|
+
modal.style.display = "none";
|
|
1269
1265
|
}
|
|
1270
1266
|
});
|
|
1271
1267
|
// Create modal overlay if it doesn't exist
|
|
1272
|
-
let loadingModalOverlay = document.getElementById(
|
|
1268
|
+
let loadingModalOverlay = document.getElementById("onboarding-loading-modal-overlay");
|
|
1273
1269
|
if (!loadingModalOverlay) {
|
|
1274
|
-
loadingModalOverlay = this.createElement(
|
|
1275
|
-
id:
|
|
1270
|
+
loadingModalOverlay = this.createElement("div", {
|
|
1271
|
+
id: "onboarding-loading-modal-overlay",
|
|
1276
1272
|
style: `
|
|
1277
1273
|
position: fixed;
|
|
1278
1274
|
top: 0;
|
|
@@ -1287,10 +1283,10 @@ export class OnboardingUIWeb {
|
|
|
1287
1283
|
backdrop-filter: blur(4px);
|
|
1288
1284
|
`,
|
|
1289
1285
|
});
|
|
1290
|
-
const loadingCard = this.createElement(
|
|
1286
|
+
const loadingCard = this.createElement("div", {
|
|
1291
1287
|
className: `onboarding-card onboarding-theme-${this.config.theme}`,
|
|
1292
1288
|
style: `
|
|
1293
|
-
background: ${this.config.theme ===
|
|
1289
|
+
background: ${this.config.theme === "dark" ? "#1f2937" : "white"};
|
|
1294
1290
|
border-radius: 16px;
|
|
1295
1291
|
padding: 32px 32px 28px;
|
|
1296
1292
|
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
@@ -1306,31 +1302,35 @@ export class OnboardingUIWeb {
|
|
|
1306
1302
|
`,
|
|
1307
1303
|
});
|
|
1308
1304
|
// Header with logo and title
|
|
1309
|
-
const header = this.createElement(
|
|
1310
|
-
className:
|
|
1311
|
-
style:
|
|
1305
|
+
const header = this.createElement("div", {
|
|
1306
|
+
className: "onboarding-header",
|
|
1307
|
+
style: "display: flex; flex-direction: column; align-items: center; gap: 8px; width: 100%; margin-bottom: 32px;",
|
|
1308
|
+
});
|
|
1309
|
+
const logoSection = this.createElement("div", {
|
|
1310
|
+
className: "onboarding-logo-section",
|
|
1312
1311
|
});
|
|
1313
|
-
const logoSection = this.createElement('div', { className: 'onboarding-logo-section' });
|
|
1314
1312
|
if (this.config.logo) {
|
|
1315
|
-
const logoContainer = this.createElement(
|
|
1316
|
-
|
|
1313
|
+
const logoContainer = this.createElement("div", {
|
|
1314
|
+
className: "onboarding-logo-container",
|
|
1315
|
+
});
|
|
1316
|
+
const logoImg = this.createElement("img", {
|
|
1317
1317
|
src: this.config.logo,
|
|
1318
|
-
alt:
|
|
1319
|
-
className:
|
|
1318
|
+
alt: "Abstraxn",
|
|
1319
|
+
className: "onboarding-logo-img",
|
|
1320
1320
|
});
|
|
1321
1321
|
logoContainer.appendChild(logoImg);
|
|
1322
1322
|
logoSection.appendChild(logoContainer);
|
|
1323
1323
|
}
|
|
1324
1324
|
header.appendChild(logoSection);
|
|
1325
1325
|
// Add title
|
|
1326
|
-
const title = this.createElement(
|
|
1327
|
-
className:
|
|
1328
|
-
textContent: this.config.onboardTitle ||
|
|
1326
|
+
const title = this.createElement("h1", {
|
|
1327
|
+
className: "onboarding-title",
|
|
1328
|
+
textContent: this.config.onboardTitle || "Sign In",
|
|
1329
1329
|
style: `
|
|
1330
1330
|
font-size: 24px;
|
|
1331
1331
|
font-weight: 600;
|
|
1332
1332
|
margin: 0;
|
|
1333
|
-
color: ${this.config.theme ===
|
|
1333
|
+
color: ${this.config.theme === "dark" ? "#ffffff" : "#111827"};
|
|
1334
1334
|
text-align: center;
|
|
1335
1335
|
margin-bottom: 0;
|
|
1336
1336
|
letter-spacing: -0.01em;
|
|
@@ -1340,10 +1340,12 @@ export class OnboardingUIWeb {
|
|
|
1340
1340
|
header.appendChild(title);
|
|
1341
1341
|
loadingCard.appendChild(header);
|
|
1342
1342
|
// Spinner
|
|
1343
|
-
const spinnerColor = this.config.theme ===
|
|
1344
|
-
const spinnerBorderColor = this.config.theme ===
|
|
1345
|
-
|
|
1346
|
-
|
|
1343
|
+
const spinnerColor = this.config.theme === "dark" ? "#9ca3af" : "#111827";
|
|
1344
|
+
const spinnerBorderColor = this.config.theme === "dark"
|
|
1345
|
+
? "rgba(156, 163, 175, 0.2)"
|
|
1346
|
+
: "rgba(17, 24, 39, 0.1)";
|
|
1347
|
+
const spinner = this.createElement("div", {
|
|
1348
|
+
className: "onboarding-loading-spinner",
|
|
1347
1349
|
style: `
|
|
1348
1350
|
width: 40px;
|
|
1349
1351
|
height: 40px;
|
|
@@ -1355,9 +1357,9 @@ export class OnboardingUIWeb {
|
|
|
1355
1357
|
`,
|
|
1356
1358
|
});
|
|
1357
1359
|
// Add keyframes if not exists
|
|
1358
|
-
if (!document.getElementById(
|
|
1359
|
-
const style = document.createElement(
|
|
1360
|
-
style.id =
|
|
1360
|
+
if (!document.getElementById("onboarding-spin-style")) {
|
|
1361
|
+
const style = document.createElement("style");
|
|
1362
|
+
style.id = "onboarding-spin-style";
|
|
1361
1363
|
style.textContent = `
|
|
1362
1364
|
@keyframes onboarding-spin {
|
|
1363
1365
|
to { transform: rotate(360deg); }
|
|
@@ -1366,11 +1368,11 @@ export class OnboardingUIWeb {
|
|
|
1366
1368
|
document.head.appendChild(style);
|
|
1367
1369
|
}
|
|
1368
1370
|
// Text
|
|
1369
|
-
const text = this.createElement(
|
|
1370
|
-
textContent:
|
|
1371
|
+
const text = this.createElement("p", {
|
|
1372
|
+
textContent: "Verifying login...",
|
|
1371
1373
|
style: `
|
|
1372
1374
|
font-size: 16px;
|
|
1373
|
-
color: ${this.config.theme ===
|
|
1375
|
+
color: ${this.config.theme === "dark" ? "#e5e7eb" : "#374151"};
|
|
1374
1376
|
margin: 0;
|
|
1375
1377
|
font-weight: 500;
|
|
1376
1378
|
`,
|
|
@@ -1379,23 +1381,30 @@ export class OnboardingUIWeb {
|
|
|
1379
1381
|
loadingCard.appendChild(text);
|
|
1380
1382
|
// Footer "Powered by Abstraxn"
|
|
1381
1383
|
if (this.config.showFooter !== false) {
|
|
1382
|
-
const textColor = this.config.colors?.text ||
|
|
1383
|
-
|
|
1384
|
-
const
|
|
1385
|
-
|
|
1386
|
-
|
|
1384
|
+
const textColor = this.config.colors?.text ||
|
|
1385
|
+
(this.config.theme === "dark" ? "#9ca3af" : "#6b7280");
|
|
1386
|
+
const brandColor = this.config.colors?.text ||
|
|
1387
|
+
(this.config.theme === "dark" ? "#e5e7eb" : "#374151");
|
|
1388
|
+
const footer = this.createElement("div", {
|
|
1389
|
+
className: "onboarding-footer",
|
|
1390
|
+
});
|
|
1391
|
+
const footerText = this.createElement("p", {
|
|
1392
|
+
className: "onboarding-footer-text",
|
|
1387
1393
|
style: `color: ${textColor}; display: flex; align-items: center; gap: 6px; justify-content: center; font-size: 11px; margin: 0;`,
|
|
1388
1394
|
});
|
|
1389
|
-
const poweredBySpan = this.createElement(
|
|
1395
|
+
const poweredBySpan = this.createElement("span", {
|
|
1396
|
+
textContent: "Powered by",
|
|
1397
|
+
style: `color: ${textColor};`,
|
|
1398
|
+
});
|
|
1390
1399
|
footerText.appendChild(poweredBySpan);
|
|
1391
|
-
const brandContainer = this.createElement(
|
|
1392
|
-
href:
|
|
1393
|
-
target:
|
|
1394
|
-
rel:
|
|
1395
|
-
style:
|
|
1396
|
-
|
|
1400
|
+
const brandContainer = this.createElement("a", {
|
|
1401
|
+
href: "https://www.abstraxn.com/",
|
|
1402
|
+
target: "_blank",
|
|
1403
|
+
rel: "noopener noreferrer",
|
|
1404
|
+
style: "display: inline-flex; align-items: center; gap: 6px; text-decoration: none; cursor: pointer;",
|
|
1405
|
+
"aria-label": "Visit Abstraxn website",
|
|
1397
1406
|
});
|
|
1398
|
-
const logoSvg = this.createElement(
|
|
1407
|
+
const logoSvg = this.createElement("span", {
|
|
1399
1408
|
innerHTML: `
|
|
1400
1409
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none" style="width: 20px; height: 20px; display: inline-block; vertical-align: middle;">
|
|
1401
1410
|
<path d="M47.9082 37.191L23.9541 23.553L0 9.91504L37.7436 -8.13502e-06L47.9082 37.191Z" fill="url(#paint0_linear_1242_781)"/>
|
|
@@ -1414,11 +1423,11 @@ export class OnboardingUIWeb {
|
|
|
1414
1423
|
</defs>
|
|
1415
1424
|
</svg>
|
|
1416
1425
|
`,
|
|
1417
|
-
style:
|
|
1426
|
+
style: "display: inline-flex; align-items: center;",
|
|
1418
1427
|
});
|
|
1419
1428
|
brandContainer.appendChild(logoSvg);
|
|
1420
|
-
const brandText = this.createElement(
|
|
1421
|
-
textContent:
|
|
1429
|
+
const brandText = this.createElement("span", {
|
|
1430
|
+
textContent: "abstraxn",
|
|
1422
1431
|
style: `color: ${brandColor}; font-weight: 700; letter-spacing: 0.2px;`,
|
|
1423
1432
|
});
|
|
1424
1433
|
brandContainer.appendChild(brandText);
|
|
@@ -1431,31 +1440,31 @@ export class OnboardingUIWeb {
|
|
|
1431
1440
|
}
|
|
1432
1441
|
else {
|
|
1433
1442
|
// Ensure modal is visible
|
|
1434
|
-
loadingModalOverlay.style.display =
|
|
1435
|
-
loadingModalOverlay.style.visibility =
|
|
1436
|
-
loadingModalOverlay.style.opacity =
|
|
1437
|
-
loadingModalOverlay.style.zIndex =
|
|
1443
|
+
loadingModalOverlay.style.display = "flex";
|
|
1444
|
+
loadingModalOverlay.style.visibility = "visible";
|
|
1445
|
+
loadingModalOverlay.style.opacity = "1";
|
|
1446
|
+
loadingModalOverlay.style.zIndex = "9999999";
|
|
1438
1447
|
}
|
|
1439
1448
|
// Prevent body scroll
|
|
1440
|
-
document.body.style.overflow =
|
|
1449
|
+
document.body.style.overflow = "hidden";
|
|
1441
1450
|
// Force visibility (defensive check)
|
|
1442
1451
|
if (loadingModalOverlay) {
|
|
1443
|
-
loadingModalOverlay.style.display =
|
|
1444
|
-
loadingModalOverlay.style.visibility =
|
|
1445
|
-
loadingModalOverlay.style.opacity =
|
|
1446
|
-
loadingModalOverlay.style.zIndex =
|
|
1452
|
+
loadingModalOverlay.style.display = "flex";
|
|
1453
|
+
loadingModalOverlay.style.visibility = "visible";
|
|
1454
|
+
loadingModalOverlay.style.opacity = "1";
|
|
1455
|
+
loadingModalOverlay.style.zIndex = "9999999";
|
|
1447
1456
|
}
|
|
1448
1457
|
}
|
|
1449
1458
|
/**
|
|
1450
1459
|
* Hide loading modal overlay
|
|
1451
1460
|
*/
|
|
1452
1461
|
hideLoadingModal() {
|
|
1453
|
-
const loadingModalOverlay = document.getElementById(
|
|
1462
|
+
const loadingModalOverlay = document.getElementById("onboarding-loading-modal-overlay");
|
|
1454
1463
|
if (loadingModalOverlay) {
|
|
1455
|
-
loadingModalOverlay.style.display =
|
|
1456
|
-
loadingModalOverlay.style.visibility =
|
|
1457
|
-
loadingModalOverlay.style.opacity =
|
|
1458
|
-
document.body.style.overflow =
|
|
1464
|
+
loadingModalOverlay.style.display = "none";
|
|
1465
|
+
loadingModalOverlay.style.visibility = "hidden";
|
|
1466
|
+
loadingModalOverlay.style.opacity = "0";
|
|
1467
|
+
document.body.style.overflow = "";
|
|
1459
1468
|
}
|
|
1460
1469
|
}
|
|
1461
1470
|
/**
|
|
@@ -1464,21 +1473,21 @@ export class OnboardingUIWeb {
|
|
|
1464
1473
|
showErrorModal(message) {
|
|
1465
1474
|
// Helper function to close error modal
|
|
1466
1475
|
const closeErrorModal = () => {
|
|
1467
|
-
const overlay = document.getElementById(
|
|
1476
|
+
const overlay = document.getElementById("onboarding-error-modal-overlay");
|
|
1468
1477
|
if (overlay) {
|
|
1469
|
-
overlay.style.display =
|
|
1470
|
-
document.body.style.overflow =
|
|
1478
|
+
overlay.style.display = "none";
|
|
1479
|
+
document.body.style.overflow = "";
|
|
1471
1480
|
// Clear URL params
|
|
1472
1481
|
const url = new URL(window.location.href);
|
|
1473
|
-
url.searchParams.delete(
|
|
1482
|
+
url.searchParams.delete("error");
|
|
1474
1483
|
window.history.replaceState({}, document.title, url.toString());
|
|
1475
1484
|
}
|
|
1476
1485
|
};
|
|
1477
1486
|
// Create modal overlay if it doesn't exist
|
|
1478
|
-
let errorModalOverlay = document.getElementById(
|
|
1487
|
+
let errorModalOverlay = document.getElementById("onboarding-error-modal-overlay");
|
|
1479
1488
|
if (!errorModalOverlay) {
|
|
1480
|
-
errorModalOverlay = this.createElement(
|
|
1481
|
-
id:
|
|
1489
|
+
errorModalOverlay = this.createElement("div", {
|
|
1490
|
+
id: "onboarding-error-modal-overlay",
|
|
1482
1491
|
style: `
|
|
1483
1492
|
position: fixed;
|
|
1484
1493
|
top: 0;
|
|
@@ -1494,15 +1503,15 @@ export class OnboardingUIWeb {
|
|
|
1494
1503
|
`,
|
|
1495
1504
|
});
|
|
1496
1505
|
// Add backdrop click handler to close modal
|
|
1497
|
-
errorModalOverlay.addEventListener(
|
|
1506
|
+
errorModalOverlay.addEventListener("click", (e) => {
|
|
1498
1507
|
if (e.target === errorModalOverlay) {
|
|
1499
1508
|
closeErrorModal();
|
|
1500
1509
|
}
|
|
1501
1510
|
});
|
|
1502
|
-
const errorCard = this.createElement(
|
|
1511
|
+
const errorCard = this.createElement("div", {
|
|
1503
1512
|
className: `onboarding-card onboarding-theme-${this.config.theme}`,
|
|
1504
1513
|
style: `
|
|
1505
|
-
background: ${this.config.theme ===
|
|
1514
|
+
background: ${this.config.theme === "dark" ? "#1f2937" : "white"};
|
|
1506
1515
|
border-radius: 16px;
|
|
1507
1516
|
padding: 40px;
|
|
1508
1517
|
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
@@ -1519,21 +1528,25 @@ export class OnboardingUIWeb {
|
|
|
1519
1528
|
`,
|
|
1520
1529
|
});
|
|
1521
1530
|
// Prevent clicks on card from closing modal
|
|
1522
|
-
errorCard.addEventListener(
|
|
1531
|
+
errorCard.addEventListener("click", (e) => {
|
|
1523
1532
|
e.stopPropagation();
|
|
1524
1533
|
});
|
|
1525
1534
|
// Header with logo
|
|
1526
|
-
const header = this.createElement(
|
|
1527
|
-
className:
|
|
1528
|
-
style:
|
|
1535
|
+
const header = this.createElement("div", {
|
|
1536
|
+
className: "onboarding-header",
|
|
1537
|
+
style: "display: flex; flex-direction: column; align-items: center; gap: 8px; width: 100%; margin-bottom: 24px;",
|
|
1538
|
+
});
|
|
1539
|
+
const logoSection = this.createElement("div", {
|
|
1540
|
+
className: "onboarding-logo-section",
|
|
1529
1541
|
});
|
|
1530
|
-
const logoSection = this.createElement('div', { className: 'onboarding-logo-section' });
|
|
1531
1542
|
if (this.config.logo) {
|
|
1532
|
-
const logoContainer = this.createElement(
|
|
1533
|
-
|
|
1543
|
+
const logoContainer = this.createElement("div", {
|
|
1544
|
+
className: "onboarding-logo-container",
|
|
1545
|
+
});
|
|
1546
|
+
const logoImg = this.createElement("img", {
|
|
1534
1547
|
src: this.config.logo,
|
|
1535
|
-
alt:
|
|
1536
|
-
className:
|
|
1548
|
+
alt: "Abstraxn",
|
|
1549
|
+
className: "onboarding-logo-img",
|
|
1537
1550
|
});
|
|
1538
1551
|
logoContainer.appendChild(logoImg);
|
|
1539
1552
|
logoSection.appendChild(logoContainer);
|
|
@@ -1541,79 +1554,86 @@ export class OnboardingUIWeb {
|
|
|
1541
1554
|
header.appendChild(logoSection);
|
|
1542
1555
|
errorCard.appendChild(header);
|
|
1543
1556
|
// Error Icon
|
|
1544
|
-
const iconContainer = this.createElement(
|
|
1545
|
-
style:
|
|
1546
|
-
});
|
|
1547
|
-
if (this.config.theme ===
|
|
1548
|
-
iconContainer.style.backgroundColor =
|
|
1549
|
-
}
|
|
1550
|
-
const iconSvg = document.createElementNS(
|
|
1551
|
-
iconSvg.setAttribute(
|
|
1552
|
-
iconSvg.setAttribute(
|
|
1553
|
-
iconSvg.setAttribute(
|
|
1554
|
-
iconSvg.setAttribute(
|
|
1555
|
-
iconSvg.setAttribute(
|
|
1556
|
-
iconSvg.setAttribute(
|
|
1557
|
-
iconSvg.setAttribute(
|
|
1558
|
-
iconSvg.setAttribute(
|
|
1559
|
-
const circle = document.createElementNS(
|
|
1560
|
-
circle.setAttribute(
|
|
1561
|
-
circle.setAttribute(
|
|
1562
|
-
circle.setAttribute(
|
|
1557
|
+
const iconContainer = this.createElement("div", {
|
|
1558
|
+
style: "width: 64px; height: 64px; background-color: #fee2e2; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-bottom: 20px;",
|
|
1559
|
+
});
|
|
1560
|
+
if (this.config.theme === "dark") {
|
|
1561
|
+
iconContainer.style.backgroundColor = "rgba(220, 38, 38, 0.2)";
|
|
1562
|
+
}
|
|
1563
|
+
const iconSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
1564
|
+
iconSvg.setAttribute("width", "32");
|
|
1565
|
+
iconSvg.setAttribute("height", "32");
|
|
1566
|
+
iconSvg.setAttribute("viewBox", "0 0 24 24");
|
|
1567
|
+
iconSvg.setAttribute("fill", "none");
|
|
1568
|
+
iconSvg.setAttribute("stroke", "#dc2626");
|
|
1569
|
+
iconSvg.setAttribute("stroke-width", "2");
|
|
1570
|
+
iconSvg.setAttribute("stroke-linecap", "round");
|
|
1571
|
+
iconSvg.setAttribute("stroke-linejoin", "round");
|
|
1572
|
+
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
1573
|
+
circle.setAttribute("cx", "12");
|
|
1574
|
+
circle.setAttribute("cy", "12");
|
|
1575
|
+
circle.setAttribute("r", "10");
|
|
1563
1576
|
iconSvg.appendChild(circle);
|
|
1564
|
-
const line1 = document.createElementNS(
|
|
1565
|
-
line1.setAttribute(
|
|
1566
|
-
line1.setAttribute(
|
|
1567
|
-
line1.setAttribute(
|
|
1568
|
-
line1.setAttribute(
|
|
1577
|
+
const line1 = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
1578
|
+
line1.setAttribute("x1", "12");
|
|
1579
|
+
line1.setAttribute("y1", "8");
|
|
1580
|
+
line1.setAttribute("x2", "12");
|
|
1581
|
+
line1.setAttribute("y2", "12");
|
|
1569
1582
|
iconSvg.appendChild(line1);
|
|
1570
|
-
const line2 = document.createElementNS(
|
|
1571
|
-
line2.setAttribute(
|
|
1572
|
-
line2.setAttribute(
|
|
1573
|
-
line2.setAttribute(
|
|
1574
|
-
line2.setAttribute(
|
|
1583
|
+
const line2 = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
1584
|
+
line2.setAttribute("x1", "12");
|
|
1585
|
+
line2.setAttribute("y1", "16");
|
|
1586
|
+
line2.setAttribute("x2", "12.01");
|
|
1587
|
+
line2.setAttribute("y2", "16");
|
|
1575
1588
|
iconSvg.appendChild(line2);
|
|
1576
1589
|
iconContainer.appendChild(iconSvg);
|
|
1577
1590
|
errorCard.appendChild(iconContainer);
|
|
1578
1591
|
// Title
|
|
1579
|
-
const title = this.createElement(
|
|
1580
|
-
textContent:
|
|
1581
|
-
style: `font-size: 20px; font-weight: 600; margin: 0 0 12px 0; color: ${this.config.theme ===
|
|
1592
|
+
const title = this.createElement("h3", {
|
|
1593
|
+
textContent: "Authentication Failed",
|
|
1594
|
+
style: `font-size: 20px; font-weight: 600; margin: 0 0 12px 0; color: ${this.config.theme === "dark" ? "#ffffff" : "#111827"};`,
|
|
1582
1595
|
});
|
|
1583
1596
|
errorCard.appendChild(title);
|
|
1584
1597
|
// Message
|
|
1585
|
-
const msg = this.createElement(
|
|
1598
|
+
const msg = this.createElement("p", {
|
|
1586
1599
|
textContent: message,
|
|
1587
|
-
style: `font-size: 14px; color: ${this.config.theme ===
|
|
1600
|
+
style: `font-size: 14px; color: ${this.config.theme === "dark" ? "#e5e7eb" : "#374151"}; margin: 0 0 24px 0; line-height: 1.5; max-width: 100%; word-break: break-word;`,
|
|
1588
1601
|
});
|
|
1589
1602
|
errorCard.appendChild(msg);
|
|
1590
1603
|
// OK Button
|
|
1591
|
-
const okButton = this.createElement(
|
|
1592
|
-
className:
|
|
1593
|
-
textContent:
|
|
1594
|
-
style:
|
|
1604
|
+
const okButton = this.createElement("button", {
|
|
1605
|
+
className: "onboarding-button onboarding-button-primary",
|
|
1606
|
+
textContent: "OK",
|
|
1607
|
+
style: "width: 100%; max-width: 200px;",
|
|
1595
1608
|
});
|
|
1596
|
-
okButton.addEventListener(
|
|
1609
|
+
okButton.addEventListener("click", closeErrorModal);
|
|
1597
1610
|
errorCard.appendChild(okButton);
|
|
1598
1611
|
// Footer "Powered by Abstraxn"
|
|
1599
1612
|
if (this.config.showFooter !== false) {
|
|
1600
|
-
const textColor = this.config.colors?.text ||
|
|
1601
|
-
|
|
1602
|
-
const
|
|
1603
|
-
|
|
1604
|
-
|
|
1613
|
+
const textColor = this.config.colors?.text ||
|
|
1614
|
+
(this.config.theme === "dark" ? "#9ca3af" : "#6b7280");
|
|
1615
|
+
const brandColor = this.config.colors?.text ||
|
|
1616
|
+
(this.config.theme === "dark" ? "#e5e7eb" : "#374151");
|
|
1617
|
+
const footer = this.createElement("div", {
|
|
1618
|
+
className: "onboarding-footer",
|
|
1619
|
+
});
|
|
1620
|
+
const footerText = this.createElement("p", {
|
|
1621
|
+
className: "onboarding-footer-text",
|
|
1605
1622
|
style: `color: ${textColor}; display: flex; align-items: center; gap: 6px; justify-content: center; font-size: 11px; margin: 0; margin-top: 24px;`,
|
|
1606
1623
|
});
|
|
1607
|
-
const poweredBySpan = this.createElement(
|
|
1624
|
+
const poweredBySpan = this.createElement("span", {
|
|
1625
|
+
textContent: "Powered by",
|
|
1626
|
+
style: `color: ${textColor};`,
|
|
1627
|
+
});
|
|
1608
1628
|
footerText.appendChild(poweredBySpan);
|
|
1609
|
-
const brandContainer = this.createElement(
|
|
1610
|
-
href:
|
|
1611
|
-
target:
|
|
1612
|
-
rel:
|
|
1613
|
-
style:
|
|
1614
|
-
|
|
1629
|
+
const brandContainer = this.createElement("a", {
|
|
1630
|
+
href: "https://www.abstraxn.com/",
|
|
1631
|
+
target: "_blank",
|
|
1632
|
+
rel: "noopener noreferrer",
|
|
1633
|
+
style: "display: inline-flex; align-items: center; gap: 6px; text-decoration: none; cursor: pointer;",
|
|
1634
|
+
"aria-label": "Visit Abstraxn website",
|
|
1615
1635
|
});
|
|
1616
|
-
const logoSvg = this.createElement(
|
|
1636
|
+
const logoSvg = this.createElement("span", {
|
|
1617
1637
|
innerHTML: `
|
|
1618
1638
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none" style="width: 20px; height: 20px; display: inline-block; vertical-align: middle;">
|
|
1619
1639
|
<path d="M47.9082 37.191L23.9541 23.553L0 9.91504L37.7436 -8.13502e-06L47.9082 37.191Z" fill="url(#paint0_linear_error_modal)"/>
|
|
@@ -1632,11 +1652,11 @@ export class OnboardingUIWeb {
|
|
|
1632
1652
|
</defs>
|
|
1633
1653
|
</svg>
|
|
1634
1654
|
`,
|
|
1635
|
-
style:
|
|
1655
|
+
style: "display: inline-flex; align-items: center;",
|
|
1636
1656
|
});
|
|
1637
1657
|
brandContainer.appendChild(logoSvg);
|
|
1638
|
-
const brandText = this.createElement(
|
|
1639
|
-
textContent:
|
|
1658
|
+
const brandText = this.createElement("span", {
|
|
1659
|
+
textContent: "abstraxn",
|
|
1640
1660
|
style: `color: ${brandColor}; font-weight: 700; letter-spacing: 0.2px;`,
|
|
1641
1661
|
});
|
|
1642
1662
|
brandContainer.appendChild(brandText);
|
|
@@ -1649,13 +1669,13 @@ export class OnboardingUIWeb {
|
|
|
1649
1669
|
}
|
|
1650
1670
|
else {
|
|
1651
1671
|
// Update message if overlay exists
|
|
1652
|
-
const msgEl = errorModalOverlay.querySelector(
|
|
1672
|
+
const msgEl = errorModalOverlay.querySelector("p");
|
|
1653
1673
|
if (msgEl)
|
|
1654
1674
|
msgEl.textContent = message;
|
|
1655
|
-
errorModalOverlay.style.display =
|
|
1675
|
+
errorModalOverlay.style.display = "flex";
|
|
1656
1676
|
}
|
|
1657
1677
|
// Prevent body scroll
|
|
1658
|
-
document.body.style.overflow =
|
|
1678
|
+
document.body.style.overflow = "hidden";
|
|
1659
1679
|
}
|
|
1660
1680
|
/**
|
|
1661
1681
|
* Inject CSS styles into the document head (only once)
|
|
@@ -1665,20 +1685,20 @@ export class OnboardingUIWeb {
|
|
|
1665
1685
|
return;
|
|
1666
1686
|
}
|
|
1667
1687
|
// Check if styles are already injected
|
|
1668
|
-
const existingStyle = document.getElementById(
|
|
1688
|
+
const existingStyle = document.getElementById("onboarding-ui-styles");
|
|
1669
1689
|
if (existingStyle) {
|
|
1670
1690
|
OnboardingUIWeb.stylesInjected = true;
|
|
1671
1691
|
return;
|
|
1672
1692
|
}
|
|
1673
1693
|
// Create and inject style element
|
|
1674
|
-
const styleElement = document.createElement(
|
|
1675
|
-
styleElement.id =
|
|
1694
|
+
const styleElement = document.createElement("style");
|
|
1695
|
+
styleElement.id = "onboarding-ui-styles";
|
|
1676
1696
|
styleElement.textContent = ONBOARDING_UI_STYLES;
|
|
1677
1697
|
document.head.appendChild(styleElement);
|
|
1678
1698
|
// Inject custom CSS if provided
|
|
1679
1699
|
if (this.config.customCSS) {
|
|
1680
|
-
const customStyleElement = document.createElement(
|
|
1681
|
-
customStyleElement.id =
|
|
1700
|
+
const customStyleElement = document.createElement("style");
|
|
1701
|
+
customStyleElement.id = "onboarding-ui-custom-styles";
|
|
1682
1702
|
customStyleElement.textContent = this.config.customCSS;
|
|
1683
1703
|
document.head.appendChild(customStyleElement);
|
|
1684
1704
|
}
|
|
@@ -1688,8 +1708,8 @@ export class OnboardingUIWeb {
|
|
|
1688
1708
|
}
|
|
1689
1709
|
OnboardingUIWeb.stylesInjected = true;
|
|
1690
1710
|
// Inject utility styles for loading/error modes
|
|
1691
|
-
const utilityStyle = document.createElement(
|
|
1692
|
-
utilityStyle.id =
|
|
1711
|
+
const utilityStyle = document.createElement("style");
|
|
1712
|
+
utilityStyle.id = "onboarding-utility-styles";
|
|
1693
1713
|
utilityStyle.textContent = `
|
|
1694
1714
|
.onboarding-card.onboarding-mode-loading > *:not(.onboarding-loading-container):not(.onboarding-header):not(.onboarding-footer),
|
|
1695
1715
|
.onboarding-card.onboarding-mode-error > *:not(.onboarding-error-container):not(.onboarding-header):not(.onboarding-footer) {
|
|
@@ -1705,9 +1725,9 @@ export class OnboardingUIWeb {
|
|
|
1705
1725
|
if (!this.config.colors)
|
|
1706
1726
|
return;
|
|
1707
1727
|
const root = this.rootElement || document.documentElement;
|
|
1708
|
-
const style = document.createElement(
|
|
1709
|
-
style.id =
|
|
1710
|
-
let css =
|
|
1728
|
+
const style = document.createElement("style");
|
|
1729
|
+
style.id = "onboarding-ui-colors";
|
|
1730
|
+
let css = "";
|
|
1711
1731
|
if (this.config.colors.primary) {
|
|
1712
1732
|
css += `.onboarding-button-primary { background-color: ${this.config.colors.primary} !important; background: ${this.config.colors.primary} !important; }`;
|
|
1713
1733
|
css += `.onboarding-footer-brand { color: ${this.config.colors.primary} !important; }`;
|
|
@@ -1726,7 +1746,7 @@ export class OnboardingUIWeb {
|
|
|
1726
1746
|
css += `.onboarding-input { border-color: ${this.config.colors.border} !important; }`;
|
|
1727
1747
|
}
|
|
1728
1748
|
if (this.config.colors.error) {
|
|
1729
|
-
css += `.onboarding-error {
|
|
1749
|
+
css += `.onboarding-error { color: ${this.config.colors.error} !important; }`;
|
|
1730
1750
|
}
|
|
1731
1751
|
style.textContent = css;
|
|
1732
1752
|
document.head.appendChild(style);
|
|
@@ -1741,7 +1761,7 @@ export class OnboardingUIWeb {
|
|
|
1741
1761
|
}
|
|
1742
1762
|
else {
|
|
1743
1763
|
if (this.config.container) {
|
|
1744
|
-
if (typeof this.config.container ===
|
|
1764
|
+
if (typeof this.config.container === "string") {
|
|
1745
1765
|
this.container = document.querySelector(this.config.container);
|
|
1746
1766
|
if (!this.container) {
|
|
1747
1767
|
throw new Error(`Container element not found: ${this.config.container}`);
|
|
@@ -1775,41 +1795,23 @@ export class OnboardingUIWeb {
|
|
|
1775
1795
|
*/
|
|
1776
1796
|
renderAsModal() {
|
|
1777
1797
|
// Create modal overlay (backdrop) - start hidden to prevent flicker
|
|
1778
|
-
this.modalOverlay = this.createElement(
|
|
1779
|
-
className:
|
|
1780
|
-
style:
|
|
1798
|
+
this.modalOverlay = this.createElement("div", {
|
|
1799
|
+
className: "onboarding-modal-overlay",
|
|
1800
|
+
style: "display: none;", // Start hidden by default
|
|
1781
1801
|
});
|
|
1782
1802
|
// Create modal content wrapper
|
|
1783
|
-
this.modalContent = this.createElement(
|
|
1803
|
+
this.modalContent = this.createElement("div", {
|
|
1784
1804
|
className: `onboarding-modal-content onboarding-theme-${this.config.theme}`,
|
|
1785
|
-
role:
|
|
1786
|
-
|
|
1787
|
-
|
|
1805
|
+
role: "dialog",
|
|
1806
|
+
"aria-modal": "true",
|
|
1807
|
+
"aria-labelledby": "onboarding-title",
|
|
1788
1808
|
tabIndex: -1,
|
|
1789
1809
|
});
|
|
1790
1810
|
// Create root element for the form
|
|
1791
|
-
this.rootElement = this.createElement(
|
|
1811
|
+
this.rootElement = this.createElement("div", {
|
|
1792
1812
|
className: `onboarding-container onboarding-theme-${this.config.theme} ${this.config.className}`,
|
|
1793
1813
|
style: this.parseStyle(this.config.style),
|
|
1794
1814
|
});
|
|
1795
|
-
// Close button
|
|
1796
|
-
if (this.config.showCloseButton) {
|
|
1797
|
-
this.closeButton = this.createElement('button', {
|
|
1798
|
-
className: 'onboarding-modal-close',
|
|
1799
|
-
type: 'button',
|
|
1800
|
-
innerHTML: '×',
|
|
1801
|
-
'aria-label': 'Close modal',
|
|
1802
|
-
'aria-describedby': 'close-button-description',
|
|
1803
|
-
});
|
|
1804
|
-
this.closeButton.addEventListener('click', () => this.close());
|
|
1805
|
-
this.closeButton.addEventListener('keydown', (e) => {
|
|
1806
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
1807
|
-
e.preventDefault();
|
|
1808
|
-
this.close();
|
|
1809
|
-
}
|
|
1810
|
-
});
|
|
1811
|
-
this.modalContent.appendChild(this.closeButton);
|
|
1812
|
-
}
|
|
1813
1815
|
// Build the form content
|
|
1814
1816
|
this.buildFormContent();
|
|
1815
1817
|
// Append form to root, root to modal content, modal content to overlay
|
|
@@ -1817,33 +1819,30 @@ export class OnboardingUIWeb {
|
|
|
1817
1819
|
this.modalOverlay.appendChild(this.modalContent);
|
|
1818
1820
|
// Add click handler for backdrop
|
|
1819
1821
|
if (this.config.closeOnBackdropClick) {
|
|
1820
|
-
this.modalOverlay.addEventListener(
|
|
1822
|
+
this.modalOverlay.addEventListener("click", (e) => {
|
|
1821
1823
|
if (e.target === this.modalOverlay) {
|
|
1822
1824
|
this.close();
|
|
1823
1825
|
}
|
|
1824
1826
|
});
|
|
1825
1827
|
}
|
|
1826
1828
|
// Prevent body scroll when modal is open
|
|
1827
|
-
document.body.style.overflow =
|
|
1829
|
+
document.body.style.overflow = "hidden";
|
|
1828
1830
|
// Append to body
|
|
1829
1831
|
document.body.appendChild(this.modalOverlay);
|
|
1830
1832
|
// Add animation class
|
|
1831
1833
|
setTimeout(() => {
|
|
1832
1834
|
if (this.modalOverlay) {
|
|
1833
|
-
this.modalOverlay.classList.add(
|
|
1835
|
+
this.modalOverlay.classList.add("onboarding-modal-open");
|
|
1834
1836
|
// Focus management for accessibility
|
|
1835
1837
|
if (this.emailInput) {
|
|
1836
1838
|
this.emailInput.focus();
|
|
1837
1839
|
}
|
|
1838
1840
|
}
|
|
1839
1841
|
}, 10);
|
|
1840
|
-
// Add keyboard navigation
|
|
1841
|
-
this.modalOverlay.addEventListener(
|
|
1842
|
-
if (e.key === 'Escape' && this.config.showCloseButton) {
|
|
1843
|
-
this.close();
|
|
1844
|
-
}
|
|
1842
|
+
// Add keyboard navigation
|
|
1843
|
+
this.modalOverlay.addEventListener("keydown", (e) => {
|
|
1845
1844
|
// Trap focus within modal
|
|
1846
|
-
if (e.key ===
|
|
1845
|
+
if (e.key === "Tab") {
|
|
1847
1846
|
this.trapFocus(e);
|
|
1848
1847
|
}
|
|
1849
1848
|
});
|
|
@@ -1873,7 +1872,7 @@ export class OnboardingUIWeb {
|
|
|
1873
1872
|
if (!this.container)
|
|
1874
1873
|
return;
|
|
1875
1874
|
// Create root element
|
|
1876
|
-
this.rootElement = this.createElement(
|
|
1875
|
+
this.rootElement = this.createElement("div", {
|
|
1877
1876
|
className: `onboarding-container onboarding-inline onboarding-theme-${this.config.theme} ${this.config.className}`,
|
|
1878
1877
|
style: this.parseStyle(this.config.style),
|
|
1879
1878
|
});
|
|
@@ -1884,7 +1883,7 @@ export class OnboardingUIWeb {
|
|
|
1884
1883
|
this.container.appendChild(this.rootElement);
|
|
1885
1884
|
}
|
|
1886
1885
|
else {
|
|
1887
|
-
this.container.innerHTML =
|
|
1886
|
+
this.container.innerHTML = "";
|
|
1888
1887
|
this.container.appendChild(this.rootElement);
|
|
1889
1888
|
}
|
|
1890
1889
|
}
|
|
@@ -1895,95 +1894,110 @@ export class OnboardingUIWeb {
|
|
|
1895
1894
|
if (!this.rootElement)
|
|
1896
1895
|
return;
|
|
1897
1896
|
// Create card
|
|
1898
|
-
const card = this.createElement(
|
|
1897
|
+
const card = this.createElement("div", { className: "onboarding-card" });
|
|
1899
1898
|
// Header with logo at top
|
|
1900
|
-
const header = this.createElement(
|
|
1899
|
+
const header = this.createElement("div", {
|
|
1900
|
+
className: "onboarding-header",
|
|
1901
|
+
});
|
|
1901
1902
|
// Logo section (centered at top)
|
|
1902
|
-
const logoSection = this.createElement('div', { className: 'onboarding-logo-section' });
|
|
1903
1903
|
if (this.config.logo) {
|
|
1904
|
-
const
|
|
1905
|
-
|
|
1904
|
+
const logoSection = this.createElement("div", {
|
|
1905
|
+
className: "onboarding-logo-section",
|
|
1906
|
+
});
|
|
1907
|
+
const logoContainer = this.createElement("div", {
|
|
1908
|
+
className: "onboarding-logo-container",
|
|
1909
|
+
});
|
|
1910
|
+
const logoImg = this.createElement("img", {
|
|
1906
1911
|
src: this.config.logo,
|
|
1907
|
-
alt:
|
|
1908
|
-
className:
|
|
1912
|
+
alt: "Logo",
|
|
1913
|
+
className: "onboarding-logo-img",
|
|
1909
1914
|
});
|
|
1910
1915
|
logoContainer.appendChild(logoImg);
|
|
1911
1916
|
logoSection.appendChild(logoContainer);
|
|
1917
|
+
header.appendChild(logoSection);
|
|
1912
1918
|
}
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
id: 'onboarding-title',
|
|
1919
|
+
// Onboarding title (always shown, default: "Sign In")
|
|
1920
|
+
const title = this.createElement("h1", {
|
|
1921
|
+
className: "onboarding-title",
|
|
1922
|
+
textContent: this.config.onboardTitle || "Sign In",
|
|
1923
|
+
id: "onboarding-title",
|
|
1919
1924
|
});
|
|
1920
1925
|
header.appendChild(title);
|
|
1921
1926
|
// Form
|
|
1922
|
-
this.emailForm = this.createElement(
|
|
1923
|
-
className:
|
|
1924
|
-
|
|
1927
|
+
this.emailForm = this.createElement("form", {
|
|
1928
|
+
className: "onboarding-form",
|
|
1929
|
+
"aria-label": "Sign In form",
|
|
1925
1930
|
noValidate: true,
|
|
1926
1931
|
});
|
|
1927
1932
|
// Email input group
|
|
1928
|
-
const emailGroup = this.createElement(
|
|
1933
|
+
const emailGroup = this.createElement("div", {
|
|
1934
|
+
className: "onboarding-input-group",
|
|
1935
|
+
});
|
|
1929
1936
|
// Email label
|
|
1930
|
-
const emailLabel = this.createElement(
|
|
1931
|
-
className:
|
|
1932
|
-
textContent: this.config.labels?.emailLabel ||
|
|
1933
|
-
htmlFor:
|
|
1937
|
+
const emailLabel = this.createElement("label", {
|
|
1938
|
+
className: "onboarding-input-label",
|
|
1939
|
+
textContent: this.config.labels?.emailLabel || "Email Address",
|
|
1940
|
+
htmlFor: "onboarding-email-input",
|
|
1934
1941
|
});
|
|
1935
1942
|
emailGroup.appendChild(emailLabel);
|
|
1936
|
-
const emailWrapper = this.createElement(
|
|
1943
|
+
const emailWrapper = this.createElement("div", {
|
|
1944
|
+
className: "onboarding-input-wrapper",
|
|
1945
|
+
});
|
|
1937
1946
|
// Email icon SVG
|
|
1938
1947
|
const emailIcon = this.createEmailIcon();
|
|
1939
1948
|
emailWrapper.appendChild(emailIcon);
|
|
1940
1949
|
// Get auth methods to check if all are enabled
|
|
1941
|
-
const authMethods = this.config.authMethods || [
|
|
1942
|
-
const showEmail = authMethods.includes(
|
|
1943
|
-
const showGoogle = authMethods.includes(
|
|
1944
|
-
const showTwitter = authMethods.includes(
|
|
1945
|
-
const showDiscord = authMethods.includes(
|
|
1946
|
-
const showPasskey = authMethods.includes(
|
|
1950
|
+
const authMethods = this.config.authMethods || ["otp", "google"];
|
|
1951
|
+
const showEmail = authMethods.includes("otp");
|
|
1952
|
+
const showGoogle = authMethods.includes("google");
|
|
1953
|
+
const showTwitter = authMethods.includes("twitter");
|
|
1954
|
+
const showDiscord = authMethods.includes("discord");
|
|
1955
|
+
const showPasskey = authMethods.includes("passkey");
|
|
1947
1956
|
const socialMethods = [
|
|
1948
|
-
{ key:
|
|
1949
|
-
{ key:
|
|
1950
|
-
{ key:
|
|
1957
|
+
{ key: "google", show: showGoogle },
|
|
1958
|
+
{ key: "twitter", show: showTwitter },
|
|
1959
|
+
{ key: "discord", show: showDiscord },
|
|
1951
1960
|
].filter((m) => m.show);
|
|
1952
1961
|
// Treat “all configs” as email + passkey + all socials present
|
|
1953
1962
|
const allAuthMethodsEnabled = showEmail && showPasskey && showGoogle && showTwitter && showDiscord;
|
|
1954
1963
|
// Email input
|
|
1955
|
-
this.emailInput = this.createElement(
|
|
1956
|
-
type:
|
|
1957
|
-
id:
|
|
1958
|
-
placeholder: this.config.labels?.emailPlaceholder ||
|
|
1959
|
-
className:
|
|
1964
|
+
this.emailInput = this.createElement("input", {
|
|
1965
|
+
type: "email",
|
|
1966
|
+
id: "onboarding-email-input",
|
|
1967
|
+
placeholder: this.config.labels?.emailPlaceholder || "Enter your email",
|
|
1968
|
+
className: "onboarding-input",
|
|
1960
1969
|
required: true,
|
|
1961
|
-
autocomplete:
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
style: allAuthMethodsEnabled ?
|
|
1970
|
+
autocomplete: "email",
|
|
1971
|
+
"aria-label": this.config.labels?.emailLabel || "Email Address",
|
|
1972
|
+
"aria-required": "true",
|
|
1973
|
+
style: allAuthMethodsEnabled ? "padding-right: 48px;" : "",
|
|
1965
1974
|
});
|
|
1966
1975
|
emailWrapper.appendChild(this.emailInput);
|
|
1967
1976
|
// Add right arrow button inside input when all auth methods are enabled
|
|
1968
1977
|
if (allAuthMethodsEnabled) {
|
|
1969
|
-
this.emailArrowButton = this.createElement(
|
|
1970
|
-
type:
|
|
1971
|
-
className:
|
|
1972
|
-
|
|
1978
|
+
this.emailArrowButton = this.createElement("button", {
|
|
1979
|
+
type: "button",
|
|
1980
|
+
className: "onboarding-input-arrow-button",
|
|
1981
|
+
"aria-label": this.config.labels?.emailButton || "Continue with email",
|
|
1982
|
+
disabled: true,
|
|
1973
1983
|
});
|
|
1974
1984
|
const arrowIcon = this.createArrowIcon();
|
|
1975
|
-
arrowIcon.setAttribute(
|
|
1985
|
+
arrowIcon.setAttribute("aria-hidden", "true");
|
|
1976
1986
|
this.emailArrowButton.appendChild(arrowIcon);
|
|
1977
1987
|
// Add click handler to submit form
|
|
1978
|
-
this.emailArrowButton.addEventListener(
|
|
1988
|
+
this.emailArrowButton.addEventListener("click", (e) => {
|
|
1979
1989
|
e.preventDefault();
|
|
1980
|
-
if (this.emailInput &&
|
|
1990
|
+
if (this.emailInput &&
|
|
1991
|
+
this.emailInput.value.trim() &&
|
|
1992
|
+
isValidEmail(this.emailInput.value.trim())) {
|
|
1981
1993
|
this.emailForm?.requestSubmit();
|
|
1982
1994
|
}
|
|
1983
1995
|
});
|
|
1984
1996
|
// Also submit on Enter key
|
|
1985
|
-
this.emailInput.addEventListener(
|
|
1986
|
-
if (e.key ===
|
|
1997
|
+
this.emailInput.addEventListener("keydown", (e) => {
|
|
1998
|
+
if (e.key === "Enter" &&
|
|
1999
|
+
this.emailInput?.value.trim() &&
|
|
2000
|
+
isValidEmail(this.emailInput.value.trim())) {
|
|
1987
2001
|
e.preventDefault();
|
|
1988
2002
|
this.emailForm?.requestSubmit();
|
|
1989
2003
|
}
|
|
@@ -1993,48 +2007,51 @@ export class OnboardingUIWeb {
|
|
|
1993
2007
|
emailGroup.appendChild(emailWrapper);
|
|
1994
2008
|
this.emailForm.appendChild(emailGroup);
|
|
1995
2009
|
// OTP input group (initially hidden)
|
|
1996
|
-
this.otpGroup = this.createElement(
|
|
1997
|
-
className:
|
|
1998
|
-
style:
|
|
2010
|
+
this.otpGroup = this.createElement("div", {
|
|
2011
|
+
className: "onboarding-input-group",
|
|
2012
|
+
style: "display: none;",
|
|
1999
2013
|
});
|
|
2000
2014
|
// OTP label
|
|
2001
|
-
const otpLabel = this.createElement(
|
|
2002
|
-
className:
|
|
2003
|
-
textContent: this.config.labels?.otpLabel ||
|
|
2004
|
-
htmlFor:
|
|
2015
|
+
const otpLabel = this.createElement("label", {
|
|
2016
|
+
className: "onboarding-input-label",
|
|
2017
|
+
textContent: this.config.labels?.otpLabel || "Verification code",
|
|
2018
|
+
htmlFor: "onboarding-otp-input",
|
|
2005
2019
|
});
|
|
2006
2020
|
this.otpGroup.appendChild(otpLabel);
|
|
2007
|
-
const otpWrapper = this.createElement(
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2021
|
+
const otpWrapper = this.createElement("div", {
|
|
2022
|
+
className: "onboarding-input-wrapper",
|
|
2023
|
+
});
|
|
2024
|
+
this.otpInput = this.createElement("input", {
|
|
2025
|
+
type: "text",
|
|
2026
|
+
id: "onboarding-otp-input",
|
|
2027
|
+
placeholder: this.config.labels?.otpPlaceholder || "Enter 6-digit code",
|
|
2028
|
+
className: "onboarding-input",
|
|
2013
2029
|
required: false, // Don't require initially since it's hidden
|
|
2014
2030
|
maxLength: 6,
|
|
2015
|
-
inputMode:
|
|
2016
|
-
pattern:
|
|
2017
|
-
autocomplete:
|
|
2018
|
-
|
|
2031
|
+
inputMode: "numeric",
|
|
2032
|
+
pattern: "[0-9]*",
|
|
2033
|
+
autocomplete: "one-time-code",
|
|
2034
|
+
"aria-label": this.config.labels?.otpLabel || "Verification code",
|
|
2019
2035
|
});
|
|
2020
2036
|
otpWrapper.appendChild(this.otpInput);
|
|
2021
2037
|
this.otpGroup.appendChild(otpWrapper);
|
|
2022
2038
|
this.emailForm.appendChild(this.otpGroup);
|
|
2023
2039
|
// Error element
|
|
2024
|
-
this.errorElement = this.createElement(
|
|
2025
|
-
className:
|
|
2026
|
-
style:
|
|
2027
|
-
role:
|
|
2028
|
-
|
|
2040
|
+
this.errorElement = this.createElement("div", {
|
|
2041
|
+
className: "onboarding-error",
|
|
2042
|
+
style: "display: none;",
|
|
2043
|
+
role: "alert",
|
|
2044
|
+
"aria-live": "polite",
|
|
2029
2045
|
});
|
|
2030
2046
|
this.emailForm.appendChild(this.errorElement);
|
|
2031
2047
|
// Continue button (hide if all auth methods are enabled)
|
|
2032
|
-
this.continueButton = this.createElement(
|
|
2033
|
-
type:
|
|
2034
|
-
className:
|
|
2035
|
-
textContent: this.config.labels?.emailButton ||
|
|
2036
|
-
|
|
2037
|
-
style: allAuthMethodsEnabled ?
|
|
2048
|
+
this.continueButton = this.createElement("button", {
|
|
2049
|
+
type: "submit",
|
|
2050
|
+
className: "onboarding-button onboarding-button-primary",
|
|
2051
|
+
textContent: this.config.labels?.emailButton || "Continue",
|
|
2052
|
+
"aria-label": this.config.labels?.emailButton || "Continue with email",
|
|
2053
|
+
style: allAuthMethodsEnabled ? "display: none;" : "",
|
|
2054
|
+
disabled: true,
|
|
2038
2055
|
});
|
|
2039
2056
|
this.emailForm.appendChild(this.continueButton);
|
|
2040
2057
|
card.appendChild(header);
|
|
@@ -2045,24 +2062,26 @@ export class OnboardingUIWeb {
|
|
|
2045
2062
|
}
|
|
2046
2063
|
else {
|
|
2047
2064
|
// Still create the form but hide it (needed for OTP flow)
|
|
2048
|
-
this.emailForm.style.display =
|
|
2065
|
+
this.emailForm.style.display = "none";
|
|
2049
2066
|
card.appendChild(this.emailForm);
|
|
2050
2067
|
}
|
|
2051
2068
|
// Divider (show if email plus any social method is enabled)
|
|
2052
2069
|
if (showEmail && socialMethods.length > 0) {
|
|
2053
|
-
this.divider = this.createElement(
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2070
|
+
this.divider = this.createElement("div", {
|
|
2071
|
+
className: "onboarding-divider",
|
|
2072
|
+
});
|
|
2073
|
+
const dividerText = this.createElement("span", {
|
|
2074
|
+
className: "onboarding-divider-text",
|
|
2075
|
+
textContent: "or",
|
|
2057
2076
|
});
|
|
2058
2077
|
this.divider.appendChild(dividerText);
|
|
2059
2078
|
card.appendChild(this.divider);
|
|
2060
2079
|
}
|
|
2061
2080
|
else {
|
|
2062
2081
|
// Create divider element but hide it
|
|
2063
|
-
this.divider = this.createElement(
|
|
2064
|
-
className:
|
|
2065
|
-
style:
|
|
2082
|
+
this.divider = this.createElement("div", {
|
|
2083
|
+
className: "onboarding-divider",
|
|
2084
|
+
style: "display: none;",
|
|
2066
2085
|
});
|
|
2067
2086
|
card.appendChild(this.divider);
|
|
2068
2087
|
}
|
|
@@ -2070,17 +2089,19 @@ export class OnboardingUIWeb {
|
|
|
2070
2089
|
if (socialMethods.length > 0) {
|
|
2071
2090
|
if (socialMethods.length === 1) {
|
|
2072
2091
|
const method = socialMethods[0].key;
|
|
2073
|
-
const isGoogle = method ===
|
|
2074
|
-
const isTwitter = method ===
|
|
2075
|
-
const isDiscord = method ===
|
|
2076
|
-
const button = this.createElement(
|
|
2077
|
-
type:
|
|
2078
|
-
className: isGoogle
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2092
|
+
const isGoogle = method === "google";
|
|
2093
|
+
const isTwitter = method === "twitter";
|
|
2094
|
+
const isDiscord = method === "discord";
|
|
2095
|
+
const button = this.createElement("button", {
|
|
2096
|
+
type: "button",
|
|
2097
|
+
className: isGoogle
|
|
2098
|
+
? "onboarding-button onboarding-button-google"
|
|
2099
|
+
: "onboarding-button onboarding-button-social",
|
|
2100
|
+
"aria-label": this.config.labels?.[`${method}Button`] ||
|
|
2101
|
+
(method === "google"
|
|
2102
|
+
? "Continue with Google"
|
|
2103
|
+
: method === "twitter"
|
|
2104
|
+
? "Continue with X"
|
|
2084
2105
|
: `Continue with ${method.charAt(0).toUpperCase() + method.slice(1)}`),
|
|
2085
2106
|
});
|
|
2086
2107
|
const icon = isGoogle
|
|
@@ -2088,13 +2109,13 @@ export class OnboardingUIWeb {
|
|
|
2088
2109
|
: isTwitter
|
|
2089
2110
|
? this.createTwitterIcon()
|
|
2090
2111
|
: this.createDiscordIcon();
|
|
2091
|
-
icon.setAttribute(
|
|
2112
|
+
icon.setAttribute("aria-hidden", "true");
|
|
2092
2113
|
button.appendChild(icon);
|
|
2093
2114
|
const label = this.config.labels?.[`${method}Button`] ||
|
|
2094
|
-
(method ===
|
|
2095
|
-
?
|
|
2096
|
-
: method ===
|
|
2097
|
-
?
|
|
2115
|
+
(method === "google"
|
|
2116
|
+
? "Continue with Google"
|
|
2117
|
+
: method === "twitter"
|
|
2118
|
+
? "Continue with X"
|
|
2098
2119
|
: `Continue with ${method.charAt(0).toUpperCase() + method.slice(1)}`);
|
|
2099
2120
|
button.appendChild(document.createTextNode(` ${label}`));
|
|
2100
2121
|
if (isGoogle) {
|
|
@@ -2109,19 +2130,21 @@ export class OnboardingUIWeb {
|
|
|
2109
2130
|
card.appendChild(button);
|
|
2110
2131
|
}
|
|
2111
2132
|
else {
|
|
2112
|
-
this.socialGrid = this.createElement(
|
|
2133
|
+
this.socialGrid = this.createElement("div", {
|
|
2134
|
+
className: "onboarding-social-grid",
|
|
2135
|
+
});
|
|
2113
2136
|
socialMethods.forEach(({ key: method }) => {
|
|
2114
|
-
const isGoogle = method ===
|
|
2115
|
-
const isTwitter = method ===
|
|
2116
|
-
const isDiscord = method ===
|
|
2117
|
-
const button = this.createElement(
|
|
2118
|
-
type:
|
|
2119
|
-
className:
|
|
2120
|
-
|
|
2121
|
-
(method ===
|
|
2122
|
-
?
|
|
2123
|
-
: method ===
|
|
2124
|
-
?
|
|
2137
|
+
const isGoogle = method === "google";
|
|
2138
|
+
const isTwitter = method === "twitter";
|
|
2139
|
+
const isDiscord = method === "discord";
|
|
2140
|
+
const button = this.createElement("button", {
|
|
2141
|
+
type: "button",
|
|
2142
|
+
className: "onboarding-button-social-icon",
|
|
2143
|
+
"aria-label": this.config.labels?.[`${method}Button`] ||
|
|
2144
|
+
(method === "google"
|
|
2145
|
+
? "Google"
|
|
2146
|
+
: method === "twitter"
|
|
2147
|
+
? "X"
|
|
2125
2148
|
: method.charAt(0).toUpperCase() + method.slice(1)),
|
|
2126
2149
|
});
|
|
2127
2150
|
const icon = isGoogle
|
|
@@ -2129,7 +2152,7 @@ export class OnboardingUIWeb {
|
|
|
2129
2152
|
: isTwitter
|
|
2130
2153
|
? this.createTwitterIcon()
|
|
2131
2154
|
: this.createDiscordIcon();
|
|
2132
|
-
icon.setAttribute(
|
|
2155
|
+
icon.setAttribute("aria-hidden", "true");
|
|
2133
2156
|
button.appendChild(icon);
|
|
2134
2157
|
if (isGoogle) {
|
|
2135
2158
|
this.googleButton = button;
|
|
@@ -2151,10 +2174,12 @@ export class OnboardingUIWeb {
|
|
|
2151
2174
|
}
|
|
2152
2175
|
// Passkey divider (only show if passkey is enabled and there are other auth methods)
|
|
2153
2176
|
if (showPasskey && (showEmail || socialMethods.length > 0)) {
|
|
2154
|
-
this.passkeyDivider = this.createElement(
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2177
|
+
this.passkeyDivider = this.createElement("div", {
|
|
2178
|
+
className: "onboarding-divider",
|
|
2179
|
+
});
|
|
2180
|
+
const passkeyDividerText = this.createElement("span", {
|
|
2181
|
+
className: "onboarding-divider-text",
|
|
2182
|
+
textContent: "or",
|
|
2158
2183
|
});
|
|
2159
2184
|
this.passkeyDivider.appendChild(passkeyDividerText);
|
|
2160
2185
|
card.appendChild(this.passkeyDivider);
|
|
@@ -2165,17 +2190,15 @@ export class OnboardingUIWeb {
|
|
|
2165
2190
|
// Passkey login button (only show if passkey auth is enabled)
|
|
2166
2191
|
if (showPasskey) {
|
|
2167
2192
|
const passkeyBg = this.config.colors?.primary ||
|
|
2168
|
-
(this.config.theme ===
|
|
2193
|
+
(this.config.theme === "dark" ? "#4b5563" : "#ffffff");
|
|
2169
2194
|
const passkeyBorder = this.config.colors?.border ||
|
|
2170
|
-
(this.config.theme ===
|
|
2195
|
+
(this.config.theme === "dark" ? "#6b7280" : "#e5e7eb");
|
|
2171
2196
|
const passkeyTextColor = this.config.colors?.text ||
|
|
2172
|
-
(this.config.theme ===
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
className: 'onboarding-button onboarding-button-passkey',
|
|
2178
|
-
'aria-label': this.config.labels?.passkeyLoginButton || 'Log in with passkey',
|
|
2197
|
+
(this.config.theme === "dark" ? "#ffffff" : "#1f2937");
|
|
2198
|
+
this.passkeyLoginButton = this.createElement("button", {
|
|
2199
|
+
type: "button",
|
|
2200
|
+
className: "onboarding-button onboarding-button-passkey",
|
|
2201
|
+
"aria-label": this.config.labels?.passkeyLoginButton || "Log in with passkey",
|
|
2179
2202
|
style: `
|
|
2180
2203
|
background-color: ${passkeyBg};
|
|
2181
2204
|
color: ${passkeyTextColor};
|
|
@@ -2183,94 +2206,98 @@ export class OnboardingUIWeb {
|
|
|
2183
2206
|
`,
|
|
2184
2207
|
});
|
|
2185
2208
|
const passkeyIcon = this.createPasskeyIcon();
|
|
2186
|
-
passkeyIcon.setAttribute(
|
|
2209
|
+
passkeyIcon.setAttribute("aria-hidden", "true");
|
|
2187
2210
|
this.passkeyLoginButton.appendChild(passkeyIcon);
|
|
2188
|
-
const passkeyText = this.config.labels?.passkeyLoginButton ||
|
|
2211
|
+
const passkeyText = this.config.labels?.passkeyLoginButton || "Log in with passkey";
|
|
2189
2212
|
this.passkeyLoginButton.appendChild(document.createTextNode(` ${passkeyText}`));
|
|
2190
2213
|
card.appendChild(this.passkeyLoginButton);
|
|
2191
2214
|
// Passkey signup link
|
|
2192
|
-
const passkeySignupContainer = this.createElement(
|
|
2193
|
-
style:
|
|
2215
|
+
const passkeySignupContainer = this.createElement("div", {
|
|
2216
|
+
style: "text-align: center; margin-top: 12px;",
|
|
2194
2217
|
});
|
|
2195
|
-
this.passkeySignupLink = this.createElement(
|
|
2196
|
-
className:
|
|
2197
|
-
href:
|
|
2198
|
-
textContent: this.config.labels?.passkeySignupButton ||
|
|
2199
|
-
|
|
2200
|
-
style: `color: ${passkeyLinkColor};`,
|
|
2218
|
+
this.passkeySignupLink = this.createElement("a", {
|
|
2219
|
+
className: "onboarding-passkey-signup-link",
|
|
2220
|
+
href: "#",
|
|
2221
|
+
textContent: this.config.labels?.passkeySignupButton || "Sign up with passkey",
|
|
2222
|
+
"aria-label": this.config.labels?.passkeySignupButton || "Sign up with passkey",
|
|
2201
2223
|
});
|
|
2202
2224
|
passkeySignupContainer.appendChild(this.passkeySignupLink);
|
|
2203
2225
|
card.appendChild(passkeySignupContainer);
|
|
2204
2226
|
// Passkey error element (local to passkey section)
|
|
2205
|
-
this.passkeyErrorElement = this.createElement(
|
|
2206
|
-
className:
|
|
2207
|
-
style:
|
|
2208
|
-
role:
|
|
2209
|
-
|
|
2227
|
+
this.passkeyErrorElement = this.createElement("div", {
|
|
2228
|
+
className: "onboarding-error",
|
|
2229
|
+
style: "display: none; margin-top: 12px;",
|
|
2230
|
+
role: "alert",
|
|
2231
|
+
"aria-live": "polite",
|
|
2210
2232
|
});
|
|
2211
2233
|
card.appendChild(this.passkeyErrorElement);
|
|
2212
2234
|
}
|
|
2213
2235
|
else {
|
|
2214
2236
|
// Create passkey elements but hide them
|
|
2215
|
-
this.passkeyLoginButton = this.createElement(
|
|
2216
|
-
type:
|
|
2217
|
-
className:
|
|
2218
|
-
style:
|
|
2237
|
+
this.passkeyLoginButton = this.createElement("button", {
|
|
2238
|
+
type: "button",
|
|
2239
|
+
className: "onboarding-button onboarding-button-passkey",
|
|
2240
|
+
style: "display: none;",
|
|
2219
2241
|
});
|
|
2220
2242
|
card.appendChild(this.passkeyLoginButton);
|
|
2221
|
-
this.passkeySignupLink = this.createElement(
|
|
2222
|
-
className:
|
|
2223
|
-
href:
|
|
2224
|
-
style:
|
|
2243
|
+
this.passkeySignupLink = this.createElement("a", {
|
|
2244
|
+
className: "onboarding-passkey-signup-link",
|
|
2245
|
+
href: "#",
|
|
2246
|
+
style: "display: none;",
|
|
2225
2247
|
});
|
|
2226
2248
|
card.appendChild(this.passkeySignupLink);
|
|
2227
|
-
this.passkeyErrorElement = this.createElement(
|
|
2228
|
-
className:
|
|
2229
|
-
style:
|
|
2249
|
+
this.passkeyErrorElement = this.createElement("div", {
|
|
2250
|
+
className: "onboarding-error",
|
|
2251
|
+
style: "display: none;",
|
|
2230
2252
|
});
|
|
2231
2253
|
card.appendChild(this.passkeyErrorElement);
|
|
2232
2254
|
}
|
|
2233
2255
|
// External wallet divider (shown immediately if external wallets are enabled)
|
|
2234
|
-
this.externalWalletDivider = this.createElement(
|
|
2235
|
-
className:
|
|
2236
|
-
style: this.externalWalletsEnabled ?
|
|
2256
|
+
this.externalWalletDivider = this.createElement("div", {
|
|
2257
|
+
className: "onboarding-divider",
|
|
2258
|
+
style: this.externalWalletsEnabled ? "" : "display: none;",
|
|
2237
2259
|
});
|
|
2238
|
-
const externalWalletDividerText = this.createElement(
|
|
2239
|
-
className:
|
|
2240
|
-
textContent:
|
|
2260
|
+
const externalWalletDividerText = this.createElement("span", {
|
|
2261
|
+
className: "onboarding-divider-text",
|
|
2262
|
+
textContent: "or",
|
|
2241
2263
|
});
|
|
2242
2264
|
this.externalWalletDivider.appendChild(externalWalletDividerText);
|
|
2243
2265
|
card.appendChild(this.externalWalletDivider);
|
|
2244
2266
|
// External wallet container (shown immediately if external wallets are enabled)
|
|
2245
|
-
this.externalWalletContainer = this.createElement(
|
|
2246
|
-
id:
|
|
2247
|
-
style: this.externalWalletsEnabled ?
|
|
2267
|
+
this.externalWalletContainer = this.createElement("div", {
|
|
2268
|
+
id: "onboarding-external-wallet-container",
|
|
2269
|
+
style: this.externalWalletsEnabled ? "" : "display: none;",
|
|
2248
2270
|
});
|
|
2249
2271
|
card.appendChild(this.externalWalletContainer);
|
|
2250
2272
|
// Footer (inside card, so it appears on initial login screen)
|
|
2251
2273
|
if (this.config.showFooter) {
|
|
2252
2274
|
const textColor = this.config.colors?.text ||
|
|
2253
|
-
(this.config.theme ===
|
|
2275
|
+
(this.config.theme === "dark" ? "#9ca3af" : "#6b7280");
|
|
2254
2276
|
const brandColor = this.config.colors?.text ||
|
|
2255
|
-
(this.config.theme ===
|
|
2256
|
-
this.footer = this.createElement(
|
|
2257
|
-
|
|
2258
|
-
|
|
2277
|
+
(this.config.theme === "dark" ? "#e5e7eb" : "#374151");
|
|
2278
|
+
this.footer = this.createElement("div", {
|
|
2279
|
+
className: "onboarding-footer",
|
|
2280
|
+
});
|
|
2281
|
+
const footerText = this.createElement("p", {
|
|
2282
|
+
className: "onboarding-footer-text",
|
|
2259
2283
|
style: `color: ${textColor}; display: flex; align-items: center; gap: 6px; justify-content: center;`,
|
|
2260
2284
|
});
|
|
2261
2285
|
// "Powered by" text
|
|
2262
|
-
const poweredBySpan = this.createElement(
|
|
2286
|
+
const poweredBySpan = this.createElement("span", {
|
|
2287
|
+
textContent: "Powered by",
|
|
2288
|
+
style: `color: ${textColor};`,
|
|
2289
|
+
});
|
|
2263
2290
|
footerText.appendChild(poweredBySpan);
|
|
2264
2291
|
// Inline brand with logo (clickable link)
|
|
2265
|
-
const brandContainer = this.createElement(
|
|
2266
|
-
href:
|
|
2267
|
-
target:
|
|
2268
|
-
rel:
|
|
2269
|
-
style:
|
|
2270
|
-
|
|
2292
|
+
const brandContainer = this.createElement("a", {
|
|
2293
|
+
href: "https://www.abstraxn.com/",
|
|
2294
|
+
target: "_blank",
|
|
2295
|
+
rel: "noopener noreferrer",
|
|
2296
|
+
style: "display: inline-flex; align-items: center; gap: 6px; text-decoration: none; cursor: pointer;",
|
|
2297
|
+
"aria-label": "Visit Abstraxn website",
|
|
2271
2298
|
});
|
|
2272
2299
|
// Abstraxn logo SVG
|
|
2273
|
-
const logoSvg = this.createElement(
|
|
2300
|
+
const logoSvg = this.createElement("span", {
|
|
2274
2301
|
innerHTML: `
|
|
2275
2302
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none" style="width: 20px; height: 20px; display: inline-block; vertical-align: middle;">
|
|
2276
2303
|
<path d="M47.9082 37.191L23.9541 23.553L0 9.91504L37.7436 -8.13502e-06L47.9082 37.191Z" fill="url(#paint0_linear_1242_781)"/>
|
|
@@ -2289,11 +2316,11 @@ export class OnboardingUIWeb {
|
|
|
2289
2316
|
</defs>
|
|
2290
2317
|
</svg>
|
|
2291
2318
|
`,
|
|
2292
|
-
style:
|
|
2319
|
+
style: "display: inline-flex; align-items: center;",
|
|
2293
2320
|
});
|
|
2294
2321
|
brandContainer.appendChild(logoSvg);
|
|
2295
|
-
const brandText = this.createElement(
|
|
2296
|
-
textContent:
|
|
2322
|
+
const brandText = this.createElement("span", {
|
|
2323
|
+
textContent: "abstraxn",
|
|
2297
2324
|
style: `color: ${brandColor}; font-weight: 700; letter-spacing: 0.2px;`,
|
|
2298
2325
|
});
|
|
2299
2326
|
brandContainer.appendChild(brandText);
|
|
@@ -2307,54 +2334,57 @@ export class OnboardingUIWeb {
|
|
|
2307
2334
|
* Attach event listeners
|
|
2308
2335
|
*/
|
|
2309
2336
|
attachEventListeners() {
|
|
2310
|
-
if (!this.emailForm ||
|
|
2337
|
+
if (!this.emailForm ||
|
|
2338
|
+
!this.emailInput ||
|
|
2339
|
+
!this.otpInput ||
|
|
2340
|
+
!this.continueButton) {
|
|
2311
2341
|
return;
|
|
2312
2342
|
}
|
|
2313
2343
|
// Email input change
|
|
2314
|
-
this.emailInput.addEventListener(
|
|
2344
|
+
this.emailInput.addEventListener("input", (e) => {
|
|
2315
2345
|
this.email = e.target.value;
|
|
2316
2346
|
this.updateButtonState();
|
|
2317
2347
|
});
|
|
2318
2348
|
// OTP input change
|
|
2319
|
-
this.otpInput.addEventListener(
|
|
2349
|
+
this.otpInput.addEventListener("input", (e) => {
|
|
2320
2350
|
this.otp = e.target.value;
|
|
2321
2351
|
});
|
|
2322
2352
|
// Form submit
|
|
2323
|
-
this.emailForm.addEventListener(
|
|
2353
|
+
this.emailForm.addEventListener("submit", (e) => {
|
|
2324
2354
|
e.preventDefault();
|
|
2325
2355
|
this.handleEmailSubmit();
|
|
2326
2356
|
});
|
|
2327
2357
|
// Google button click
|
|
2328
2358
|
if (this.googleButton) {
|
|
2329
|
-
this.googleButton.addEventListener(
|
|
2359
|
+
this.googleButton.addEventListener("click", (e) => {
|
|
2330
2360
|
e.preventDefault();
|
|
2331
2361
|
this.handleGoogleLogin();
|
|
2332
2362
|
});
|
|
2333
2363
|
}
|
|
2334
2364
|
// Twitter button click
|
|
2335
2365
|
if (this.twitterButton) {
|
|
2336
|
-
this.twitterButton.addEventListener(
|
|
2366
|
+
this.twitterButton.addEventListener("click", (e) => {
|
|
2337
2367
|
e.preventDefault();
|
|
2338
2368
|
this.handleTwitterLogin();
|
|
2339
2369
|
});
|
|
2340
2370
|
}
|
|
2341
2371
|
// Discord button click
|
|
2342
2372
|
if (this.discordButton) {
|
|
2343
|
-
this.discordButton.addEventListener(
|
|
2373
|
+
this.discordButton.addEventListener("click", (e) => {
|
|
2344
2374
|
e.preventDefault();
|
|
2345
2375
|
this.handleDiscordLogin();
|
|
2346
2376
|
});
|
|
2347
2377
|
}
|
|
2348
2378
|
// Passkey login button click
|
|
2349
2379
|
if (this.passkeyLoginButton) {
|
|
2350
|
-
this.passkeyLoginButton.addEventListener(
|
|
2380
|
+
this.passkeyLoginButton.addEventListener("click", (e) => {
|
|
2351
2381
|
e.preventDefault();
|
|
2352
2382
|
this.handlePasskeyLogin();
|
|
2353
2383
|
});
|
|
2354
2384
|
}
|
|
2355
2385
|
// Passkey signup link click
|
|
2356
2386
|
if (this.passkeySignupLink) {
|
|
2357
|
-
this.passkeySignupLink.addEventListener(
|
|
2387
|
+
this.passkeySignupLink.addEventListener("click", (e) => {
|
|
2358
2388
|
e.preventDefault();
|
|
2359
2389
|
this.handlePasskeySignup();
|
|
2360
2390
|
});
|
|
@@ -2368,12 +2398,12 @@ export class OnboardingUIWeb {
|
|
|
2368
2398
|
return;
|
|
2369
2399
|
// Ensure email is captured from input field
|
|
2370
2400
|
this.email = this.emailInput.value.trim();
|
|
2371
|
-
if (!this.email || !this.email.includes(
|
|
2372
|
-
this.setError(
|
|
2401
|
+
if (!this.email || !this.email.includes("@")) {
|
|
2402
|
+
this.setError("Please enter a valid email address");
|
|
2373
2403
|
return;
|
|
2374
2404
|
}
|
|
2375
2405
|
this.setError(null);
|
|
2376
|
-
this.setLoading(true,
|
|
2406
|
+
this.setLoading(true, "email");
|
|
2377
2407
|
try {
|
|
2378
2408
|
if (!this.otpSent) {
|
|
2379
2409
|
// Initiate OTP
|
|
@@ -2382,20 +2412,20 @@ export class OnboardingUIWeb {
|
|
|
2382
2412
|
}
|
|
2383
2413
|
else if (this.config.emailOtpEndpoint) {
|
|
2384
2414
|
const response = await fetch(this.config.emailOtpEndpoint, {
|
|
2385
|
-
method:
|
|
2415
|
+
method: "POST",
|
|
2386
2416
|
headers: {
|
|
2387
|
-
|
|
2417
|
+
"Content-Type": "application/json",
|
|
2388
2418
|
},
|
|
2389
2419
|
body: JSON.stringify({ email: this.email }),
|
|
2390
2420
|
});
|
|
2391
2421
|
if (!response.ok) {
|
|
2392
|
-
throw new Error(
|
|
2422
|
+
throw new Error("Failed to send OTP");
|
|
2393
2423
|
}
|
|
2394
2424
|
}
|
|
2395
2425
|
this.otpSent = true;
|
|
2396
2426
|
this.showOtpInput();
|
|
2397
2427
|
if (this.continueButton) {
|
|
2398
|
-
this.continueButton.textContent =
|
|
2428
|
+
this.continueButton.textContent = "Verify OTP";
|
|
2399
2429
|
}
|
|
2400
2430
|
}
|
|
2401
2431
|
else {
|
|
@@ -2406,14 +2436,14 @@ export class OnboardingUIWeb {
|
|
|
2406
2436
|
this.config.onLoginSuccess?.({ token: result.token });
|
|
2407
2437
|
}
|
|
2408
2438
|
else {
|
|
2409
|
-
throw new Error(
|
|
2439
|
+
throw new Error("Invalid OTP");
|
|
2410
2440
|
}
|
|
2411
2441
|
}
|
|
2412
2442
|
else if (this.config.emailOtpEndpoint) {
|
|
2413
2443
|
const response = await fetch(`${this.config.emailOtpEndpoint}/verify`, {
|
|
2414
|
-
method:
|
|
2444
|
+
method: "POST",
|
|
2415
2445
|
headers: {
|
|
2416
|
-
|
|
2446
|
+
"Content-Type": "application/json",
|
|
2417
2447
|
},
|
|
2418
2448
|
body: JSON.stringify({ email: this.email, otp: this.otp }),
|
|
2419
2449
|
});
|
|
@@ -2422,13 +2452,13 @@ export class OnboardingUIWeb {
|
|
|
2422
2452
|
this.config.onLoginSuccess?.({ token: data.token });
|
|
2423
2453
|
}
|
|
2424
2454
|
else {
|
|
2425
|
-
throw new Error(data.message ||
|
|
2455
|
+
throw new Error(data.message || "Invalid OTP");
|
|
2426
2456
|
}
|
|
2427
2457
|
}
|
|
2428
2458
|
}
|
|
2429
2459
|
}
|
|
2430
2460
|
catch (err) {
|
|
2431
|
-
const errorMessage = err instanceof Error ? err.message :
|
|
2461
|
+
const errorMessage = err instanceof Error ? err.message : "An error occurred";
|
|
2432
2462
|
this.setError(errorMessage);
|
|
2433
2463
|
this.config.onLoginError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
2434
2464
|
}
|
|
@@ -2441,14 +2471,14 @@ export class OnboardingUIWeb {
|
|
|
2441
2471
|
*/
|
|
2442
2472
|
async handleGoogleLogin() {
|
|
2443
2473
|
// console.log('🔵 Google login button clicked');
|
|
2444
|
-
// console.log('🔵 Config:', {
|
|
2445
|
-
// hasOnGoogleLogin: !!this.config.onGoogleLogin,
|
|
2446
|
-
// googleAuthEndpoint: this.config.googleAuthEndpoint
|
|
2474
|
+
// console.log('🔵 Config:', {
|
|
2475
|
+
// hasOnGoogleLogin: !!this.config.onGoogleLogin,
|
|
2476
|
+
// googleAuthEndpoint: this.config.googleAuthEndpoint
|
|
2447
2477
|
// });
|
|
2448
2478
|
this.setError(null);
|
|
2449
|
-
this.setLoading(true,
|
|
2479
|
+
this.setLoading(true, "google");
|
|
2450
2480
|
try {
|
|
2451
|
-
localStorage.setItem(
|
|
2481
|
+
localStorage.setItem("abstraxn_login_source", this.config.modal ? "modal" : "inline");
|
|
2452
2482
|
if (this.config.onGoogleLogin) {
|
|
2453
2483
|
// console.log('🔄 Calling onGoogleLogin callback');
|
|
2454
2484
|
await this.config.onGoogleLogin();
|
|
@@ -2458,11 +2488,11 @@ export class OnboardingUIWeb {
|
|
|
2458
2488
|
window.location.href = this.config.googleAuthEndpoint;
|
|
2459
2489
|
}
|
|
2460
2490
|
else {
|
|
2461
|
-
throw new Error(
|
|
2491
|
+
throw new Error("Google login endpoint not configured");
|
|
2462
2492
|
}
|
|
2463
2493
|
}
|
|
2464
2494
|
catch (err) {
|
|
2465
|
-
const errorMessage = err instanceof Error ? err.message :
|
|
2495
|
+
const errorMessage = err instanceof Error ? err.message : "An error occurred";
|
|
2466
2496
|
this.setError(errorMessage);
|
|
2467
2497
|
this.config.onLoginError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
2468
2498
|
}
|
|
@@ -2475,7 +2505,7 @@ export class OnboardingUIWeb {
|
|
|
2475
2505
|
*/
|
|
2476
2506
|
async handleTwitterLogin() {
|
|
2477
2507
|
this.setError(null);
|
|
2478
|
-
this.setLoading(true,
|
|
2508
|
+
this.setLoading(true, "twitter");
|
|
2479
2509
|
try {
|
|
2480
2510
|
if (this.config.onTwitterLogin) {
|
|
2481
2511
|
await this.config.onTwitterLogin();
|
|
@@ -2484,11 +2514,11 @@ export class OnboardingUIWeb {
|
|
|
2484
2514
|
window.location.href = this.config.twitterAuthEndpoint;
|
|
2485
2515
|
}
|
|
2486
2516
|
else {
|
|
2487
|
-
throw new Error(
|
|
2517
|
+
throw new Error("X (Twitter) login not configured");
|
|
2488
2518
|
}
|
|
2489
2519
|
}
|
|
2490
2520
|
catch (err) {
|
|
2491
|
-
const errorMessage = err instanceof Error ? err.message :
|
|
2521
|
+
const errorMessage = err instanceof Error ? err.message : "An error occurred";
|
|
2492
2522
|
this.setError(errorMessage);
|
|
2493
2523
|
this.config.onLoginError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
2494
2524
|
}
|
|
@@ -2501,7 +2531,7 @@ export class OnboardingUIWeb {
|
|
|
2501
2531
|
*/
|
|
2502
2532
|
async handleDiscordLogin() {
|
|
2503
2533
|
this.setError(null);
|
|
2504
|
-
this.setLoading(true,
|
|
2534
|
+
this.setLoading(true, "discord");
|
|
2505
2535
|
try {
|
|
2506
2536
|
if (this.config.onDiscordLogin) {
|
|
2507
2537
|
await this.config.onDiscordLogin();
|
|
@@ -2510,11 +2540,11 @@ export class OnboardingUIWeb {
|
|
|
2510
2540
|
window.location.href = this.config.discordAuthEndpoint;
|
|
2511
2541
|
}
|
|
2512
2542
|
else {
|
|
2513
|
-
throw new Error(
|
|
2543
|
+
throw new Error("Discord login not configured");
|
|
2514
2544
|
}
|
|
2515
2545
|
}
|
|
2516
2546
|
catch (err) {
|
|
2517
|
-
const errorMessage = err instanceof Error ? err.message :
|
|
2547
|
+
const errorMessage = err instanceof Error ? err.message : "An error occurred";
|
|
2518
2548
|
this.setError(errorMessage);
|
|
2519
2549
|
this.config.onLoginError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
2520
2550
|
}
|
|
@@ -2529,46 +2559,51 @@ export class OnboardingUIWeb {
|
|
|
2529
2559
|
*/
|
|
2530
2560
|
hideLoginElements() {
|
|
2531
2561
|
if (this.emailForm) {
|
|
2532
|
-
this.emailForm.style.display =
|
|
2562
|
+
this.emailForm.style.display = "none";
|
|
2563
|
+
}
|
|
2564
|
+
// Hide the header when showing OTP screen
|
|
2565
|
+
const header = this.rootElement?.querySelector(".onboarding-header");
|
|
2566
|
+
if (header) {
|
|
2567
|
+
header.style.display = "none";
|
|
2533
2568
|
}
|
|
2534
2569
|
if (this.divider) {
|
|
2535
|
-
this.divider.style.display =
|
|
2570
|
+
this.divider.style.display = "none";
|
|
2536
2571
|
}
|
|
2537
2572
|
if (this.googleButton) {
|
|
2538
|
-
this.googleButton.style.display =
|
|
2573
|
+
this.googleButton.style.display = "none";
|
|
2539
2574
|
}
|
|
2540
2575
|
if (this.twitterButton) {
|
|
2541
|
-
this.twitterButton.style.display =
|
|
2576
|
+
this.twitterButton.style.display = "none";
|
|
2542
2577
|
}
|
|
2543
2578
|
if (this.discordButton) {
|
|
2544
|
-
this.discordButton.style.display =
|
|
2579
|
+
this.discordButton.style.display = "none";
|
|
2545
2580
|
}
|
|
2546
2581
|
if (this.socialGrid) {
|
|
2547
|
-
this.socialGrid.style.display =
|
|
2582
|
+
this.socialGrid.style.display = "none";
|
|
2548
2583
|
}
|
|
2549
2584
|
if (this.passkeyDivider) {
|
|
2550
|
-
this.passkeyDivider.style.display =
|
|
2585
|
+
this.passkeyDivider.style.display = "none";
|
|
2551
2586
|
}
|
|
2552
2587
|
// Hide passkey buttons on OTP screen
|
|
2553
2588
|
if (this.passkeyLoginButton) {
|
|
2554
|
-
this.passkeyLoginButton.style.display =
|
|
2589
|
+
this.passkeyLoginButton.style.display = "none";
|
|
2555
2590
|
}
|
|
2556
2591
|
if (this.passkeySignupLink) {
|
|
2557
|
-
this.passkeySignupLink.style.display =
|
|
2592
|
+
this.passkeySignupLink.style.display = "none";
|
|
2558
2593
|
}
|
|
2559
2594
|
if (this.passkeyErrorElement) {
|
|
2560
|
-
this.passkeyErrorElement.style.display =
|
|
2595
|
+
this.passkeyErrorElement.style.display = "none";
|
|
2561
2596
|
}
|
|
2562
2597
|
// Hide external wallets on OTP screen
|
|
2563
2598
|
if (this.externalWalletContainer) {
|
|
2564
|
-
this.externalWalletContainer.style.display =
|
|
2599
|
+
this.externalWalletContainer.style.display = "none";
|
|
2565
2600
|
}
|
|
2566
2601
|
if (this.externalWalletDivider) {
|
|
2567
|
-
this.externalWalletDivider.style.display =
|
|
2602
|
+
this.externalWalletDivider.style.display = "none";
|
|
2568
2603
|
}
|
|
2569
2604
|
// Hide footer on login card (OTP screen has its own footer)
|
|
2570
2605
|
if (this.footer) {
|
|
2571
|
-
this.footer.style.display =
|
|
2606
|
+
this.footer.style.display = "none";
|
|
2572
2607
|
}
|
|
2573
2608
|
}
|
|
2574
2609
|
/**
|
|
@@ -2594,97 +2629,115 @@ export class OnboardingUIWeb {
|
|
|
2594
2629
|
this.verifyButton = null;
|
|
2595
2630
|
}
|
|
2596
2631
|
// Get the card element
|
|
2597
|
-
const card = this.rootElement.querySelector(
|
|
2632
|
+
const card = this.rootElement.querySelector(".onboarding-card");
|
|
2598
2633
|
if (!card)
|
|
2599
2634
|
return;
|
|
2600
2635
|
// Add class to card to indicate OTP screen is active (for CSS targeting)
|
|
2601
|
-
card.classList.add(
|
|
2636
|
+
card.classList.add("onboarding-otp-active");
|
|
2602
2637
|
// Create OTP verification container
|
|
2603
|
-
this.otpVerificationScreen = this.createElement(
|
|
2604
|
-
className:
|
|
2638
|
+
this.otpVerificationScreen = this.createElement("div", {
|
|
2639
|
+
className: "onboarding-otp-verification",
|
|
2640
|
+
});
|
|
2641
|
+
// Add Back Button
|
|
2642
|
+
const backButton = this.createElement("button", {
|
|
2643
|
+
type: "button",
|
|
2644
|
+
className: "onboarding-otp-back-button",
|
|
2645
|
+
"aria-label": "Go back to email input",
|
|
2605
2646
|
});
|
|
2647
|
+
backButton.innerHTML = `
|
|
2648
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2649
|
+
<path d="M19 12H5M12 19l-7-7 7-7" />
|
|
2650
|
+
</svg>
|
|
2651
|
+
`;
|
|
2652
|
+
backButton.addEventListener("click", () => {
|
|
2653
|
+
if (!this.loading) {
|
|
2654
|
+
this.resetToLoginForm();
|
|
2655
|
+
}
|
|
2656
|
+
});
|
|
2657
|
+
this.otpVerificationScreen.appendChild(backButton);
|
|
2606
2658
|
// Email icon container
|
|
2607
|
-
const iconContainer = this.createElement(
|
|
2608
|
-
className:
|
|
2659
|
+
const iconContainer = this.createElement("div", {
|
|
2660
|
+
className: "onboarding-otp-icon-container",
|
|
2609
2661
|
});
|
|
2610
|
-
const iconInner = this.createElement(
|
|
2611
|
-
className:
|
|
2662
|
+
const iconInner = this.createElement("div", {
|
|
2663
|
+
className: "onboarding-otp-icon-inner",
|
|
2612
2664
|
});
|
|
2613
2665
|
const emailIcon = this.createEmailIconSVG();
|
|
2614
2666
|
iconInner.appendChild(emailIcon);
|
|
2615
2667
|
iconContainer.appendChild(iconInner);
|
|
2616
2668
|
this.otpVerificationScreen.appendChild(iconContainer);
|
|
2617
2669
|
// Title
|
|
2618
|
-
const title = this.createElement(
|
|
2619
|
-
className:
|
|
2620
|
-
textContent:
|
|
2670
|
+
const title = this.createElement("h1", {
|
|
2671
|
+
className: "onboarding-otp-title",
|
|
2672
|
+
textContent: "Enter verification code",
|
|
2621
2673
|
});
|
|
2622
2674
|
this.otpVerificationScreen.appendChild(title);
|
|
2623
2675
|
// Instruction text
|
|
2624
|
-
const instruction = this.createElement(
|
|
2625
|
-
className:
|
|
2626
|
-
textContent:
|
|
2676
|
+
const instruction = this.createElement("p", {
|
|
2677
|
+
className: "onboarding-otp-instruction",
|
|
2678
|
+
textContent: "We sent a verification code to",
|
|
2627
2679
|
});
|
|
2628
2680
|
this.otpVerificationScreen.appendChild(instruction);
|
|
2629
2681
|
// Email address
|
|
2630
|
-
const emailDisplay = this.createElement(
|
|
2631
|
-
className:
|
|
2682
|
+
const emailDisplay = this.createElement("p", {
|
|
2683
|
+
className: "onboarding-otp-email",
|
|
2632
2684
|
textContent: this.email,
|
|
2633
2685
|
});
|
|
2634
2686
|
this.otpVerificationScreen.appendChild(emailDisplay);
|
|
2635
2687
|
// OTP inputs container
|
|
2636
|
-
const inputsContainer = this.createElement(
|
|
2637
|
-
className:
|
|
2688
|
+
const inputsContainer = this.createElement("div", {
|
|
2689
|
+
className: "onboarding-otp-inputs-container",
|
|
2638
2690
|
});
|
|
2639
2691
|
// Create 6 input fields
|
|
2640
2692
|
this.otpInputs = [];
|
|
2641
2693
|
for (let i = 0; i < 6; i++) {
|
|
2642
|
-
const input = this.createElement(
|
|
2643
|
-
type:
|
|
2644
|
-
className:
|
|
2694
|
+
const input = this.createElement("input", {
|
|
2695
|
+
type: "text",
|
|
2696
|
+
className: "onboarding-otp-input",
|
|
2645
2697
|
maxLength: 1,
|
|
2646
|
-
inputMode:
|
|
2647
|
-
pattern:
|
|
2698
|
+
inputMode: "numeric",
|
|
2699
|
+
pattern: "[0-9]*",
|
|
2648
2700
|
});
|
|
2649
2701
|
// Add event listeners for auto-advance
|
|
2650
|
-
input.addEventListener(
|
|
2651
|
-
input.addEventListener(
|
|
2652
|
-
input.addEventListener(
|
|
2702
|
+
input.addEventListener("input", (e) => this.handleOtpInput(e, i));
|
|
2703
|
+
input.addEventListener("keydown", (e) => this.handleOtpKeydown(e, i));
|
|
2704
|
+
input.addEventListener("paste", (e) => this.handleOtpPaste(e));
|
|
2653
2705
|
this.otpInputs.push(input);
|
|
2654
2706
|
inputsContainer.appendChild(input);
|
|
2655
2707
|
}
|
|
2656
2708
|
this.otpVerificationScreen.appendChild(inputsContainer);
|
|
2657
2709
|
// Error element (for OTP screen)
|
|
2658
|
-
const otpErrorElement = this.createElement(
|
|
2659
|
-
className:
|
|
2660
|
-
style:
|
|
2710
|
+
const otpErrorElement = this.createElement("div", {
|
|
2711
|
+
className: "onboarding-error",
|
|
2712
|
+
style: "display: none;",
|
|
2661
2713
|
});
|
|
2662
2714
|
this.otpVerificationScreen.appendChild(otpErrorElement);
|
|
2663
2715
|
// Store reference for OTP screen errors
|
|
2664
2716
|
this.otpVerificationScreen.errorElement = otpErrorElement;
|
|
2665
2717
|
// Verify button
|
|
2666
|
-
this.verifyButton = this.createElement(
|
|
2667
|
-
type:
|
|
2668
|
-
className:
|
|
2669
|
-
textContent:
|
|
2718
|
+
this.verifyButton = this.createElement("button", {
|
|
2719
|
+
type: "button",
|
|
2720
|
+
className: "onboarding-button onboarding-button-primary",
|
|
2721
|
+
textContent: "Verify",
|
|
2670
2722
|
});
|
|
2671
|
-
this.verifyButton.addEventListener(
|
|
2723
|
+
this.verifyButton.addEventListener("click", () => this.handleOtpVerify());
|
|
2672
2724
|
this.otpVerificationScreen.appendChild(this.verifyButton);
|
|
2673
2725
|
// Resend section
|
|
2674
|
-
const resendSection = this.createElement(
|
|
2675
|
-
className:
|
|
2726
|
+
const resendSection = this.createElement("div", {
|
|
2727
|
+
className: "onboarding-otp-resend",
|
|
2676
2728
|
});
|
|
2677
|
-
const resendText = this.createElement(
|
|
2678
|
-
className:
|
|
2729
|
+
const resendText = this.createElement("p", {
|
|
2730
|
+
className: "onboarding-otp-resend-text",
|
|
2679
2731
|
});
|
|
2680
|
-
resendText.innerHTML =
|
|
2732
|
+
resendText.innerHTML =
|
|
2733
|
+
'Didn\'t receive the email? <span class="onboarding-otp-resend-link" id="otp-resend-link">Resend</span>';
|
|
2681
2734
|
resendSection.appendChild(resendText);
|
|
2682
2735
|
this.otpVerificationScreen.appendChild(resendSection);
|
|
2683
2736
|
// Add resend click handler
|
|
2684
|
-
const resendLink = resendSection.querySelector(
|
|
2737
|
+
const resendLink = resendSection.querySelector("#otp-resend-link");
|
|
2685
2738
|
if (resendLink) {
|
|
2686
2739
|
this.resendButton = resendLink;
|
|
2687
|
-
resendLink.addEventListener(
|
|
2740
|
+
resendLink.addEventListener("click", (e) => {
|
|
2688
2741
|
e.preventDefault();
|
|
2689
2742
|
e.stopPropagation();
|
|
2690
2743
|
// Prevent click if cooldown is active
|
|
@@ -2697,27 +2750,32 @@ export class OnboardingUIWeb {
|
|
|
2697
2750
|
// Footer (add to OTP screen as well)
|
|
2698
2751
|
if (this.config.showFooter) {
|
|
2699
2752
|
const textColor = this.config.colors?.text ||
|
|
2700
|
-
(this.config.theme ===
|
|
2753
|
+
(this.config.theme === "dark" ? "#9ca3af" : "#6b7280");
|
|
2701
2754
|
const brandColor = this.config.colors?.text ||
|
|
2702
|
-
(this.config.theme ===
|
|
2703
|
-
const otpFooter = this.createElement(
|
|
2704
|
-
|
|
2705
|
-
|
|
2755
|
+
(this.config.theme === "dark" ? "#e5e7eb" : "#374151");
|
|
2756
|
+
const otpFooter = this.createElement("div", {
|
|
2757
|
+
className: "onboarding-footer",
|
|
2758
|
+
});
|
|
2759
|
+
const otpFooterText = this.createElement("p", {
|
|
2760
|
+
className: "onboarding-footer-text",
|
|
2706
2761
|
style: `color: ${textColor}; display: flex; align-items: center; gap: 6px; justify-content: center;`,
|
|
2707
2762
|
});
|
|
2708
2763
|
// "Powered by" text
|
|
2709
|
-
const poweredBySpan = this.createElement(
|
|
2764
|
+
const poweredBySpan = this.createElement("span", {
|
|
2765
|
+
textContent: "Powered by",
|
|
2766
|
+
style: `color: ${textColor};`,
|
|
2767
|
+
});
|
|
2710
2768
|
otpFooterText.appendChild(poweredBySpan);
|
|
2711
2769
|
// Inline brand with logo (clickable link)
|
|
2712
|
-
const brandContainer = this.createElement(
|
|
2713
|
-
href:
|
|
2714
|
-
target:
|
|
2715
|
-
rel:
|
|
2716
|
-
style:
|
|
2717
|
-
|
|
2770
|
+
const brandContainer = this.createElement("a", {
|
|
2771
|
+
href: "https://www.abstraxn.com/",
|
|
2772
|
+
target: "_blank",
|
|
2773
|
+
rel: "noopener noreferrer",
|
|
2774
|
+
style: "display: inline-flex; align-items: center; gap: 6px; text-decoration: none; cursor: pointer;",
|
|
2775
|
+
"aria-label": "Visit Abstraxn website",
|
|
2718
2776
|
});
|
|
2719
2777
|
// Abstraxn logo SVG
|
|
2720
|
-
const logoSvg = this.createElement(
|
|
2778
|
+
const logoSvg = this.createElement("span", {
|
|
2721
2779
|
innerHTML: `
|
|
2722
2780
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none" style="width: 20px; height: 20px; display: inline-block; vertical-align: middle;">
|
|
2723
2781
|
<path d="M47.9082 37.191L23.9541 23.553L0 9.91504L37.7436 -8.13502e-06L47.9082 37.191Z" fill="url(#paint0_linear_1242_781_otp)"/>
|
|
@@ -2736,11 +2794,11 @@ export class OnboardingUIWeb {
|
|
|
2736
2794
|
</defs>
|
|
2737
2795
|
</svg>
|
|
2738
2796
|
`,
|
|
2739
|
-
style:
|
|
2797
|
+
style: "display: inline-flex; align-items: center;",
|
|
2740
2798
|
});
|
|
2741
2799
|
brandContainer.appendChild(logoSvg);
|
|
2742
|
-
const brandText = this.createElement(
|
|
2743
|
-
textContent:
|
|
2800
|
+
const brandText = this.createElement("span", {
|
|
2801
|
+
textContent: "abstraxn",
|
|
2744
2802
|
style: `color: ${brandColor}; font-weight: 700; letter-spacing: 0.2px;`,
|
|
2745
2803
|
});
|
|
2746
2804
|
brandContainer.appendChild(brandText);
|
|
@@ -2755,7 +2813,8 @@ export class OnboardingUIWeb {
|
|
|
2755
2813
|
this.hideLoginElements();
|
|
2756
2814
|
// Also ensure they stay hidden after DOM updates
|
|
2757
2815
|
setTimeout(() => {
|
|
2758
|
-
if (this.otpVerificationScreen &&
|
|
2816
|
+
if (this.otpVerificationScreen &&
|
|
2817
|
+
this.otpVerificationScreen.parentElement) {
|
|
2759
2818
|
this.hideLoginElements();
|
|
2760
2819
|
}
|
|
2761
2820
|
}, 0);
|
|
@@ -2765,7 +2824,8 @@ export class OnboardingUIWeb {
|
|
|
2765
2824
|
this.otpInputs[0].focus();
|
|
2766
2825
|
}
|
|
2767
2826
|
// Final check to ensure social buttons are hidden
|
|
2768
|
-
if (this.otpVerificationScreen &&
|
|
2827
|
+
if (this.otpVerificationScreen &&
|
|
2828
|
+
this.otpVerificationScreen.parentElement) {
|
|
2769
2829
|
this.hideLoginElements();
|
|
2770
2830
|
}
|
|
2771
2831
|
}, 100);
|
|
@@ -2776,20 +2836,15 @@ export class OnboardingUIWeb {
|
|
|
2776
2836
|
* Create email icon SVG
|
|
2777
2837
|
*/
|
|
2778
2838
|
createEmailIconSVG() {
|
|
2779
|
-
const svg = document.createElementNS(
|
|
2780
|
-
svg.setAttribute(
|
|
2781
|
-
svg.setAttribute(
|
|
2782
|
-
svg.setAttribute(
|
|
2783
|
-
svg.setAttribute(
|
|
2784
|
-
svg.setAttribute(
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
2788
|
-
path.setAttribute('d', 'M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z');
|
|
2839
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
2840
|
+
svg.setAttribute("class", "onboarding-otp-icon");
|
|
2841
|
+
svg.setAttribute("viewBox", "0 0 17 17");
|
|
2842
|
+
svg.setAttribute("fill", "currentColor");
|
|
2843
|
+
svg.setAttribute("width", "28");
|
|
2844
|
+
svg.setAttribute("height", "28");
|
|
2845
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
2846
|
+
path.setAttribute("d", "M0 2v13h17v-13h-17zM8.494 9.817l-6.896-6.817h13.82l-6.924 6.817zM5.755 8.516l-4.755 4.682v-9.383l4.755 4.701zM6.466 9.219l2.026 2.003 1.996-1.966 4.8 4.744h-13.677l4.855-4.781zM11.201 8.555l4.799-4.725v9.467l-4.799-4.742z");
|
|
2789
2847
|
svg.appendChild(path);
|
|
2790
|
-
const polyline = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
|
|
2791
|
-
polyline.setAttribute('points', '22,6 12,13 2,6');
|
|
2792
|
-
svg.appendChild(polyline);
|
|
2793
2848
|
return svg;
|
|
2794
2849
|
}
|
|
2795
2850
|
/**
|
|
@@ -2797,7 +2852,7 @@ export class OnboardingUIWeb {
|
|
|
2797
2852
|
*/
|
|
2798
2853
|
handleOtpInput(e, index) {
|
|
2799
2854
|
const input = e.target;
|
|
2800
|
-
const value = input.value.replace(/[^0-9]/g,
|
|
2855
|
+
const value = input.value.replace(/[^0-9]/g, "");
|
|
2801
2856
|
if (value) {
|
|
2802
2857
|
input.value = value;
|
|
2803
2858
|
// Move to next input if available
|
|
@@ -2811,7 +2866,7 @@ export class OnboardingUIWeb {
|
|
|
2811
2866
|
}
|
|
2812
2867
|
}
|
|
2813
2868
|
else {
|
|
2814
|
-
input.value =
|
|
2869
|
+
input.value = "";
|
|
2815
2870
|
}
|
|
2816
2871
|
this.updateOtpValue();
|
|
2817
2872
|
// Auto-submit when 6 digits are entered (only if auto-submit is enabled)
|
|
@@ -2827,7 +2882,7 @@ export class OnboardingUIWeb {
|
|
|
2827
2882
|
*/
|
|
2828
2883
|
handleOtpKeydown(e, index) {
|
|
2829
2884
|
const input = e.target;
|
|
2830
|
-
if (e.key ===
|
|
2885
|
+
if (e.key === "Backspace" && !input.value && index > 0) {
|
|
2831
2886
|
this.otpInputs[index - 1].focus();
|
|
2832
2887
|
}
|
|
2833
2888
|
}
|
|
@@ -2836,11 +2891,11 @@ export class OnboardingUIWeb {
|
|
|
2836
2891
|
*/
|
|
2837
2892
|
handleOtpPaste(e) {
|
|
2838
2893
|
e.preventDefault();
|
|
2839
|
-
const pastedData = e.clipboardData?.getData(
|
|
2840
|
-
const digits = pastedData.replace(/[^0-9]/g,
|
|
2894
|
+
const pastedData = e.clipboardData?.getData("text") || "";
|
|
2895
|
+
const digits = pastedData.replace(/[^0-9]/g, "").slice(0, 6);
|
|
2841
2896
|
for (let i = 0; i < 6; i++) {
|
|
2842
2897
|
if (this.otpInputs[i]) {
|
|
2843
|
-
this.otpInputs[i].value = digits[i] ||
|
|
2898
|
+
this.otpInputs[i].value = digits[i] || "";
|
|
2844
2899
|
}
|
|
2845
2900
|
}
|
|
2846
2901
|
// Focus the last filled input or the last input
|
|
@@ -2861,7 +2916,7 @@ export class OnboardingUIWeb {
|
|
|
2861
2916
|
* Update OTP value from input fields
|
|
2862
2917
|
*/
|
|
2863
2918
|
updateOtpValue() {
|
|
2864
|
-
this.otp = this.otpInputs.map(input => input.value).join(
|
|
2919
|
+
this.otp = this.otpInputs.map((input) => input.value).join("");
|
|
2865
2920
|
}
|
|
2866
2921
|
/**
|
|
2867
2922
|
* Handle OTP verification
|
|
@@ -2869,14 +2924,14 @@ export class OnboardingUIWeb {
|
|
|
2869
2924
|
async handleOtpVerify() {
|
|
2870
2925
|
this.updateOtpValue();
|
|
2871
2926
|
if (this.otp.length !== 6) {
|
|
2872
|
-
this.setError(
|
|
2927
|
+
this.setError("Please enter the complete 6-digit code");
|
|
2873
2928
|
return;
|
|
2874
2929
|
}
|
|
2875
2930
|
// Disable inputs during verification
|
|
2876
|
-
this.otpInputs.forEach(input => {
|
|
2931
|
+
this.otpInputs.forEach((input) => {
|
|
2877
2932
|
input.disabled = true;
|
|
2878
2933
|
});
|
|
2879
|
-
this.setLoading(true,
|
|
2934
|
+
this.setLoading(true, "email");
|
|
2880
2935
|
this.setError(null);
|
|
2881
2936
|
try {
|
|
2882
2937
|
if (this.config.onEmailOtpVerify) {
|
|
@@ -2886,15 +2941,15 @@ export class OnboardingUIWeb {
|
|
|
2886
2941
|
}
|
|
2887
2942
|
else {
|
|
2888
2943
|
// Use the error message from the API response, fallback to generic message only if not provided
|
|
2889
|
-
const errorMessage = result.error ||
|
|
2944
|
+
const errorMessage = result.error || "Invalid verification code";
|
|
2890
2945
|
throw new Error(errorMessage);
|
|
2891
2946
|
}
|
|
2892
2947
|
}
|
|
2893
2948
|
else if (this.config.emailOtpEndpoint) {
|
|
2894
2949
|
const response = await fetch(`${this.config.emailOtpEndpoint}/verify`, {
|
|
2895
|
-
method:
|
|
2950
|
+
method: "POST",
|
|
2896
2951
|
headers: {
|
|
2897
|
-
|
|
2952
|
+
"Content-Type": "application/json",
|
|
2898
2953
|
},
|
|
2899
2954
|
body: JSON.stringify({ email: this.email, otp: this.otp }),
|
|
2900
2955
|
});
|
|
@@ -2904,13 +2959,13 @@ export class OnboardingUIWeb {
|
|
|
2904
2959
|
}
|
|
2905
2960
|
else {
|
|
2906
2961
|
// Use the error message from the API response, fallback to generic message only if not provided
|
|
2907
|
-
const errorMessage = data.message || data.error ||
|
|
2962
|
+
const errorMessage = data.message || data.error || "Invalid verification code";
|
|
2908
2963
|
throw new Error(errorMessage);
|
|
2909
2964
|
}
|
|
2910
2965
|
}
|
|
2911
2966
|
}
|
|
2912
2967
|
catch (err) {
|
|
2913
|
-
const errorMessage = err instanceof Error ? err.message :
|
|
2968
|
+
const errorMessage = err instanceof Error ? err.message : "An error occurred";
|
|
2914
2969
|
this.setError(errorMessage);
|
|
2915
2970
|
this.config.onLoginError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
2916
2971
|
// Disable auto-submit after failed attempt
|
|
@@ -2922,23 +2977,25 @@ export class OnboardingUIWeb {
|
|
|
2922
2977
|
this.hideLoginElements();
|
|
2923
2978
|
// Also use setTimeout to ensure they stay hidden after any potential re-renders
|
|
2924
2979
|
setTimeout(() => {
|
|
2925
|
-
if (this.otpVerificationScreen &&
|
|
2980
|
+
if (this.otpVerificationScreen &&
|
|
2981
|
+
this.otpVerificationScreen.parentElement) {
|
|
2926
2982
|
this.hideLoginElements();
|
|
2927
2983
|
}
|
|
2928
2984
|
}, 0);
|
|
2929
2985
|
// Additional check after a short delay to catch any late re-renders
|
|
2930
2986
|
setTimeout(() => {
|
|
2931
|
-
if (this.otpVerificationScreen &&
|
|
2987
|
+
if (this.otpVerificationScreen &&
|
|
2988
|
+
this.otpVerificationScreen.parentElement) {
|
|
2932
2989
|
this.hideLoginElements();
|
|
2933
2990
|
}
|
|
2934
2991
|
}, 100);
|
|
2935
2992
|
}
|
|
2936
2993
|
// Clear OTP inputs on error
|
|
2937
|
-
this.otpInputs.forEach(input => {
|
|
2938
|
-
input.value =
|
|
2994
|
+
this.otpInputs.forEach((input) => {
|
|
2995
|
+
input.value = "";
|
|
2939
2996
|
input.disabled = false;
|
|
2940
2997
|
});
|
|
2941
|
-
this.otp =
|
|
2998
|
+
this.otp = "";
|
|
2942
2999
|
if (this.otpInputs[0]) {
|
|
2943
3000
|
this.otpInputs[0].focus();
|
|
2944
3001
|
}
|
|
@@ -2957,29 +3014,29 @@ export class OnboardingUIWeb {
|
|
|
2957
3014
|
// Re-enable auto-submit when resending OTP
|
|
2958
3015
|
this.autoSubmitEnabled = true;
|
|
2959
3016
|
this.setError(null);
|
|
2960
|
-
this.setLoading(true,
|
|
3017
|
+
this.setLoading(true, "email");
|
|
2961
3018
|
try {
|
|
2962
3019
|
if (this.config.onEmailOtpInitiate) {
|
|
2963
3020
|
await this.config.onEmailOtpInitiate(this.email);
|
|
2964
3021
|
}
|
|
2965
3022
|
else if (this.config.emailOtpEndpoint) {
|
|
2966
3023
|
const response = await fetch(this.config.emailOtpEndpoint, {
|
|
2967
|
-
method:
|
|
3024
|
+
method: "POST",
|
|
2968
3025
|
headers: {
|
|
2969
|
-
|
|
3026
|
+
"Content-Type": "application/json",
|
|
2970
3027
|
},
|
|
2971
3028
|
body: JSON.stringify({ email: this.email }),
|
|
2972
3029
|
});
|
|
2973
3030
|
if (!response.ok) {
|
|
2974
|
-
throw new Error(
|
|
3031
|
+
throw new Error("Failed to resend OTP");
|
|
2975
3032
|
}
|
|
2976
3033
|
}
|
|
2977
3034
|
// Clear OTP inputs
|
|
2978
|
-
this.otpInputs.forEach(input => {
|
|
2979
|
-
input.value =
|
|
3035
|
+
this.otpInputs.forEach((input) => {
|
|
3036
|
+
input.value = "";
|
|
2980
3037
|
input.disabled = false;
|
|
2981
3038
|
});
|
|
2982
|
-
this.otp =
|
|
3039
|
+
this.otp = "";
|
|
2983
3040
|
if (this.otpInputs[0]) {
|
|
2984
3041
|
this.otpInputs[0].focus();
|
|
2985
3042
|
}
|
|
@@ -2987,7 +3044,7 @@ export class OnboardingUIWeb {
|
|
|
2987
3044
|
this.startResendCooldown();
|
|
2988
3045
|
}
|
|
2989
3046
|
catch (err) {
|
|
2990
|
-
const errorMessage = err instanceof Error ? err.message :
|
|
3047
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to resend OTP";
|
|
2991
3048
|
this.setError(errorMessage);
|
|
2992
3049
|
this.config.onLoginError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
2993
3050
|
}
|
|
@@ -3007,10 +3064,10 @@ export class OnboardingUIWeb {
|
|
|
3007
3064
|
// Update UI immediately
|
|
3008
3065
|
if (this.resendButton) {
|
|
3009
3066
|
this.resendButton.textContent = `Resend (${this.resendCooldown}s)`;
|
|
3010
|
-
this.resendButton.classList.add(
|
|
3011
|
-
this.resendButton.style.pointerEvents =
|
|
3012
|
-
this.resendButton.style.cursor =
|
|
3013
|
-
this.resendButton.style.opacity =
|
|
3067
|
+
this.resendButton.classList.add("onboarding-otp-resend-link-disabled");
|
|
3068
|
+
this.resendButton.style.pointerEvents = "none";
|
|
3069
|
+
this.resendButton.style.cursor = "not-allowed";
|
|
3070
|
+
this.resendButton.style.opacity = "0.6";
|
|
3014
3071
|
}
|
|
3015
3072
|
// Start countdown timer
|
|
3016
3073
|
this.resendCooldownTimer = setInterval(() => {
|
|
@@ -3027,11 +3084,11 @@ export class OnboardingUIWeb {
|
|
|
3027
3084
|
this.resendCooldownTimer = null;
|
|
3028
3085
|
}
|
|
3029
3086
|
if (this.resendButton) {
|
|
3030
|
-
this.resendButton.textContent =
|
|
3031
|
-
this.resendButton.classList.remove(
|
|
3032
|
-
this.resendButton.style.pointerEvents =
|
|
3033
|
-
this.resendButton.style.cursor =
|
|
3034
|
-
this.resendButton.style.opacity =
|
|
3087
|
+
this.resendButton.textContent = "Resend";
|
|
3088
|
+
this.resendButton.classList.remove("onboarding-otp-resend-link-disabled");
|
|
3089
|
+
this.resendButton.style.pointerEvents = "auto";
|
|
3090
|
+
this.resendButton.style.cursor = "pointer";
|
|
3091
|
+
this.resendButton.style.opacity = "1";
|
|
3035
3092
|
}
|
|
3036
3093
|
}
|
|
3037
3094
|
}, 1000);
|
|
@@ -3040,32 +3097,42 @@ export class OnboardingUIWeb {
|
|
|
3040
3097
|
* Set error message
|
|
3041
3098
|
*/
|
|
3042
3099
|
setError(message) {
|
|
3100
|
+
const formatMessage = (msg) => {
|
|
3101
|
+
if (msg.startsWith("{") && msg.endsWith("}")) {
|
|
3102
|
+
return msg;
|
|
3103
|
+
}
|
|
3104
|
+
return `{ ${msg} }`;
|
|
3105
|
+
};
|
|
3043
3106
|
// Show error in OTP screen if it exists
|
|
3044
3107
|
if (this.otpVerificationScreen) {
|
|
3045
|
-
const otpErrorElement = this.otpVerificationScreen
|
|
3108
|
+
const otpErrorElement = this.otpVerificationScreen
|
|
3109
|
+
.errorElement;
|
|
3046
3110
|
if (otpErrorElement) {
|
|
3047
3111
|
if (message) {
|
|
3048
|
-
otpErrorElement.textContent = message;
|
|
3049
|
-
otpErrorElement.style.display =
|
|
3112
|
+
otpErrorElement.textContent = formatMessage(message);
|
|
3113
|
+
otpErrorElement.style.display = "block";
|
|
3050
3114
|
}
|
|
3051
3115
|
else {
|
|
3052
|
-
otpErrorElement.style.display =
|
|
3116
|
+
otpErrorElement.style.display = "none";
|
|
3053
3117
|
}
|
|
3054
3118
|
// Ensure social buttons remain hidden when showing error on OTP screen
|
|
3055
3119
|
// Call immediately and also with delays to catch any re-renders
|
|
3056
3120
|
this.hideLoginElements();
|
|
3057
3121
|
setTimeout(() => {
|
|
3058
|
-
if (this.otpVerificationScreen &&
|
|
3122
|
+
if (this.otpVerificationScreen &&
|
|
3123
|
+
this.otpVerificationScreen.parentElement) {
|
|
3059
3124
|
this.hideLoginElements();
|
|
3060
3125
|
}
|
|
3061
3126
|
}, 0);
|
|
3062
3127
|
setTimeout(() => {
|
|
3063
|
-
if (this.otpVerificationScreen &&
|
|
3128
|
+
if (this.otpVerificationScreen &&
|
|
3129
|
+
this.otpVerificationScreen.parentElement) {
|
|
3064
3130
|
this.hideLoginElements();
|
|
3065
3131
|
}
|
|
3066
3132
|
}, 50);
|
|
3067
3133
|
setTimeout(() => {
|
|
3068
|
-
if (this.otpVerificationScreen &&
|
|
3134
|
+
if (this.otpVerificationScreen &&
|
|
3135
|
+
this.otpVerificationScreen.parentElement) {
|
|
3069
3136
|
this.hideLoginElements();
|
|
3070
3137
|
}
|
|
3071
3138
|
}, 150);
|
|
@@ -3076,11 +3143,11 @@ export class OnboardingUIWeb {
|
|
|
3076
3143
|
if (!this.errorElement)
|
|
3077
3144
|
return;
|
|
3078
3145
|
if (message) {
|
|
3079
|
-
this.errorElement.textContent = message;
|
|
3080
|
-
this.errorElement.style.display =
|
|
3146
|
+
this.errorElement.textContent = formatMessage(message);
|
|
3147
|
+
this.errorElement.style.display = "block";
|
|
3081
3148
|
}
|
|
3082
3149
|
else {
|
|
3083
|
-
this.errorElement.style.display =
|
|
3150
|
+
this.errorElement.style.display = "none";
|
|
3084
3151
|
}
|
|
3085
3152
|
}
|
|
3086
3153
|
/**
|
|
@@ -3099,11 +3166,15 @@ export class OnboardingUIWeb {
|
|
|
3099
3166
|
if (this.continueButton) {
|
|
3100
3167
|
this.continueButton.disabled = loading || !this.email;
|
|
3101
3168
|
// Show loading text only if this is the active button
|
|
3102
|
-
if (loading && this.activeButton ===
|
|
3103
|
-
this.continueButton.textContent = this.otpSent
|
|
3169
|
+
if (loading && this.activeButton === "email") {
|
|
3170
|
+
this.continueButton.textContent = this.otpSent
|
|
3171
|
+
? "Verifying..."
|
|
3172
|
+
: "Loading...";
|
|
3104
3173
|
}
|
|
3105
3174
|
else if (!loading) {
|
|
3106
|
-
this.continueButton.textContent = this.otpSent
|
|
3175
|
+
this.continueButton.textContent = this.otpSent
|
|
3176
|
+
? "Verify OTP"
|
|
3177
|
+
: "Continue";
|
|
3107
3178
|
}
|
|
3108
3179
|
}
|
|
3109
3180
|
// Email arrow button (when all auth methods are enabled)
|
|
@@ -3127,23 +3198,23 @@ export class OnboardingUIWeb {
|
|
|
3127
3198
|
if (this.passkeyLoginButton) {
|
|
3128
3199
|
this.passkeyLoginButton.disabled = loading;
|
|
3129
3200
|
// Show loading text only if this is the active button
|
|
3130
|
-
if (loading && this.activeButton ===
|
|
3201
|
+
if (loading && this.activeButton === "passkey") {
|
|
3131
3202
|
// Update only the text node, preserve the icon
|
|
3132
|
-
const textNodes = Array.from(this.passkeyLoginButton.childNodes).filter(node => node.nodeType === Node.TEXT_NODE);
|
|
3203
|
+
const textNodes = Array.from(this.passkeyLoginButton.childNodes).filter((node) => node.nodeType === Node.TEXT_NODE);
|
|
3133
3204
|
if (textNodes.length > 0) {
|
|
3134
|
-
textNodes[0].textContent =
|
|
3205
|
+
textNodes[0].textContent = " Authenticating...";
|
|
3135
3206
|
}
|
|
3136
3207
|
else {
|
|
3137
3208
|
// If no text node exists, append one (icon should already be there)
|
|
3138
|
-
this.passkeyLoginButton.appendChild(document.createTextNode(
|
|
3209
|
+
this.passkeyLoginButton.appendChild(document.createTextNode(" Authenticating..."));
|
|
3139
3210
|
}
|
|
3140
|
-
this.passkeyLoginButton.style.opacity =
|
|
3141
|
-
this.passkeyLoginButton.style.cursor =
|
|
3211
|
+
this.passkeyLoginButton.style.opacity = "0.7";
|
|
3212
|
+
this.passkeyLoginButton.style.cursor = "not-allowed";
|
|
3142
3213
|
}
|
|
3143
3214
|
else if (!loading) {
|
|
3144
3215
|
// Update only the text node, preserve the icon
|
|
3145
|
-
const textNodes = Array.from(this.passkeyLoginButton.childNodes).filter(node => node.nodeType === Node.TEXT_NODE);
|
|
3146
|
-
const passkeyText = ` ${this.config.labels?.passkeyLoginButton ||
|
|
3216
|
+
const textNodes = Array.from(this.passkeyLoginButton.childNodes).filter((node) => node.nodeType === Node.TEXT_NODE);
|
|
3217
|
+
const passkeyText = ` ${this.config.labels?.passkeyLoginButton || "Log in with passkey"}`;
|
|
3147
3218
|
if (textNodes.length > 0) {
|
|
3148
3219
|
textNodes[0].textContent = passkeyText;
|
|
3149
3220
|
}
|
|
@@ -3151,21 +3222,21 @@ export class OnboardingUIWeb {
|
|
|
3151
3222
|
// If no text node exists, append one (icon should already be there)
|
|
3152
3223
|
this.passkeyLoginButton.appendChild(document.createTextNode(passkeyText));
|
|
3153
3224
|
}
|
|
3154
|
-
this.passkeyLoginButton.style.opacity =
|
|
3155
|
-
this.passkeyLoginButton.style.cursor =
|
|
3225
|
+
this.passkeyLoginButton.style.opacity = "1";
|
|
3226
|
+
this.passkeyLoginButton.style.cursor = "pointer";
|
|
3156
3227
|
}
|
|
3157
3228
|
}
|
|
3158
3229
|
// Passkey signup link
|
|
3159
3230
|
if (this.passkeySignupLink) {
|
|
3160
3231
|
if (loading) {
|
|
3161
|
-
this.passkeySignupLink.style.opacity =
|
|
3162
|
-
this.passkeySignupLink.style.pointerEvents =
|
|
3163
|
-
this.passkeySignupLink.style.cursor =
|
|
3232
|
+
this.passkeySignupLink.style.opacity = "0.5";
|
|
3233
|
+
this.passkeySignupLink.style.pointerEvents = "none";
|
|
3234
|
+
this.passkeySignupLink.style.cursor = "not-allowed";
|
|
3164
3235
|
}
|
|
3165
3236
|
else {
|
|
3166
|
-
this.passkeySignupLink.style.opacity =
|
|
3167
|
-
this.passkeySignupLink.style.pointerEvents =
|
|
3168
|
-
this.passkeySignupLink.style.cursor =
|
|
3237
|
+
this.passkeySignupLink.style.opacity = "1";
|
|
3238
|
+
this.passkeySignupLink.style.pointerEvents = "auto";
|
|
3239
|
+
this.passkeySignupLink.style.cursor = "pointer";
|
|
3169
3240
|
}
|
|
3170
3241
|
}
|
|
3171
3242
|
// Email input
|
|
@@ -3180,14 +3251,14 @@ export class OnboardingUIWeb {
|
|
|
3180
3251
|
if (this.verifyButton) {
|
|
3181
3252
|
this.verifyButton.disabled = loading;
|
|
3182
3253
|
if (loading) {
|
|
3183
|
-
this.verifyButton.textContent =
|
|
3184
|
-
this.verifyButton.style.opacity =
|
|
3185
|
-
this.verifyButton.style.cursor =
|
|
3254
|
+
this.verifyButton.textContent = "Verifying...";
|
|
3255
|
+
this.verifyButton.style.opacity = "0.7";
|
|
3256
|
+
this.verifyButton.style.cursor = "not-allowed";
|
|
3186
3257
|
}
|
|
3187
3258
|
else {
|
|
3188
|
-
this.verifyButton.textContent =
|
|
3189
|
-
this.verifyButton.style.opacity =
|
|
3190
|
-
this.verifyButton.style.cursor =
|
|
3259
|
+
this.verifyButton.textContent = "Verify";
|
|
3260
|
+
this.verifyButton.style.opacity = "1";
|
|
3261
|
+
this.verifyButton.style.cursor = "pointer";
|
|
3191
3262
|
}
|
|
3192
3263
|
}
|
|
3193
3264
|
}
|
|
@@ -3195,12 +3266,13 @@ export class OnboardingUIWeb {
|
|
|
3195
3266
|
* Update button state
|
|
3196
3267
|
*/
|
|
3197
3268
|
updateButtonState() {
|
|
3269
|
+
const isValid = isValidEmail(this.email.trim());
|
|
3198
3270
|
if (this.continueButton) {
|
|
3199
|
-
this.continueButton.disabled = this.loading || !
|
|
3271
|
+
this.continueButton.disabled = this.loading || !isValid;
|
|
3200
3272
|
}
|
|
3201
3273
|
// Update arrow button state (when all auth methods are enabled)
|
|
3202
3274
|
if (this.emailArrowButton) {
|
|
3203
|
-
this.emailArrowButton.disabled = this.loading || !
|
|
3275
|
+
this.emailArrowButton.disabled = this.loading || !isValid;
|
|
3204
3276
|
}
|
|
3205
3277
|
}
|
|
3206
3278
|
/**
|
|
@@ -3217,7 +3289,7 @@ export class OnboardingUIWeb {
|
|
|
3217
3289
|
*/
|
|
3218
3290
|
setVisible(visible) {
|
|
3219
3291
|
if (this.rootElement) {
|
|
3220
|
-
this.rootElement.style.display = visible ?
|
|
3292
|
+
this.rootElement.style.display = visible ? "" : "none";
|
|
3221
3293
|
}
|
|
3222
3294
|
}
|
|
3223
3295
|
/**
|
|
@@ -3236,26 +3308,26 @@ export class OnboardingUIWeb {
|
|
|
3236
3308
|
this.otpVerificationScreen = null;
|
|
3237
3309
|
}
|
|
3238
3310
|
// Remove loading/error mode classes and OTP active class
|
|
3239
|
-
const card = this.rootElement?.querySelector(
|
|
3311
|
+
const card = this.rootElement?.querySelector(".onboarding-card");
|
|
3240
3312
|
if (card) {
|
|
3241
|
-
card.classList.remove(
|
|
3242
|
-
card.classList.remove(
|
|
3243
|
-
card.classList.remove(
|
|
3313
|
+
card.classList.remove("onboarding-mode-loading");
|
|
3314
|
+
card.classList.remove("onboarding-mode-error");
|
|
3315
|
+
card.classList.remove("onboarding-otp-active");
|
|
3244
3316
|
}
|
|
3245
3317
|
// Hide loading modal if exists (for inline components)
|
|
3246
3318
|
this.hideLoadingModal();
|
|
3247
3319
|
// Remove error container if exists
|
|
3248
|
-
const errorContainer = this.rootElement?.querySelector(
|
|
3320
|
+
const errorContainer = this.rootElement?.querySelector(".onboarding-error-container");
|
|
3249
3321
|
if (errorContainer) {
|
|
3250
3322
|
errorContainer.remove();
|
|
3251
3323
|
}
|
|
3252
3324
|
// Clear OTP inputs
|
|
3253
|
-
this.otpInputs.forEach(input => {
|
|
3254
|
-
input.value =
|
|
3325
|
+
this.otpInputs.forEach((input) => {
|
|
3326
|
+
input.value = "";
|
|
3255
3327
|
input.disabled = false;
|
|
3256
3328
|
});
|
|
3257
3329
|
this.otpInputs = [];
|
|
3258
|
-
this.otp =
|
|
3330
|
+
this.otp = "";
|
|
3259
3331
|
this.otpSent = false;
|
|
3260
3332
|
this.loading = false;
|
|
3261
3333
|
// Clear timer
|
|
@@ -3266,88 +3338,105 @@ export class OnboardingUIWeb {
|
|
|
3266
3338
|
}
|
|
3267
3339
|
this.resendCooldown = 0;
|
|
3268
3340
|
if (this.resendButton) {
|
|
3269
|
-
this.resendButton.textContent =
|
|
3270
|
-
this.resendButton.classList.remove(
|
|
3271
|
-
this.resendButton.style.pointerEvents =
|
|
3272
|
-
this.resendButton.style.cursor =
|
|
3273
|
-
this.resendButton.style.opacity =
|
|
3341
|
+
this.resendButton.textContent = "Resend";
|
|
3342
|
+
this.resendButton.classList.remove("onboarding-otp-resend-link-disabled");
|
|
3343
|
+
this.resendButton.style.pointerEvents = "auto";
|
|
3344
|
+
this.resendButton.style.cursor = "pointer";
|
|
3345
|
+
this.resendButton.style.opacity = "1";
|
|
3274
3346
|
}
|
|
3275
3347
|
// Get auth methods
|
|
3276
|
-
const authMethods = this.config.authMethods || [
|
|
3277
|
-
const showEmail = authMethods.includes(
|
|
3278
|
-
const showGoogle = authMethods.includes(
|
|
3279
|
-
const showTwitter = authMethods.includes(
|
|
3280
|
-
const showDiscord = authMethods.includes(
|
|
3281
|
-
const showPasskey = authMethods.includes(
|
|
3348
|
+
const authMethods = this.config.authMethods || ["otp", "google"];
|
|
3349
|
+
const showEmail = authMethods.includes("otp");
|
|
3350
|
+
const showGoogle = authMethods.includes("google");
|
|
3351
|
+
const showTwitter = authMethods.includes("twitter");
|
|
3352
|
+
const showDiscord = authMethods.includes("discord");
|
|
3353
|
+
const showPasskey = authMethods.includes("passkey");
|
|
3282
3354
|
const socialMethods = [
|
|
3283
|
-
{ key:
|
|
3284
|
-
{ key:
|
|
3285
|
-
{ key:
|
|
3355
|
+
{ key: "google", show: showGoogle },
|
|
3356
|
+
{ key: "twitter", show: showTwitter },
|
|
3357
|
+
{ key: "discord", show: showDiscord },
|
|
3286
3358
|
].filter((m) => m.show);
|
|
3287
3359
|
// Show the email form and all login-related elements
|
|
3288
3360
|
if (this.emailForm) {
|
|
3289
|
-
this.emailForm.style.display = showEmail ?
|
|
3361
|
+
this.emailForm.style.display = showEmail ? "" : "none";
|
|
3362
|
+
}
|
|
3363
|
+
// Show the header again when returning to login form
|
|
3364
|
+
const header = this.rootElement?.querySelector(".onboarding-header");
|
|
3365
|
+
if (header) {
|
|
3366
|
+
header.style.display = "";
|
|
3290
3367
|
}
|
|
3291
3368
|
if (this.divider) {
|
|
3292
|
-
this.divider.style.display =
|
|
3369
|
+
this.divider.style.display =
|
|
3370
|
+
showEmail && socialMethods.length > 0 ? "" : "none";
|
|
3293
3371
|
}
|
|
3294
3372
|
if (this.passkeyDivider) {
|
|
3295
|
-
this.passkeyDivider.style.display =
|
|
3373
|
+
this.passkeyDivider.style.display =
|
|
3374
|
+
showPasskey && (showEmail || socialMethods.length > 0) ? "" : "none";
|
|
3296
3375
|
}
|
|
3297
3376
|
if (this.googleButton) {
|
|
3298
|
-
this.googleButton.style.display = showGoogle ?
|
|
3377
|
+
this.googleButton.style.display = showGoogle ? "" : "none";
|
|
3299
3378
|
this.googleButton.disabled = false;
|
|
3300
3379
|
}
|
|
3301
3380
|
if (this.twitterButton) {
|
|
3302
|
-
this.twitterButton.style.display = showTwitter ?
|
|
3381
|
+
this.twitterButton.style.display = showTwitter ? "" : "none";
|
|
3303
3382
|
this.twitterButton.disabled = false;
|
|
3304
3383
|
}
|
|
3305
3384
|
if (this.discordButton) {
|
|
3306
|
-
this.discordButton.style.display = showDiscord ?
|
|
3385
|
+
this.discordButton.style.display = showDiscord ? "" : "none";
|
|
3307
3386
|
this.discordButton.disabled = false;
|
|
3308
3387
|
}
|
|
3309
3388
|
if (this.socialGrid) {
|
|
3310
|
-
this.socialGrid.style.display = socialMethods.length > 1 ?
|
|
3389
|
+
this.socialGrid.style.display = socialMethods.length > 1 ? "" : "none";
|
|
3311
3390
|
}
|
|
3312
3391
|
// Show passkey buttons again when returning to login form
|
|
3313
3392
|
if (this.passkeyLoginButton) {
|
|
3314
|
-
this.passkeyLoginButton.style.display = showPasskey ?
|
|
3393
|
+
this.passkeyLoginButton.style.display = showPasskey ? "" : "none";
|
|
3315
3394
|
}
|
|
3316
3395
|
if (this.passkeySignupLink) {
|
|
3317
|
-
this.passkeySignupLink.style.display = showPasskey ?
|
|
3396
|
+
this.passkeySignupLink.style.display = showPasskey ? "" : "none";
|
|
3318
3397
|
}
|
|
3319
3398
|
if (this.passkeyErrorElement) {
|
|
3320
|
-
this.passkeyErrorElement.style.display =
|
|
3399
|
+
this.passkeyErrorElement.style.display = "none"; // Hide error when resetting
|
|
3321
3400
|
}
|
|
3322
3401
|
// Show external wallets again when returning to login form
|
|
3323
|
-
|
|
3324
|
-
|
|
3402
|
+
if (this.externalWalletsEnabled) {
|
|
3403
|
+
if (this.externalWalletContainer) {
|
|
3404
|
+
this.externalWalletContainer.style.display = "";
|
|
3405
|
+
}
|
|
3406
|
+
if (this.externalWalletDivider) {
|
|
3407
|
+
// Show divider only if we have email or social methods
|
|
3408
|
+
const hasEmailOrSocial = showEmail || socialMethods.length > 0;
|
|
3409
|
+
this.externalWalletDivider.style.display = hasEmailOrSocial
|
|
3410
|
+
? ""
|
|
3411
|
+
: "none";
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3325
3414
|
if (this.footer) {
|
|
3326
|
-
this.footer.style.display =
|
|
3415
|
+
this.footer.style.display = "";
|
|
3327
3416
|
}
|
|
3328
3417
|
// Clear error messages
|
|
3329
3418
|
this.setError(null);
|
|
3330
3419
|
if (this.errorElement) {
|
|
3331
|
-
this.errorElement.style.display =
|
|
3420
|
+
this.errorElement.style.display = "none";
|
|
3332
3421
|
}
|
|
3333
3422
|
// Reset email input - enable it and clear value
|
|
3334
3423
|
if (this.emailInput) {
|
|
3335
|
-
this.emailInput.value =
|
|
3424
|
+
this.emailInput.value = "";
|
|
3336
3425
|
this.emailInput.disabled = false;
|
|
3337
|
-
this.email =
|
|
3426
|
+
this.email = "";
|
|
3338
3427
|
}
|
|
3339
3428
|
// Reset OTP group (hidden input)
|
|
3340
3429
|
if (this.otpGroup) {
|
|
3341
|
-
this.otpGroup.style.display =
|
|
3430
|
+
this.otpGroup.style.display = "none";
|
|
3342
3431
|
if (this.otpInput) {
|
|
3343
|
-
this.otpInput.value =
|
|
3432
|
+
this.otpInput.value = "";
|
|
3344
3433
|
this.otpInput.disabled = false;
|
|
3345
3434
|
}
|
|
3346
3435
|
}
|
|
3347
3436
|
// Reset button state - ensure it shows "Continue" and is properly enabled/disabled
|
|
3348
3437
|
if (this.continueButton) {
|
|
3349
|
-
this.continueButton.
|
|
3350
|
-
|
|
3438
|
+
this.continueButton.textContent =
|
|
3439
|
+
this.config.labels?.emailButton || "Continue";
|
|
3351
3440
|
}
|
|
3352
3441
|
// Update button state to ensure everything is in sync
|
|
3353
3442
|
this.updateButtonState();
|
|
@@ -3358,13 +3447,13 @@ export class OnboardingUIWeb {
|
|
|
3358
3447
|
close() {
|
|
3359
3448
|
// Clear URL params to prevent showing error again on refresh
|
|
3360
3449
|
const url = new URL(window.location.href);
|
|
3361
|
-
url.searchParams.delete(
|
|
3362
|
-
url.searchParams.delete(
|
|
3450
|
+
url.searchParams.delete("error");
|
|
3451
|
+
url.searchParams.delete("success");
|
|
3363
3452
|
window.history.replaceState({}, document.title, url.toString());
|
|
3364
3453
|
if (this.modalOverlay) {
|
|
3365
3454
|
// Add closing animation
|
|
3366
|
-
this.modalOverlay.classList.remove(
|
|
3367
|
-
this.modalOverlay.classList.add(
|
|
3455
|
+
this.modalOverlay.classList.remove("onboarding-modal-open");
|
|
3456
|
+
this.modalOverlay.classList.add("onboarding-modal-closing");
|
|
3368
3457
|
// Remove after animation
|
|
3369
3458
|
setTimeout(() => {
|
|
3370
3459
|
this.destroy();
|
|
@@ -3374,7 +3463,7 @@ export class OnboardingUIWeb {
|
|
|
3374
3463
|
this.destroy();
|
|
3375
3464
|
}
|
|
3376
3465
|
// Restore body scroll
|
|
3377
|
-
document.body.style.overflow =
|
|
3466
|
+
document.body.style.overflow = "";
|
|
3378
3467
|
// Call onClose callback
|
|
3379
3468
|
if (this.config.onClose) {
|
|
3380
3469
|
this.config.onClose();
|
|
@@ -3395,7 +3484,7 @@ export class OnboardingUIWeb {
|
|
|
3395
3484
|
this.rootElement.parentNode.removeChild(this.rootElement);
|
|
3396
3485
|
}
|
|
3397
3486
|
// Restore body scroll
|
|
3398
|
-
document.body.style.overflow =
|
|
3487
|
+
document.body.style.overflow = "";
|
|
3399
3488
|
// Clear references
|
|
3400
3489
|
this.rootElement = null;
|
|
3401
3490
|
this.modalOverlay = null;
|
|
@@ -3407,7 +3496,6 @@ export class OnboardingUIWeb {
|
|
|
3407
3496
|
this.googleButton = null;
|
|
3408
3497
|
this.errorElement = null;
|
|
3409
3498
|
this.otpGroup = null;
|
|
3410
|
-
this.closeButton = null;
|
|
3411
3499
|
this.otpVerificationScreen = null; // Clear OTP screen reference
|
|
3412
3500
|
this.externalWalletContainer = null; // Clear external wallet container reference
|
|
3413
3501
|
this.externalWalletDivider = null; // Clear external wallet divider reference
|
|
@@ -3419,35 +3507,40 @@ export class OnboardingUIWeb {
|
|
|
3419
3507
|
const element = document.createElement(tag);
|
|
3420
3508
|
Object.keys(options).forEach((key) => {
|
|
3421
3509
|
const value = options[key];
|
|
3422
|
-
if (key ===
|
|
3510
|
+
if (key === "className" && typeof value === "string") {
|
|
3423
3511
|
element.className = value;
|
|
3424
3512
|
}
|
|
3425
|
-
else if (key ===
|
|
3513
|
+
else if (key === "textContent" &&
|
|
3514
|
+
(typeof value === "string" || value === null)) {
|
|
3426
3515
|
element.textContent = value;
|
|
3427
3516
|
}
|
|
3428
|
-
else if (key ===
|
|
3517
|
+
else if (key === "innerHTML" && typeof value === "string") {
|
|
3429
3518
|
element.innerHTML = value;
|
|
3430
3519
|
}
|
|
3431
|
-
else if (key ===
|
|
3432
|
-
element.setAttribute(
|
|
3520
|
+
else if (key === "style" && typeof value === "string") {
|
|
3521
|
+
element.setAttribute("style", value);
|
|
3433
3522
|
}
|
|
3434
|
-
else if (key ===
|
|
3523
|
+
else if (key === "htmlFor" && typeof value === "string") {
|
|
3435
3524
|
// Use setAttribute for htmlFor to ensure it works correctly
|
|
3436
|
-
element.setAttribute(
|
|
3525
|
+
element.setAttribute("for", value);
|
|
3437
3526
|
}
|
|
3438
|
-
else if (key.startsWith(
|
|
3527
|
+
else if (key.startsWith("aria-") ||
|
|
3528
|
+
key === "role" ||
|
|
3529
|
+
key === "tabIndex" ||
|
|
3530
|
+
key === "autocomplete" ||
|
|
3531
|
+
key === "noValidate") {
|
|
3439
3532
|
// Handle ARIA attributes and other special attributes
|
|
3440
|
-
if (key ===
|
|
3533
|
+
if (key === "tabIndex") {
|
|
3441
3534
|
element.tabIndex = value;
|
|
3442
3535
|
}
|
|
3443
|
-
else if (key ===
|
|
3536
|
+
else if (key === "noValidate") {
|
|
3444
3537
|
element.noValidate = value;
|
|
3445
3538
|
}
|
|
3446
3539
|
else {
|
|
3447
3540
|
element.setAttribute(key, String(value));
|
|
3448
3541
|
}
|
|
3449
3542
|
}
|
|
3450
|
-
else if (key !==
|
|
3543
|
+
else if (key !== "style" && value !== undefined) {
|
|
3451
3544
|
element[key] = value;
|
|
3452
3545
|
}
|
|
3453
3546
|
});
|
|
@@ -3458,34 +3551,29 @@ export class OnboardingUIWeb {
|
|
|
3458
3551
|
*/
|
|
3459
3552
|
parseStyle(style) {
|
|
3460
3553
|
if (!style)
|
|
3461
|
-
return
|
|
3462
|
-
if (typeof style ===
|
|
3554
|
+
return "";
|
|
3555
|
+
if (typeof style === "string")
|
|
3463
3556
|
return style;
|
|
3464
3557
|
return Object.entries(style)
|
|
3465
3558
|
.filter(([_, value]) => value !== undefined && value !== null)
|
|
3466
3559
|
.map(([key, value]) => {
|
|
3467
|
-
const cssKey = key.replace(/([A-Z])/g,
|
|
3560
|
+
const cssKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
3468
3561
|
return `${cssKey}: ${value}`;
|
|
3469
3562
|
})
|
|
3470
|
-
.join(
|
|
3563
|
+
.join("; ");
|
|
3471
3564
|
}
|
|
3472
3565
|
/**
|
|
3473
3566
|
* Create email icon SVG
|
|
3474
3567
|
*/
|
|
3475
3568
|
createEmailIcon() {
|
|
3476
|
-
const svg = document.createElementNS(
|
|
3477
|
-
svg.setAttribute(
|
|
3478
|
-
svg.setAttribute(
|
|
3479
|
-
svg.setAttribute(
|
|
3480
|
-
svg.setAttribute(
|
|
3481
|
-
svg.setAttribute(
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
path.setAttribute('d', 'M2.5 6.66667L10 11.6667L17.5 6.66667M3.33333 15H16.6667C17.5871 15 18.3333 14.2538 18.3333 13.3333V6.66667C18.3333 5.74619 17.5871 5 16.6667 5H3.33333C2.41286 5 1.66667 5.74619 1.66667 6.66667V13.3333C1.66667 14.2538 2.41286 15 3.33333 15Z');
|
|
3485
|
-
path.setAttribute('stroke', 'currentColor');
|
|
3486
|
-
path.setAttribute('stroke-width', '1.5');
|
|
3487
|
-
path.setAttribute('stroke-linecap', 'round');
|
|
3488
|
-
path.setAttribute('stroke-linejoin', 'round');
|
|
3569
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
3570
|
+
svg.setAttribute("class", "onboarding-input-icon");
|
|
3571
|
+
svg.setAttribute("width", "18");
|
|
3572
|
+
svg.setAttribute("height", "18");
|
|
3573
|
+
svg.setAttribute("viewBox", "0 0 17 17");
|
|
3574
|
+
svg.setAttribute("fill", "currentColor");
|
|
3575
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
3576
|
+
path.setAttribute("d", "M0 2v13h17v-13h-17zM8.494 9.817l-6.896-6.817h13.82l-6.924 6.817zM5.755 8.516l-4.755 4.682v-9.383l4.755 4.701zM6.466 9.219l2.026 2.003 1.996-1.966 4.8 4.744h-13.677l4.855-4.781zM11.201 8.555l4.799-4.725v9.467l-4.799-4.742z");
|
|
3489
3577
|
svg.appendChild(path);
|
|
3490
3578
|
return svg;
|
|
3491
3579
|
}
|
|
@@ -3493,35 +3581,35 @@ export class OnboardingUIWeb {
|
|
|
3493
3581
|
* Create Google icon SVG
|
|
3494
3582
|
*/
|
|
3495
3583
|
createGoogleIcon() {
|
|
3496
|
-
const svg = document.createElementNS(
|
|
3497
|
-
svg.setAttribute(
|
|
3498
|
-
svg.setAttribute(
|
|
3499
|
-
svg.setAttribute(
|
|
3500
|
-
svg.setAttribute(
|
|
3501
|
-
svg.setAttribute(
|
|
3502
|
-
svg.setAttribute(
|
|
3584
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
3585
|
+
svg.setAttribute("class", "onboarding-google-icon");
|
|
3586
|
+
svg.setAttribute("width", "20");
|
|
3587
|
+
svg.setAttribute("height", "20");
|
|
3588
|
+
svg.setAttribute("viewBox", "0 0 20 20");
|
|
3589
|
+
svg.setAttribute("fill", "none");
|
|
3590
|
+
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
3503
3591
|
const paths = [
|
|
3504
3592
|
{
|
|
3505
|
-
d:
|
|
3506
|
-
fill:
|
|
3593
|
+
d: "M18.1712 8.36792H17.5V8.33333H10V11.6667H14.7096C14.2225 13.1071 13.2408 14.2854 12.0125 15.0125L14.9696 17.3458C16.7792 15.6958 17.9167 13.3958 17.9167 10.8333C17.9167 10.275 17.8708 9.72917 17.7833 9.20417L18.1712 8.36792Z",
|
|
3594
|
+
fill: "#4285F4",
|
|
3507
3595
|
},
|
|
3508
3596
|
{
|
|
3509
|
-
d:
|
|
3510
|
-
fill:
|
|
3597
|
+
d: "M10 18.3333C12.5542 18.3333 14.7208 17.4708 16.3042 16.0125L13.3471 13.6792C12.5042 14.2542 11.4042 14.5833 10 14.5833C7.52083 14.5833 5.39583 12.9042 4.61667 10.6917L1.57083 13.0292C3.13333 16.1 6.32083 18.3333 10 18.3333Z",
|
|
3598
|
+
fill: "#34A853",
|
|
3511
3599
|
},
|
|
3512
3600
|
{
|
|
3513
|
-
d:
|
|
3514
|
-
fill:
|
|
3601
|
+
d: "M4.61667 10.6917C4.39583 10.0708 4.27083 9.40417 4.27083 8.70833C4.27083 8.0125 4.39583 7.34583 4.61667 6.72417L1.57083 4.3875C0.9375 5.66667 0.583336 7.10833 0.583336 8.70833C0.583336 10.3083 0.9375 11.75 1.57083 13.0292L4.61667 10.6917Z",
|
|
3602
|
+
fill: "#FBBC05",
|
|
3515
3603
|
},
|
|
3516
3604
|
{
|
|
3517
|
-
d:
|
|
3518
|
-
fill:
|
|
3605
|
+
d: "M10 2.91667C11.5125 2.91667 12.8708 3.47083 13.9292 4.42917L16.375 2C14.7208 0.483333 12.5542 -0.000165871 10 -0.000165871C6.32083 -0.000165871 3.13333 2.23333 1.57083 5.30417L4.61667 7.64167C5.39583 5.42917 7.52083 3.75 10 3.75V2.91667Z",
|
|
3606
|
+
fill: "#EA4335",
|
|
3519
3607
|
},
|
|
3520
3608
|
];
|
|
3521
3609
|
paths.forEach((pathData) => {
|
|
3522
|
-
const path = document.createElementNS(
|
|
3523
|
-
path.setAttribute(
|
|
3524
|
-
path.setAttribute(
|
|
3610
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
3611
|
+
path.setAttribute("d", pathData.d);
|
|
3612
|
+
path.setAttribute("fill", pathData.fill);
|
|
3525
3613
|
svg.appendChild(path);
|
|
3526
3614
|
});
|
|
3527
3615
|
return svg;
|
|
@@ -3530,19 +3618,19 @@ export class OnboardingUIWeb {
|
|
|
3530
3618
|
* Create right arrow icon SVG
|
|
3531
3619
|
*/
|
|
3532
3620
|
createArrowIcon() {
|
|
3533
|
-
const svg = document.createElementNS(
|
|
3534
|
-
svg.setAttribute(
|
|
3535
|
-
svg.setAttribute(
|
|
3536
|
-
svg.setAttribute(
|
|
3537
|
-
svg.setAttribute(
|
|
3538
|
-
svg.setAttribute(
|
|
3539
|
-
svg.setAttribute(
|
|
3540
|
-
const path = document.createElementNS(
|
|
3541
|
-
path.setAttribute(
|
|
3542
|
-
path.setAttribute(
|
|
3543
|
-
path.setAttribute(
|
|
3544
|
-
path.setAttribute(
|
|
3545
|
-
path.setAttribute(
|
|
3621
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
3622
|
+
svg.setAttribute("class", "onboarding-input-arrow-icon");
|
|
3623
|
+
svg.setAttribute("width", "20");
|
|
3624
|
+
svg.setAttribute("height", "20");
|
|
3625
|
+
svg.setAttribute("viewBox", "0 0 20 20");
|
|
3626
|
+
svg.setAttribute("fill", "none");
|
|
3627
|
+
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
3628
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
3629
|
+
path.setAttribute("d", "M7.5 15L12.5 10L7.5 5");
|
|
3630
|
+
path.setAttribute("stroke", "currentColor");
|
|
3631
|
+
path.setAttribute("stroke-width", "2");
|
|
3632
|
+
path.setAttribute("stroke-linecap", "round");
|
|
3633
|
+
path.setAttribute("stroke-linejoin", "round");
|
|
3546
3634
|
svg.appendChild(path);
|
|
3547
3635
|
return svg;
|
|
3548
3636
|
}
|
|
@@ -3550,20 +3638,20 @@ export class OnboardingUIWeb {
|
|
|
3550
3638
|
* Create passkey icon SVG
|
|
3551
3639
|
*/
|
|
3552
3640
|
createPasskeyIcon() {
|
|
3553
|
-
const svg = document.createElementNS(
|
|
3554
|
-
svg.setAttribute(
|
|
3555
|
-
svg.setAttribute(
|
|
3556
|
-
svg.setAttribute(
|
|
3557
|
-
svg.setAttribute(
|
|
3558
|
-
svg.setAttribute(
|
|
3559
|
-
svg.setAttribute(
|
|
3560
|
-
svg.setAttribute(
|
|
3641
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
3642
|
+
svg.setAttribute("class", "onboarding-passkey-icon");
|
|
3643
|
+
svg.setAttribute("width", "20");
|
|
3644
|
+
svg.setAttribute("height", "20");
|
|
3645
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
3646
|
+
svg.setAttribute("fill", "none");
|
|
3647
|
+
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
3648
|
+
svg.setAttribute("aria-hidden", "true");
|
|
3561
3649
|
// Passkey icon (user with key)
|
|
3562
|
-
const path = document.createElementNS(
|
|
3563
|
-
path.setAttribute(
|
|
3650
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
3651
|
+
path.setAttribute("d", "M3.682 19.338v-2.102c0-.476.127-.915.382-1.315.255-.4.603-.708 1.042-.926a14.89 14.89 0 0 1 2.939-1.067c.982-.24 1.966-.36 2.953-.36.352 0 .708.018 1.066.054.358.035.712.084 1.062.147-.015.831.164 1.613.537 2.347a4.882 4.882 0 0 0 1.595 1.822v1.4H3.682Zm15.003 2.713-1.303-1.303v-4.029a2.976 2.976 0 0 1-1.564-1.08 2.944 2.944 0 0 1-.608-1.832c0-.841.297-1.557.891-2.147a2.944 2.944 0 0 1 2.154-.886c.837 0 1.552.295 2.145.886.594.59.89 1.306.89 2.148 0 .656-.182 1.238-.546 1.743a3.018 3.018 0 0 1-1.404 1.084l1.073 1.072-1.294 1.31 1.294 1.301-1.728 1.733ZM11 12.006c-.94 0-1.742-.333-2.405-.999a3.28 3.28 0 0 1-.994-2.4c0-.94.331-1.743.994-2.405A3.276 3.276 0 0 1 11 5.208c.94 0 1.742.331 2.405.994.663.662.994 1.463.994 2.4 0 .939-.331 1.74-.994 2.406a3.27 3.27 0 0 1-2.405.998Zm7.252 2.235a.833.833 0 0 0 .612-.255.842.842 0 0 0 .255-.617.834.834 0 0 0-.253-.614.835.835 0 0 0-.612-.252.85.85 0 0 0-.616.251.823.823 0 0 0-.257.612c0 .24.085.447.257.618a.838.838 0 0 0 .614.257Z");
|
|
3564
3652
|
// Set icon color based on theme: white for dark theme, black for light theme
|
|
3565
|
-
const iconColor = this.config.theme ===
|
|
3566
|
-
path.setAttribute(
|
|
3653
|
+
const iconColor = this.config.theme === "dark" ? "#ffffff" : "#000000";
|
|
3654
|
+
path.setAttribute("fill", iconColor);
|
|
3567
3655
|
svg.appendChild(path);
|
|
3568
3656
|
return svg;
|
|
3569
3657
|
}
|
|
@@ -3571,16 +3659,16 @@ export class OnboardingUIWeb {
|
|
|
3571
3659
|
* Create X (Twitter) icon SVG
|
|
3572
3660
|
*/
|
|
3573
3661
|
createTwitterIcon() {
|
|
3574
|
-
const svg = document.createElementNS(
|
|
3575
|
-
svg.setAttribute(
|
|
3576
|
-
svg.setAttribute(
|
|
3577
|
-
svg.setAttribute(
|
|
3578
|
-
svg.setAttribute(
|
|
3579
|
-
svg.setAttribute(
|
|
3580
|
-
svg.setAttribute(
|
|
3581
|
-
const path = document.createElementNS(
|
|
3582
|
-
path.setAttribute(
|
|
3583
|
-
path.setAttribute(
|
|
3662
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
3663
|
+
svg.setAttribute("class", "onboarding-social-icon");
|
|
3664
|
+
svg.setAttribute("width", "20");
|
|
3665
|
+
svg.setAttribute("height", "20");
|
|
3666
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
3667
|
+
svg.setAttribute("fill", "none");
|
|
3668
|
+
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
3669
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
3670
|
+
path.setAttribute("d", "M4 3h4.6l3.09 4.1L14.5 3H20l-5.63 7.08L20.4 21H15.8l-3.5-4.65L8.3 21H2.8l6-7.67L4 3Zm2.04 1.2L9.7 9l.1.12L4.97 19h1.79l4.04-5.39L14.78 19h1.8l-5.02-6.55-.05-.06L17.97 4.2h-1.8l-3.52 4.62L9 4.2H6.04Z");
|
|
3671
|
+
path.setAttribute("fill", "currentColor");
|
|
3584
3672
|
svg.appendChild(path);
|
|
3585
3673
|
return svg;
|
|
3586
3674
|
}
|
|
@@ -3588,16 +3676,16 @@ export class OnboardingUIWeb {
|
|
|
3588
3676
|
* Create Discord icon SVG
|
|
3589
3677
|
*/
|
|
3590
3678
|
createDiscordIcon() {
|
|
3591
|
-
const svg = document.createElementNS(
|
|
3592
|
-
svg.setAttribute(
|
|
3593
|
-
svg.setAttribute(
|
|
3594
|
-
svg.setAttribute(
|
|
3595
|
-
svg.setAttribute(
|
|
3596
|
-
svg.setAttribute(
|
|
3597
|
-
svg.setAttribute(
|
|
3598
|
-
const path = document.createElementNS(
|
|
3599
|
-
path.setAttribute(
|
|
3600
|
-
path.setAttribute(
|
|
3679
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
3680
|
+
svg.setAttribute("class", "onboarding-social-icon");
|
|
3681
|
+
svg.setAttribute("width", "20");
|
|
3682
|
+
svg.setAttribute("height", "20");
|
|
3683
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
3684
|
+
svg.setAttribute("fill", "none");
|
|
3685
|
+
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
|
3686
|
+
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
3687
|
+
path.setAttribute("d", "M20.317 4.37a16.75 16.75 0 0 0-4.091-1.272.06.06 0 0 0-.063.03 11.651 11.651 0 0 0-.512 1.054 15.93 15.93 0 0 0-4.813 0 10.69 10.69 0 0 0-.522-1.054.06.06 0 0 0-.063-.03 16.742 16.742 0 0 0-4.092 1.272.055.055 0 0 0-.025.021C2.84 8.167 2.18 11.875 2.46 15.547a.066.066 0 0 0 .025.045 16.86 16.86 0 0 0 4.98 2.52.06.06 0 0 0 .066-.02c.384-.525.726-1.08 1.02-1.66a.06.06 0 0 0-.033-.083 11.117 11.117 0 0 1-1.593-.765.06.06 0 0 1-.006-.1c.107-.08.214-.162.316-.245a.06.06 0 0 1 .061-.008 11.65 11.65 0 0 0 10.104 0 .06.06 0 0 1 .062.007c.103.083.21.166.316.246a.06.06 0 0 1-.005.1 10.859 10.859 0 0 1-1.594.764.06.06 0 0 0-.033.084 9.255 9.255 0 0 0 1.02 1.659.06.06 0 0 0 .065.02 16.824 16.824 0 0 0 4.982-2.52.06.06 0 0 0 .024-.044c.416-5.09-.698-8.76-2.89-11.156a.048.048 0 0 0-.024-.02ZM9.68 13.348c-.996 0-1.812-.91-1.812-2.03 0-1.12.805-2.031 1.812-2.031 1.016 0 1.822.922 1.812 2.031 0 1.12-.805 2.03-1.812 2.03Zm4.64 0c-.996 0-1.812-.91-1.812-2.03 0-1.12.805-2.031 1.812-2.031 1.016 0 1.822.922 1.812 2.031 0 1.12-.796 2.03-1.812 2.03Z");
|
|
3688
|
+
path.setAttribute("fill", "currentColor");
|
|
3601
3689
|
svg.appendChild(path);
|
|
3602
3690
|
return svg;
|
|
3603
3691
|
}
|
|
@@ -3608,7 +3696,7 @@ export class OnboardingUIWeb {
|
|
|
3608
3696
|
if (this.loading)
|
|
3609
3697
|
return;
|
|
3610
3698
|
try {
|
|
3611
|
-
this.setLoading(true,
|
|
3699
|
+
this.setLoading(true, "passkey");
|
|
3612
3700
|
this.hidePasskeyError();
|
|
3613
3701
|
if (this.config.onPasskeyLogin) {
|
|
3614
3702
|
await this.config.onPasskeyLogin();
|
|
@@ -3618,13 +3706,15 @@ export class OnboardingUIWeb {
|
|
|
3618
3706
|
}
|
|
3619
3707
|
}
|
|
3620
3708
|
else {
|
|
3621
|
-
throw new Error(
|
|
3709
|
+
throw new Error("Passkey login handler not configured");
|
|
3622
3710
|
}
|
|
3623
3711
|
}
|
|
3624
3712
|
catch (error) {
|
|
3625
|
-
this.showPasskeyError(error instanceof Error ? error.message :
|
|
3713
|
+
this.showPasskeyError(error instanceof Error ? error.message : "Failed to login with passkey");
|
|
3626
3714
|
if (this.config.onLoginError) {
|
|
3627
|
-
this.config.onLoginError(error instanceof Error
|
|
3715
|
+
this.config.onLoginError(error instanceof Error
|
|
3716
|
+
? error
|
|
3717
|
+
: new Error("Failed to login with passkey"));
|
|
3628
3718
|
}
|
|
3629
3719
|
}
|
|
3630
3720
|
finally {
|
|
@@ -3638,7 +3728,7 @@ export class OnboardingUIWeb {
|
|
|
3638
3728
|
if (this.loading)
|
|
3639
3729
|
return;
|
|
3640
3730
|
try {
|
|
3641
|
-
this.setLoading(true,
|
|
3731
|
+
this.setLoading(true, "passkey");
|
|
3642
3732
|
this.hidePasskeyError();
|
|
3643
3733
|
if (this.config.onPasskeySignup) {
|
|
3644
3734
|
await this.config.onPasskeySignup();
|
|
@@ -3648,13 +3738,15 @@ export class OnboardingUIWeb {
|
|
|
3648
3738
|
}
|
|
3649
3739
|
}
|
|
3650
3740
|
else {
|
|
3651
|
-
throw new Error(
|
|
3741
|
+
throw new Error("Passkey signup handler not configured");
|
|
3652
3742
|
}
|
|
3653
3743
|
}
|
|
3654
3744
|
catch (error) {
|
|
3655
|
-
this.showPasskeyError(error instanceof Error ? error.message :
|
|
3745
|
+
this.showPasskeyError(error instanceof Error ? error.message : "Failed to signup with passkey");
|
|
3656
3746
|
if (this.config.onLoginError) {
|
|
3657
|
-
this.config.onLoginError(error instanceof Error
|
|
3747
|
+
this.config.onLoginError(error instanceof Error
|
|
3748
|
+
? error
|
|
3749
|
+
: new Error("Failed to signup with passkey"));
|
|
3658
3750
|
}
|
|
3659
3751
|
}
|
|
3660
3752
|
finally {
|
|
@@ -3668,7 +3760,7 @@ export class OnboardingUIWeb {
|
|
|
3668
3760
|
if (!this.passkeyErrorElement)
|
|
3669
3761
|
return;
|
|
3670
3762
|
this.passkeyErrorElement.textContent = message;
|
|
3671
|
-
this.passkeyErrorElement.style.display =
|
|
3763
|
+
this.passkeyErrorElement.style.display = "block";
|
|
3672
3764
|
}
|
|
3673
3765
|
/**
|
|
3674
3766
|
* Hide passkey-specific error
|
|
@@ -3676,8 +3768,8 @@ export class OnboardingUIWeb {
|
|
|
3676
3768
|
hidePasskeyError() {
|
|
3677
3769
|
if (!this.passkeyErrorElement)
|
|
3678
3770
|
return;
|
|
3679
|
-
this.passkeyErrorElement.textContent =
|
|
3680
|
-
this.passkeyErrorElement.style.display =
|
|
3771
|
+
this.passkeyErrorElement.textContent = "";
|
|
3772
|
+
this.passkeyErrorElement.style.display = "none";
|
|
3681
3773
|
}
|
|
3682
3774
|
}
|
|
3683
3775
|
export default OnboardingUIWeb;
|