@swype-org/react-sdk 0.1.28 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createContext, useRef, useEffect, useState, useCallback, useMemo, useContext } from 'react';
2
- import { PrivyProvider, usePrivy } from '@privy-io/react-auth';
1
+ import { createContext, useRef, useState, useCallback, useMemo, useContext, useEffect } from 'react';
2
+ import { PrivyProvider, usePrivy, useLoginWithEmail, useLoginWithSms } from '@privy-io/react-auth';
3
3
  import { createConfig, http, WagmiProvider, useConfig, useConnect, useSwitchChain } from 'wagmi';
4
4
  import { mainnet, arbitrum, base } from 'wagmi/chains';
5
5
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
@@ -25,9 +25,9 @@ var darkTheme = {
25
25
  textMuted: "#7fa4b0",
26
26
  textInverse: "#052027",
27
27
  border: "#2b4551",
28
- borderFocus: "#2ec4cf",
29
- accent: "#2eb6c2",
30
- accentHover: "#239ba6",
28
+ borderFocus: "#28b67a",
29
+ accent: "#28b67a",
30
+ accentHover: "#219866",
31
31
  accentText: "#ffffff",
32
32
  success: "#0f9d73",
33
33
  successBg: "#0f2f2a",
@@ -49,9 +49,9 @@ var lightTheme = {
49
49
  textMuted: "#7d97a1",
50
50
  textInverse: "#ffffff",
51
51
  border: "#d2e4ea",
52
- borderFocus: "#2eb6c2",
53
- accent: "#2eb6c2",
54
- accentHover: "#259da7",
52
+ borderFocus: "#28b67a",
53
+ accent: "#28b67a",
54
+ accentHover: "#219866",
55
55
  accentText: "#ffffff",
56
56
  success: "#0f9d73",
57
57
  successBg: "#e6f7f1",
@@ -74,26 +74,6 @@ var wagmiConfig = createConfig({
74
74
  [base.id]: http()
75
75
  }
76
76
  });
77
- var PRIVY_MODAL_CENTER_CSS = `
78
- @media (max-width: 440px) {
79
- #privy-dialog [data-headlessui-state] {
80
- position: static !important;
81
- bottom: auto !important;
82
- margin: auto !important;
83
- width: 360px !important;
84
- max-width: calc(100vw - 32px) !important;
85
- box-shadow: 0px 8px 36px rgba(55, 65, 81, 0.15) !important;
86
- border-radius: var(--privy-border-radius-lg) !important;
87
- transform: none !important;
88
- transition: opacity 100ms ease-in !important;
89
- }
90
- #privy-dialog [data-headlessui-state].entering,
91
- #privy-dialog [data-headlessui-state].leaving {
92
- opacity: 0 !important;
93
- transform: none !important;
94
- }
95
- }
96
- `;
97
77
  var SwypeContext = createContext(null);
98
78
  function SwypeProvider({
99
79
  apiBaseUrl,
@@ -104,15 +84,6 @@ function SwypeProvider({
104
84
  if (!queryClientRef.current) {
105
85
  queryClientRef.current = new QueryClient();
106
86
  }
107
- useEffect(() => {
108
- const style = document.createElement("style");
109
- style.setAttribute("data-swype", "privy-modal-center");
110
- style.textContent = PRIVY_MODAL_CENTER_CSS;
111
- document.head.appendChild(style);
112
- return () => {
113
- style.remove();
114
- };
115
- }, []);
116
87
  const [depositAmount, setDepositAmountRaw] = useState(null);
117
88
  const setDepositAmount = useCallback((amount) => {
118
89
  setDepositAmountRaw(amount);
@@ -135,6 +106,12 @@ function SwypeProvider({
135
106
  appearance: {
136
107
  theme,
137
108
  accentColor: getTheme(theme).accent
109
+ },
110
+ intl: {
111
+ defaultCountry: "US"
112
+ },
113
+ embeddedWallets: {
114
+ showWalletUIs: false
138
115
  }
139
116
  },
140
117
  children: /* @__PURE__ */ jsx(SwypeContext.Provider, { value, children })
@@ -173,6 +150,7 @@ __export(api_exports, {
173
150
  fetchAccounts: () => fetchAccounts,
174
151
  fetchAuthorizationSession: () => fetchAuthorizationSession,
175
152
  fetchChains: () => fetchChains,
153
+ fetchMerchantPublicKey: () => fetchMerchantPublicKey,
176
154
  fetchProviders: () => fetchProviders,
177
155
  fetchTransfer: () => fetchTransfer,
178
156
  fetchUserConfig: () => fetchUserConfig,
@@ -215,9 +193,13 @@ async function fetchAccounts(apiBaseUrl, token, credentialId) {
215
193
  return data.items;
216
194
  }
217
195
  async function createTransfer(apiBaseUrl, token, params) {
196
+ if (!params.merchantAuthorization) {
197
+ throw new Error("merchantAuthorization is required for transfer creation.");
198
+ }
218
199
  const body = {
219
200
  id: params.id ?? crypto.randomUUID(),
220
201
  credentialId: params.credentialId,
202
+ merchantAuthorization: params.merchantAuthorization,
221
203
  sources: [{ [params.sourceType]: params.sourceId }],
222
204
  destinations: [
223
205
  {
@@ -242,6 +224,13 @@ async function createTransfer(apiBaseUrl, token, params) {
242
224
  if (!res.ok) await throwApiError(res);
243
225
  return await res.json();
244
226
  }
227
+ async function fetchMerchantPublicKey(apiBaseUrl, merchantId) {
228
+ const res = await fetch(
229
+ `${apiBaseUrl}/v1/merchants/${encodeURIComponent(merchantId)}/public-key`
230
+ );
231
+ if (!res.ok) await throwApiError(res);
232
+ return await res.json();
233
+ }
245
234
  async function fetchTransfer(apiBaseUrl, token, transferId, authorizationSessionToken) {
246
235
  if (!token && !authorizationSessionToken) {
247
236
  throw new Error("Missing auth credentials for transfer fetch.");
@@ -2097,6 +2086,46 @@ function AdvancedSettings({
2097
2086
  ] });
2098
2087
  }
2099
2088
 
2089
+ // src/auth.ts
2090
+ var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2091
+ var PHONE_DIGIT_PATTERN = /^\d{7,15}$/;
2092
+ function normalizePhoneNumber(rawValue) {
2093
+ const trimmed = rawValue.trim();
2094
+ if (!trimmed) return null;
2095
+ const hasExplicitCountryCode = trimmed.startsWith("+");
2096
+ const digits = trimmed.replace(/\D/g, "");
2097
+ if (!PHONE_DIGIT_PATTERN.test(digits)) return null;
2098
+ return hasExplicitCountryCode ? `+${digits}` : digits;
2099
+ }
2100
+ function normalizeAuthIdentifier(rawValue) {
2101
+ const trimmed = rawValue.trim();
2102
+ if (!trimmed) return null;
2103
+ if (EMAIL_PATTERN.test(trimmed)) {
2104
+ return {
2105
+ kind: "email",
2106
+ value: trimmed.toLowerCase()
2107
+ };
2108
+ }
2109
+ const normalizedPhoneNumber = normalizePhoneNumber(trimmed);
2110
+ if (normalizedPhoneNumber) {
2111
+ return {
2112
+ kind: "phone",
2113
+ value: normalizedPhoneNumber
2114
+ };
2115
+ }
2116
+ return null;
2117
+ }
2118
+ function maskAuthIdentifier(identifier) {
2119
+ if (identifier.kind === "email") {
2120
+ const [localPart, domain = ""] = identifier.value.split("@");
2121
+ const localPrefix = localPart.slice(0, 2);
2122
+ return `${localPrefix}${"*".repeat(Math.max(localPart.length - 2, 0))}@${domain}`;
2123
+ }
2124
+ const digits = identifier.value.replace(/\D/g, "");
2125
+ const visibleSuffix = digits.slice(-4);
2126
+ return `***-***-${visibleSuffix}`;
2127
+ }
2128
+
2100
2129
  // src/processingStatus.ts
2101
2130
  var PROCESSING_TIMEOUT_MS = 18e4;
2102
2131
  function resolvePreferredTransfer(polledTransfer, localTransfer) {
@@ -2121,14 +2150,20 @@ function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
2121
2150
  function buildProcessingTimeoutMessage(status) {
2122
2151
  return `Payment is taking longer than expected (status: ${status}). Please try again.`;
2123
2152
  }
2153
+
2154
+ // src/walletFlow.ts
2155
+ var MOBILE_USER_AGENT_PATTERN = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
2156
+ function isMobileUserAgent(userAgent) {
2157
+ if (!userAgent) {
2158
+ return false;
2159
+ }
2160
+ return MOBILE_USER_AGENT_PATTERN.test(userAgent);
2161
+ }
2162
+ function shouldUseWalletConnector(options) {
2163
+ return options.useWalletConnector ?? !isMobileUserAgent(options.userAgent);
2164
+ }
2124
2165
  var ACTIVE_CREDENTIAL_STORAGE_KEY = "swype_active_credential_id";
2125
2166
  var MIN_SEND_AMOUNT_USD = 0.25;
2126
- function isMobile() {
2127
- if (typeof navigator === "undefined") return false;
2128
- return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
2129
- navigator.userAgent
2130
- );
2131
- }
2132
2167
  function computeSmartDefaults(accts, transferAmount) {
2133
2168
  if (accts.length === 0) return null;
2134
2169
  for (const acct of accts) {
@@ -2203,10 +2238,21 @@ function SwypePayment({
2203
2238
  onComplete,
2204
2239
  onError,
2205
2240
  useWalletConnector,
2206
- idempotencyKey
2241
+ idempotencyKey,
2242
+ merchantAuthorization
2207
2243
  }) {
2208
2244
  const { apiBaseUrl, tokens, depositAmount } = useSwypeConfig();
2209
- const { ready, authenticated, user, login, logout, getAccessToken } = usePrivy();
2245
+ const { ready, authenticated, user, logout, getAccessToken } = usePrivy();
2246
+ const {
2247
+ sendCode: sendEmailCode,
2248
+ loginWithCode: loginWithEmailCode,
2249
+ state: emailLoginState
2250
+ } = useLoginWithEmail();
2251
+ const {
2252
+ sendCode: sendSmsCode,
2253
+ loginWithCode: loginWithSmsCode,
2254
+ state: smsLoginState
2255
+ } = useLoginWithSms();
2210
2256
  const [step, setStep] = useState("login");
2211
2257
  const [error, setError] = useState(null);
2212
2258
  const [providers, setProviders] = useState([]);
@@ -2231,6 +2277,11 @@ function SwypePayment({
2231
2277
  if (typeof window === "undefined") return null;
2232
2278
  return window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY);
2233
2279
  });
2280
+ const [authInput, setAuthInput] = useState("");
2281
+ const [verificationTarget, setVerificationTarget] = useState(
2282
+ null
2283
+ );
2284
+ const [otpCode, setOtpCode] = useState("");
2234
2285
  const [mobileFlow, setMobileFlow] = useState(false);
2235
2286
  const pollingTransferIdRef = useRef(null);
2236
2287
  const mobileSigningTransferIdRef = useRef(null);
@@ -2248,9 +2299,81 @@ function SwypePayment({
2248
2299
  setAmount(depositAmount.toString());
2249
2300
  }
2250
2301
  }, [depositAmount]);
2302
+ const resetHeadlessLogin = useCallback(() => {
2303
+ setAuthInput("");
2304
+ setVerificationTarget(null);
2305
+ setOtpCode("");
2306
+ }, []);
2307
+ const activeOtpStatus = verificationTarget?.kind === "email" ? emailLoginState.status : verificationTarget?.kind === "phone" ? smsLoginState.status : "initial";
2308
+ const activeOtpErrorMessage = verificationTarget?.kind === "email" && emailLoginState.status === "error" ? emailLoginState.error?.message ?? "Failed to continue with email." : verificationTarget?.kind === "phone" && smsLoginState.status === "error" ? smsLoginState.error?.message ?? "Failed to continue with phone number." : null;
2309
+ useEffect(() => {
2310
+ if (activeOtpErrorMessage) {
2311
+ setError(activeOtpErrorMessage);
2312
+ }
2313
+ }, [activeOtpErrorMessage]);
2314
+ const handleSendLoginCode = useCallback(async () => {
2315
+ const normalizedIdentifier = normalizeAuthIdentifier(authInput);
2316
+ if (!normalizedIdentifier) {
2317
+ setError("Enter a valid email address or phone number.");
2318
+ return;
2319
+ }
2320
+ setError(null);
2321
+ setOtpCode("");
2322
+ try {
2323
+ if (normalizedIdentifier.kind === "email") {
2324
+ await sendEmailCode({ email: normalizedIdentifier.value });
2325
+ } else {
2326
+ await sendSmsCode({ phoneNumber: normalizedIdentifier.value });
2327
+ }
2328
+ setVerificationTarget(normalizedIdentifier);
2329
+ } catch (err) {
2330
+ const msg = err instanceof Error ? err.message : "Failed to send verification code";
2331
+ setError(msg);
2332
+ }
2333
+ }, [authInput, sendEmailCode, sendSmsCode]);
2334
+ const handleVerifyLoginCode = useCallback(async () => {
2335
+ if (!verificationTarget) return;
2336
+ const trimmedCode = otpCode.trim();
2337
+ if (!/^\d{6}$/.test(trimmedCode)) {
2338
+ setError("Enter the 6-digit verification code.");
2339
+ return;
2340
+ }
2341
+ setError(null);
2342
+ try {
2343
+ if (verificationTarget.kind === "email") {
2344
+ await loginWithEmailCode({ code: trimmedCode });
2345
+ } else {
2346
+ await loginWithSmsCode({ code: trimmedCode });
2347
+ }
2348
+ } catch (err) {
2349
+ const msg = err instanceof Error ? err.message : "Failed to verify code";
2350
+ setError(msg);
2351
+ }
2352
+ }, [verificationTarget, otpCode, loginWithEmailCode, loginWithSmsCode]);
2353
+ const handleResendLoginCode = useCallback(async () => {
2354
+ if (!verificationTarget) return;
2355
+ setError(null);
2356
+ try {
2357
+ if (verificationTarget.kind === "email") {
2358
+ await sendEmailCode({ email: verificationTarget.value });
2359
+ } else {
2360
+ await sendSmsCode({ phoneNumber: verificationTarget.value });
2361
+ }
2362
+ } catch (err) {
2363
+ const msg = err instanceof Error ? err.message : "Failed to resend code";
2364
+ setError(msg);
2365
+ }
2366
+ }, [verificationTarget, sendEmailCode, sendSmsCode]);
2367
+ const handleEditIdentifier = useCallback(() => {
2368
+ setError(null);
2369
+ setVerificationTarget(null);
2370
+ setOtpCode("");
2371
+ }, []);
2251
2372
  useEffect(() => {
2252
2373
  if (!ready || !authenticated || step !== "login") return;
2253
2374
  let cancelled = false;
2375
+ setError(null);
2376
+ resetHeadlessLogin();
2254
2377
  const checkPasskey = async () => {
2255
2378
  try {
2256
2379
  const token = await getAccessToken();
@@ -2299,7 +2422,16 @@ function SwypePayment({
2299
2422
  return () => {
2300
2423
  cancelled = true;
2301
2424
  };
2302
- }, [ready, authenticated, step, depositAmount, apiBaseUrl, getAccessToken, activeCredentialId]);
2425
+ }, [
2426
+ ready,
2427
+ authenticated,
2428
+ step,
2429
+ depositAmount,
2430
+ apiBaseUrl,
2431
+ getAccessToken,
2432
+ activeCredentialId,
2433
+ resetHeadlessLogin
2434
+ ]);
2303
2435
  const loadingDataRef = useRef(false);
2304
2436
  useEffect(() => {
2305
2437
  if (!authenticated) return;
@@ -2519,6 +2651,7 @@ function SwypePayment({
2519
2651
  const t = await createTransfer(apiBaseUrl, token, {
2520
2652
  id: idempotencyKey,
2521
2653
  credentialId: activeCredentialId,
2654
+ merchantAuthorization,
2522
2655
  sourceType: effectiveSourceType,
2523
2656
  sourceId: effectiveSourceId,
2524
2657
  destination,
@@ -2526,8 +2659,11 @@ function SwypePayment({
2526
2659
  });
2527
2660
  setTransfer(t);
2528
2661
  if (t.authorizationSessions && t.authorizationSessions.length > 0) {
2529
- const shouldUseWalletConnector = useWalletConnector ?? !isMobile();
2530
- if (!shouldUseWalletConnector) {
2662
+ const shouldUseConnector = shouldUseWalletConnector({
2663
+ useWalletConnector,
2664
+ userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
2665
+ });
2666
+ if (!shouldUseConnector) {
2531
2667
  setMobileFlow(true);
2532
2668
  pollingTransferIdRef.current = t.id;
2533
2669
  polling.startPolling(t.id);
@@ -2608,7 +2744,8 @@ function SwypePayment({
2608
2744
  processingStartedAtRef.current = null;
2609
2745
  pollingTransferIdRef.current = null;
2610
2746
  mobileSigningTransferIdRef.current = null;
2611
- }, [logout, polling, depositAmount]);
2747
+ resetHeadlessLogin();
2748
+ }, [logout, polling, depositAmount, resetHeadlessLogin]);
2612
2749
  const handleConnectNewAccount = (providerId) => {
2613
2750
  setSelectedProviderId(providerId);
2614
2751
  setSelectedAccountId(null);
@@ -2645,7 +2782,7 @@ function SwypePayment({
2645
2782
  cursor: "pointer",
2646
2783
  transition: "filter 0.15s ease, transform 0.15s ease",
2647
2784
  fontFamily: "inherit",
2648
- boxShadow: "0 8px 18px rgba(46, 182, 194, 0.28)"
2785
+ boxShadow: "0 8px 18px rgba(40, 182, 122, 0.28)"
2649
2786
  };
2650
2787
  const btnDisabled = {
2651
2788
  ...btnPrimary,
@@ -2657,6 +2794,33 @@ function SwypePayment({
2657
2794
  background: tokens.bgCard,
2658
2795
  color: tokens.textSecondary,
2659
2796
  border: `1px solid ${tokens.border}`});
2797
+ const textFieldStyle = {
2798
+ width: "100%",
2799
+ padding: "15px 16px",
2800
+ borderRadius: "16px",
2801
+ border: `1px solid ${tokens.border}`,
2802
+ background: tokens.bgInput,
2803
+ color: tokens.text,
2804
+ fontSize: "0.98rem",
2805
+ fontFamily: "inherit",
2806
+ outline: "none",
2807
+ boxSizing: "border-box"
2808
+ };
2809
+ const authCaptionStyle = {
2810
+ fontSize: "0.84rem",
2811
+ color: tokens.textSecondary,
2812
+ margin: 0,
2813
+ lineHeight: 1.5
2814
+ };
2815
+ const authTertiaryButtonStyle = {
2816
+ background: "transparent",
2817
+ border: "none",
2818
+ color: tokens.textMuted,
2819
+ cursor: "pointer",
2820
+ fontFamily: "inherit",
2821
+ fontSize: "0.84rem",
2822
+ padding: 0
2823
+ };
2660
2824
  const errorStyle = {
2661
2825
  background: tokens.errorBg,
2662
2826
  border: `1px solid ${tokens.error}66`,
@@ -2717,6 +2881,7 @@ function SwypePayment({
2717
2881
  ]
2718
2882
  }
2719
2883
  );
2884
+ const placeholderProviders = ["A", "B", "C", "D", "E"];
2720
2885
  const displayedSelectSourceChoices = selectSourceChoices.length > 0 ? selectSourceChoices : [
2721
2886
  {
2722
2887
  chainName: "Base",
@@ -2752,43 +2917,186 @@ function SwypePayment({
2752
2917
  return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "24px 0" }, children: /* @__PURE__ */ jsx(Spinner, { label: "Initializing..." }) }) });
2753
2918
  }
2754
2919
  if (step === "login" && !authenticated) {
2920
+ const isAwaitingOtp = verificationTarget !== null;
2921
+ const isSendingCode = activeOtpStatus === "sending-code";
2922
+ const isSubmittingCode = activeOtpStatus === "submitting-code";
2923
+ const continueDisabled = authInput.trim().length === 0 || isSendingCode || isSubmittingCode;
2924
+ const verifyDisabled = otpCode.trim().length !== 6 || isSubmittingCode;
2755
2925
  return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
2756
- /* @__PURE__ */ jsxs(
2757
- "svg",
2926
+ /* @__PURE__ */ jsx(
2927
+ "div",
2758
2928
  {
2759
- width: "48",
2760
- height: "48",
2761
- viewBox: "0 0 48 48",
2762
- fill: "none",
2763
- style: { margin: "0 auto 16px" },
2764
- children: [
2765
- /* @__PURE__ */ jsx("rect", { width: "48", height: "48", rx: "12", fill: tokens.accent + "20" }),
2766
- /* @__PURE__ */ jsx(
2767
- "path",
2768
- {
2769
- d: "M24 14v20M14 24h20",
2770
- stroke: tokens.accent,
2771
- strokeWidth: "2.5",
2772
- strokeLinecap: "round"
2773
- }
2774
- )
2775
- ]
2929
+ style: {
2930
+ width: 56,
2931
+ height: 56,
2932
+ borderRadius: 14,
2933
+ background: tokens.accent,
2934
+ color: tokens.accentText,
2935
+ display: "flex",
2936
+ alignItems: "center",
2937
+ justifyContent: "center",
2938
+ fontWeight: 700,
2939
+ fontSize: "1.35rem",
2940
+ margin: "0 auto 24px",
2941
+ boxShadow: "0 10px 20px rgba(40, 182, 122, 0.22)"
2942
+ },
2943
+ children: "S"
2944
+ }
2945
+ ),
2946
+ /* @__PURE__ */ jsx(
2947
+ "h2",
2948
+ {
2949
+ style: {
2950
+ ...headingStyle,
2951
+ fontSize: "2.05rem",
2952
+ lineHeight: 1.15,
2953
+ marginBottom: "10px",
2954
+ whiteSpace: "pre-line"
2955
+ },
2956
+ children: isAwaitingOtp ? "Enter your code." : "One-time setup.\nOne-tap deposits after."
2776
2957
  }
2777
2958
  ),
2778
- /* @__PURE__ */ jsx("h2", { style: { ...headingStyle, marginBottom: "8px" }, children: "Pay with Swype" }),
2779
2959
  /* @__PURE__ */ jsx(
2780
2960
  "p",
2781
2961
  {
2782
2962
  style: {
2783
- fontSize: "0.875rem",
2784
- color: tokens.textSecondary,
2785
- margin: "0 0 24px 0",
2786
- lineHeight: 1.5
2963
+ ...authCaptionStyle,
2964
+ margin: "0 0 26px 0",
2965
+ whiteSpace: "pre-line"
2787
2966
  },
2788
- children: "Connect your account to continue"
2967
+ children: isAwaitingOtp ? `We sent a 6-digit code to ${maskAuthIdentifier(verificationTarget)}.` : "Protected by Face ID."
2789
2968
  }
2790
2969
  ),
2791
- /* @__PURE__ */ jsx("button", { style: btnPrimary, onClick: login, children: "Connect to Swype" })
2970
+ error && /* @__PURE__ */ jsx("div", { style: errorStyle, children: error }),
2971
+ isAwaitingOtp ? /* @__PURE__ */ jsxs(Fragment, { children: [
2972
+ /* @__PURE__ */ jsx(
2973
+ "input",
2974
+ {
2975
+ id: "swype-login-code",
2976
+ type: "text",
2977
+ inputMode: "numeric",
2978
+ autoComplete: "one-time-code",
2979
+ placeholder: "Verification code",
2980
+ value: otpCode,
2981
+ onChange: (event) => {
2982
+ setOtpCode(event.target.value.replace(/\D/g, "").slice(0, 6));
2983
+ },
2984
+ style: {
2985
+ ...textFieldStyle,
2986
+ textAlign: "center",
2987
+ letterSpacing: "0.24em",
2988
+ marginBottom: "14px"
2989
+ }
2990
+ }
2991
+ ),
2992
+ /* @__PURE__ */ jsx(
2993
+ "button",
2994
+ {
2995
+ style: verifyDisabled ? btnDisabled : btnPrimary,
2996
+ disabled: verifyDisabled,
2997
+ onClick: handleVerifyLoginCode,
2998
+ children: isSubmittingCode ? "Verifying..." : "Continue"
2999
+ }
3000
+ ),
3001
+ /* @__PURE__ */ jsxs(
3002
+ "div",
3003
+ {
3004
+ style: {
3005
+ display: "flex",
3006
+ justifyContent: "space-between",
3007
+ gap: "12px",
3008
+ marginTop: "14px"
3009
+ },
3010
+ children: [
3011
+ /* @__PURE__ */ jsx("button", { type: "button", style: authTertiaryButtonStyle, onClick: handleEditIdentifier, children: "Use a different email or phone" }),
3012
+ /* @__PURE__ */ jsx(
3013
+ "button",
3014
+ {
3015
+ type: "button",
3016
+ style: authTertiaryButtonStyle,
3017
+ onClick: handleResendLoginCode,
3018
+ disabled: isSendingCode || isSubmittingCode,
3019
+ children: isSendingCode ? "Sending..." : "Resend code"
3020
+ }
3021
+ )
3022
+ ]
3023
+ }
3024
+ )
3025
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3026
+ /* @__PURE__ */ jsx(
3027
+ "input",
3028
+ {
3029
+ id: "swype-login-identifier",
3030
+ type: "text",
3031
+ inputMode: "text",
3032
+ autoComplete: "username",
3033
+ placeholder: "Email or phone number",
3034
+ value: authInput,
3035
+ onChange: (event) => setAuthInput(event.target.value),
3036
+ style: { ...textFieldStyle, marginBottom: "14px" }
3037
+ }
3038
+ ),
3039
+ /* @__PURE__ */ jsx(
3040
+ "button",
3041
+ {
3042
+ style: continueDisabled ? btnDisabled : btnPrimary,
3043
+ disabled: continueDisabled,
3044
+ onClick: handleSendLoginCode,
3045
+ children: isSendingCode ? "Sending code..." : "Continue"
3046
+ }
3047
+ ),
3048
+ /* @__PURE__ */ jsxs(
3049
+ "div",
3050
+ {
3051
+ style: {
3052
+ display: "flex",
3053
+ alignItems: "center",
3054
+ gap: "10px",
3055
+ margin: "22px 0 14px",
3056
+ color: tokens.textMuted,
3057
+ fontSize: "0.82rem"
3058
+ },
3059
+ children: [
3060
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, height: 1, background: tokens.border } }),
3061
+ /* @__PURE__ */ jsx("span", { children: "works with" }),
3062
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, height: 1, background: tokens.border } })
3063
+ ]
3064
+ }
3065
+ ),
3066
+ /* @__PURE__ */ jsx(
3067
+ "div",
3068
+ {
3069
+ "aria-label": "Works with placeholder providers",
3070
+ style: {
3071
+ display: "flex",
3072
+ justifyContent: "center",
3073
+ gap: "12px",
3074
+ marginBottom: "18px"
3075
+ },
3076
+ children: placeholderProviders.map((providerLabel) => /* @__PURE__ */ jsx(
3077
+ "div",
3078
+ {
3079
+ style: {
3080
+ width: 34,
3081
+ height: 34,
3082
+ borderRadius: 999,
3083
+ border: `1px solid ${tokens.border}`,
3084
+ background: tokens.bgInput,
3085
+ color: tokens.textMuted,
3086
+ display: "flex",
3087
+ alignItems: "center",
3088
+ justifyContent: "center",
3089
+ fontSize: "0.78rem",
3090
+ fontWeight: 600
3091
+ },
3092
+ children: providerLabel
3093
+ },
3094
+ providerLabel
3095
+ ))
3096
+ }
3097
+ ),
3098
+ /* @__PURE__ */ jsx("p", { style: { ...authCaptionStyle, color: tokens.textMuted }, children: "Powered by Swype. Non-custodial." })
3099
+ ] })
2792
3100
  ] }) });
2793
3101
  }
2794
3102
  if (step === "register-passkey") {