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