@swype-org/react-sdk 0.1.28 → 0.1.29

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) {
@@ -2203,10 +2232,21 @@ function SwypePayment({
2203
2232
  onComplete,
2204
2233
  onError,
2205
2234
  useWalletConnector,
2206
- idempotencyKey
2235
+ idempotencyKey,
2236
+ merchantAuthorization
2207
2237
  }) {
2208
2238
  const { apiBaseUrl, tokens, depositAmount } = useSwypeConfig();
2209
- const { ready, authenticated, user, login, logout, getAccessToken } = usePrivy();
2239
+ const { ready, authenticated, user, logout, getAccessToken } = usePrivy();
2240
+ const {
2241
+ sendCode: sendEmailCode,
2242
+ loginWithCode: loginWithEmailCode,
2243
+ state: emailLoginState
2244
+ } = useLoginWithEmail();
2245
+ const {
2246
+ sendCode: sendSmsCode,
2247
+ loginWithCode: loginWithSmsCode,
2248
+ state: smsLoginState
2249
+ } = useLoginWithSms();
2210
2250
  const [step, setStep] = useState("login");
2211
2251
  const [error, setError] = useState(null);
2212
2252
  const [providers, setProviders] = useState([]);
@@ -2231,6 +2271,11 @@ function SwypePayment({
2231
2271
  if (typeof window === "undefined") return null;
2232
2272
  return window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY);
2233
2273
  });
2274
+ const [authInput, setAuthInput] = useState("");
2275
+ const [verificationTarget, setVerificationTarget] = useState(
2276
+ null
2277
+ );
2278
+ const [otpCode, setOtpCode] = useState("");
2234
2279
  const [mobileFlow, setMobileFlow] = useState(false);
2235
2280
  const pollingTransferIdRef = useRef(null);
2236
2281
  const mobileSigningTransferIdRef = useRef(null);
@@ -2248,9 +2293,81 @@ function SwypePayment({
2248
2293
  setAmount(depositAmount.toString());
2249
2294
  }
2250
2295
  }, [depositAmount]);
2296
+ const resetHeadlessLogin = useCallback(() => {
2297
+ setAuthInput("");
2298
+ setVerificationTarget(null);
2299
+ setOtpCode("");
2300
+ }, []);
2301
+ const activeOtpStatus = verificationTarget?.kind === "email" ? emailLoginState.status : verificationTarget?.kind === "phone" ? smsLoginState.status : "initial";
2302
+ 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;
2303
+ useEffect(() => {
2304
+ if (activeOtpErrorMessage) {
2305
+ setError(activeOtpErrorMessage);
2306
+ }
2307
+ }, [activeOtpErrorMessage]);
2308
+ const handleSendLoginCode = useCallback(async () => {
2309
+ const normalizedIdentifier = normalizeAuthIdentifier(authInput);
2310
+ if (!normalizedIdentifier) {
2311
+ setError("Enter a valid email address or phone number.");
2312
+ return;
2313
+ }
2314
+ setError(null);
2315
+ setOtpCode("");
2316
+ try {
2317
+ if (normalizedIdentifier.kind === "email") {
2318
+ await sendEmailCode({ email: normalizedIdentifier.value });
2319
+ } else {
2320
+ await sendSmsCode({ phoneNumber: normalizedIdentifier.value });
2321
+ }
2322
+ setVerificationTarget(normalizedIdentifier);
2323
+ } catch (err) {
2324
+ const msg = err instanceof Error ? err.message : "Failed to send verification code";
2325
+ setError(msg);
2326
+ }
2327
+ }, [authInput, sendEmailCode, sendSmsCode]);
2328
+ const handleVerifyLoginCode = useCallback(async () => {
2329
+ if (!verificationTarget) return;
2330
+ const trimmedCode = otpCode.trim();
2331
+ if (!/^\d{6}$/.test(trimmedCode)) {
2332
+ setError("Enter the 6-digit verification code.");
2333
+ return;
2334
+ }
2335
+ setError(null);
2336
+ try {
2337
+ if (verificationTarget.kind === "email") {
2338
+ await loginWithEmailCode({ code: trimmedCode });
2339
+ } else {
2340
+ await loginWithSmsCode({ code: trimmedCode });
2341
+ }
2342
+ } catch (err) {
2343
+ const msg = err instanceof Error ? err.message : "Failed to verify code";
2344
+ setError(msg);
2345
+ }
2346
+ }, [verificationTarget, otpCode, loginWithEmailCode, loginWithSmsCode]);
2347
+ const handleResendLoginCode = useCallback(async () => {
2348
+ if (!verificationTarget) return;
2349
+ setError(null);
2350
+ try {
2351
+ if (verificationTarget.kind === "email") {
2352
+ await sendEmailCode({ email: verificationTarget.value });
2353
+ } else {
2354
+ await sendSmsCode({ phoneNumber: verificationTarget.value });
2355
+ }
2356
+ } catch (err) {
2357
+ const msg = err instanceof Error ? err.message : "Failed to resend code";
2358
+ setError(msg);
2359
+ }
2360
+ }, [verificationTarget, sendEmailCode, sendSmsCode]);
2361
+ const handleEditIdentifier = useCallback(() => {
2362
+ setError(null);
2363
+ setVerificationTarget(null);
2364
+ setOtpCode("");
2365
+ }, []);
2251
2366
  useEffect(() => {
2252
2367
  if (!ready || !authenticated || step !== "login") return;
2253
2368
  let cancelled = false;
2369
+ setError(null);
2370
+ resetHeadlessLogin();
2254
2371
  const checkPasskey = async () => {
2255
2372
  try {
2256
2373
  const token = await getAccessToken();
@@ -2299,7 +2416,16 @@ function SwypePayment({
2299
2416
  return () => {
2300
2417
  cancelled = true;
2301
2418
  };
2302
- }, [ready, authenticated, step, depositAmount, apiBaseUrl, getAccessToken, activeCredentialId]);
2419
+ }, [
2420
+ ready,
2421
+ authenticated,
2422
+ step,
2423
+ depositAmount,
2424
+ apiBaseUrl,
2425
+ getAccessToken,
2426
+ activeCredentialId,
2427
+ resetHeadlessLogin
2428
+ ]);
2303
2429
  const loadingDataRef = useRef(false);
2304
2430
  useEffect(() => {
2305
2431
  if (!authenticated) return;
@@ -2519,6 +2645,7 @@ function SwypePayment({
2519
2645
  const t = await createTransfer(apiBaseUrl, token, {
2520
2646
  id: idempotencyKey,
2521
2647
  credentialId: activeCredentialId,
2648
+ merchantAuthorization,
2522
2649
  sourceType: effectiveSourceType,
2523
2650
  sourceId: effectiveSourceId,
2524
2651
  destination,
@@ -2608,7 +2735,8 @@ function SwypePayment({
2608
2735
  processingStartedAtRef.current = null;
2609
2736
  pollingTransferIdRef.current = null;
2610
2737
  mobileSigningTransferIdRef.current = null;
2611
- }, [logout, polling, depositAmount]);
2738
+ resetHeadlessLogin();
2739
+ }, [logout, polling, depositAmount, resetHeadlessLogin]);
2612
2740
  const handleConnectNewAccount = (providerId) => {
2613
2741
  setSelectedProviderId(providerId);
2614
2742
  setSelectedAccountId(null);
@@ -2645,7 +2773,7 @@ function SwypePayment({
2645
2773
  cursor: "pointer",
2646
2774
  transition: "filter 0.15s ease, transform 0.15s ease",
2647
2775
  fontFamily: "inherit",
2648
- boxShadow: "0 8px 18px rgba(46, 182, 194, 0.28)"
2776
+ boxShadow: "0 8px 18px rgba(40, 182, 122, 0.28)"
2649
2777
  };
2650
2778
  const btnDisabled = {
2651
2779
  ...btnPrimary,
@@ -2657,6 +2785,33 @@ function SwypePayment({
2657
2785
  background: tokens.bgCard,
2658
2786
  color: tokens.textSecondary,
2659
2787
  border: `1px solid ${tokens.border}`});
2788
+ const textFieldStyle = {
2789
+ width: "100%",
2790
+ padding: "15px 16px",
2791
+ borderRadius: "16px",
2792
+ border: `1px solid ${tokens.border}`,
2793
+ background: tokens.bgInput,
2794
+ color: tokens.text,
2795
+ fontSize: "0.98rem",
2796
+ fontFamily: "inherit",
2797
+ outline: "none",
2798
+ boxSizing: "border-box"
2799
+ };
2800
+ const authCaptionStyle = {
2801
+ fontSize: "0.84rem",
2802
+ color: tokens.textSecondary,
2803
+ margin: 0,
2804
+ lineHeight: 1.5
2805
+ };
2806
+ const authTertiaryButtonStyle = {
2807
+ background: "transparent",
2808
+ border: "none",
2809
+ color: tokens.textMuted,
2810
+ cursor: "pointer",
2811
+ fontFamily: "inherit",
2812
+ fontSize: "0.84rem",
2813
+ padding: 0
2814
+ };
2660
2815
  const errorStyle = {
2661
2816
  background: tokens.errorBg,
2662
2817
  border: `1px solid ${tokens.error}66`,
@@ -2717,6 +2872,7 @@ function SwypePayment({
2717
2872
  ]
2718
2873
  }
2719
2874
  );
2875
+ const placeholderProviders = ["A", "B", "C", "D", "E"];
2720
2876
  const displayedSelectSourceChoices = selectSourceChoices.length > 0 ? selectSourceChoices : [
2721
2877
  {
2722
2878
  chainName: "Base",
@@ -2752,43 +2908,186 @@ function SwypePayment({
2752
2908
  return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "24px 0" }, children: /* @__PURE__ */ jsx(Spinner, { label: "Initializing..." }) }) });
2753
2909
  }
2754
2910
  if (step === "login" && !authenticated) {
2911
+ const isAwaitingOtp = verificationTarget !== null;
2912
+ const isSendingCode = activeOtpStatus === "sending-code";
2913
+ const isSubmittingCode = activeOtpStatus === "submitting-code";
2914
+ const continueDisabled = authInput.trim().length === 0 || isSendingCode || isSubmittingCode;
2915
+ const verifyDisabled = otpCode.trim().length !== 6 || isSubmittingCode;
2755
2916
  return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
2756
- /* @__PURE__ */ jsxs(
2757
- "svg",
2917
+ /* @__PURE__ */ jsx(
2918
+ "div",
2758
2919
  {
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
- ]
2920
+ style: {
2921
+ width: 56,
2922
+ height: 56,
2923
+ borderRadius: 14,
2924
+ background: tokens.accent,
2925
+ color: tokens.accentText,
2926
+ display: "flex",
2927
+ alignItems: "center",
2928
+ justifyContent: "center",
2929
+ fontWeight: 700,
2930
+ fontSize: "1.35rem",
2931
+ margin: "0 auto 24px",
2932
+ boxShadow: "0 10px 20px rgba(40, 182, 122, 0.22)"
2933
+ },
2934
+ children: "S"
2935
+ }
2936
+ ),
2937
+ /* @__PURE__ */ jsx(
2938
+ "h2",
2939
+ {
2940
+ style: {
2941
+ ...headingStyle,
2942
+ fontSize: "2.05rem",
2943
+ lineHeight: 1.15,
2944
+ marginBottom: "10px",
2945
+ whiteSpace: "pre-line"
2946
+ },
2947
+ children: isAwaitingOtp ? "Enter your code." : "One-time setup.\nOne-tap deposits after."
2776
2948
  }
2777
2949
  ),
2778
- /* @__PURE__ */ jsx("h2", { style: { ...headingStyle, marginBottom: "8px" }, children: "Pay with Swype" }),
2779
2950
  /* @__PURE__ */ jsx(
2780
2951
  "p",
2781
2952
  {
2782
2953
  style: {
2783
- fontSize: "0.875rem",
2784
- color: tokens.textSecondary,
2785
- margin: "0 0 24px 0",
2786
- lineHeight: 1.5
2954
+ ...authCaptionStyle,
2955
+ margin: "0 0 26px 0",
2956
+ whiteSpace: "pre-line"
2787
2957
  },
2788
- children: "Connect your account to continue"
2958
+ children: isAwaitingOtp ? `We sent a 6-digit code to ${maskAuthIdentifier(verificationTarget)}.` : "Protected by Face ID."
2789
2959
  }
2790
2960
  ),
2791
- /* @__PURE__ */ jsx("button", { style: btnPrimary, onClick: login, children: "Connect to Swype" })
2961
+ error && /* @__PURE__ */ jsx("div", { style: errorStyle, children: error }),
2962
+ isAwaitingOtp ? /* @__PURE__ */ jsxs(Fragment, { children: [
2963
+ /* @__PURE__ */ jsx(
2964
+ "input",
2965
+ {
2966
+ id: "swype-login-code",
2967
+ type: "text",
2968
+ inputMode: "numeric",
2969
+ autoComplete: "one-time-code",
2970
+ placeholder: "Verification code",
2971
+ value: otpCode,
2972
+ onChange: (event) => {
2973
+ setOtpCode(event.target.value.replace(/\D/g, "").slice(0, 6));
2974
+ },
2975
+ style: {
2976
+ ...textFieldStyle,
2977
+ textAlign: "center",
2978
+ letterSpacing: "0.24em",
2979
+ marginBottom: "14px"
2980
+ }
2981
+ }
2982
+ ),
2983
+ /* @__PURE__ */ jsx(
2984
+ "button",
2985
+ {
2986
+ style: verifyDisabled ? btnDisabled : btnPrimary,
2987
+ disabled: verifyDisabled,
2988
+ onClick: handleVerifyLoginCode,
2989
+ children: isSubmittingCode ? "Verifying..." : "Continue"
2990
+ }
2991
+ ),
2992
+ /* @__PURE__ */ jsxs(
2993
+ "div",
2994
+ {
2995
+ style: {
2996
+ display: "flex",
2997
+ justifyContent: "space-between",
2998
+ gap: "12px",
2999
+ marginTop: "14px"
3000
+ },
3001
+ children: [
3002
+ /* @__PURE__ */ jsx("button", { type: "button", style: authTertiaryButtonStyle, onClick: handleEditIdentifier, children: "Use a different email or phone" }),
3003
+ /* @__PURE__ */ jsx(
3004
+ "button",
3005
+ {
3006
+ type: "button",
3007
+ style: authTertiaryButtonStyle,
3008
+ onClick: handleResendLoginCode,
3009
+ disabled: isSendingCode || isSubmittingCode,
3010
+ children: isSendingCode ? "Sending..." : "Resend code"
3011
+ }
3012
+ )
3013
+ ]
3014
+ }
3015
+ )
3016
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3017
+ /* @__PURE__ */ jsx(
3018
+ "input",
3019
+ {
3020
+ id: "swype-login-identifier",
3021
+ type: "text",
3022
+ inputMode: "text",
3023
+ autoComplete: "username",
3024
+ placeholder: "Email or phone number",
3025
+ value: authInput,
3026
+ onChange: (event) => setAuthInput(event.target.value),
3027
+ style: { ...textFieldStyle, marginBottom: "14px" }
3028
+ }
3029
+ ),
3030
+ /* @__PURE__ */ jsx(
3031
+ "button",
3032
+ {
3033
+ style: continueDisabled ? btnDisabled : btnPrimary,
3034
+ disabled: continueDisabled,
3035
+ onClick: handleSendLoginCode,
3036
+ children: isSendingCode ? "Sending code..." : "Continue"
3037
+ }
3038
+ ),
3039
+ /* @__PURE__ */ jsxs(
3040
+ "div",
3041
+ {
3042
+ style: {
3043
+ display: "flex",
3044
+ alignItems: "center",
3045
+ gap: "10px",
3046
+ margin: "22px 0 14px",
3047
+ color: tokens.textMuted,
3048
+ fontSize: "0.82rem"
3049
+ },
3050
+ children: [
3051
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, height: 1, background: tokens.border } }),
3052
+ /* @__PURE__ */ jsx("span", { children: "works with" }),
3053
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, height: 1, background: tokens.border } })
3054
+ ]
3055
+ }
3056
+ ),
3057
+ /* @__PURE__ */ jsx(
3058
+ "div",
3059
+ {
3060
+ "aria-label": "Works with placeholder providers",
3061
+ style: {
3062
+ display: "flex",
3063
+ justifyContent: "center",
3064
+ gap: "12px",
3065
+ marginBottom: "18px"
3066
+ },
3067
+ children: placeholderProviders.map((providerLabel) => /* @__PURE__ */ jsx(
3068
+ "div",
3069
+ {
3070
+ style: {
3071
+ width: 34,
3072
+ height: 34,
3073
+ borderRadius: 999,
3074
+ border: `1px solid ${tokens.border}`,
3075
+ background: tokens.bgInput,
3076
+ color: tokens.textMuted,
3077
+ display: "flex",
3078
+ alignItems: "center",
3079
+ justifyContent: "center",
3080
+ fontSize: "0.78rem",
3081
+ fontWeight: 600
3082
+ },
3083
+ children: providerLabel
3084
+ },
3085
+ providerLabel
3086
+ ))
3087
+ }
3088
+ ),
3089
+ /* @__PURE__ */ jsx("p", { style: { ...authCaptionStyle, color: tokens.textMuted }, children: "Powered by Swype. Non-custodial." })
3090
+ ] })
2792
3091
  ] }) });
2793
3092
  }
2794
3093
  if (step === "register-passkey") {