@flopay/react 1.1.4 → 1.1.6

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.mjs CHANGED
@@ -102,7 +102,7 @@ function FloPayProvider({
102
102
  // src/flopay-checkout.tsx
103
103
  import React7, { useCallback as useCallback2, useEffect as useEffect5, useMemo as useMemo4, useRef as useRef4, useState as useState4 } from "react";
104
104
  import { PaymentAPI as PaymentAPI4 } from "@flopay/js";
105
- import { SDK_VERSION, FloPayError as FloPayError5, resolveBillingApiUrl as resolveBillingApiUrl3, buildCheckoutDisplayData, resolveButtonsLayoutTheme as resolveButtonsLayoutTheme2 } from "@flopay/shared";
105
+ import { SDK_VERSION, FloPayError as FloPayError5, resolveBillingApiUrl as resolveBillingApiUrl3, buildCheckoutDisplayData, resolveButtonsLayoutTheme as resolveButtonsLayoutTheme2, resolveTheme as resolveTheme2 } from "@flopay/shared";
106
106
 
107
107
  // src/card-button-content.tsx
108
108
  import "react";
@@ -1221,7 +1221,7 @@ ${debugLines.join("\n")}`
1221
1221
  }
1222
1222
 
1223
1223
  // src/split-card-form.tsx
1224
- import { FloPayError as FloPayError3 } from "@flopay/shared";
1224
+ import { FloPayError as FloPayError3, resolveTheme } from "@flopay/shared";
1225
1225
  import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1226
1226
  var WALLET_RESUME_KEY = "flopay_wallet_resume";
1227
1227
  var FLOPAY_KEYFRAMES = `
@@ -1246,6 +1246,14 @@ var FLOPAY_KEYFRAMES = `
1246
1246
  }
1247
1247
  `;
1248
1248
  var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT = 44;
1249
+ var BUTTONS_PANEL_HIDDEN_STYLE = {
1250
+ visibility: "hidden",
1251
+ position: "absolute",
1252
+ pointerEvents: "none",
1253
+ width: "100%",
1254
+ height: 0,
1255
+ overflow: "hidden"
1256
+ };
1249
1257
  function getButtonMethodLabel(method) {
1250
1258
  switch (method) {
1251
1259
  case "paypal":
@@ -1721,12 +1729,14 @@ function SplitCardFormInner({
1721
1729
  showApplePay = true,
1722
1730
  showGooglePay = true,
1723
1731
  layout = "default",
1732
+ theme,
1724
1733
  buttonsTheme,
1725
1734
  buttonsStyles: buttonsStylesOverride,
1735
+ appearance: appearanceOverride,
1726
1736
  cardButtonContent,
1727
1737
  cardBackButtonContent,
1728
1738
  cardTitleContent,
1729
- showSecurityFooter = true,
1739
+ showSecurityFooter: _showSecurityFooter,
1730
1740
  onButtonClick,
1731
1741
  onBeforeButtonClick,
1732
1742
  enableAVS: enableAVSProp,
@@ -1801,8 +1811,9 @@ function SplitCardFormInner({
1801
1811
  }, [paypalDirectRetry]);
1802
1812
  const resolvedBillingApiUrl = billingApiUrl || contextBillingUrl;
1803
1813
  const displayError = externalError ?? error;
1814
+ const themeBundle = useMemo3(() => resolveTheme(theme), [theme]);
1804
1815
  const bStyles = useMemo3(() => {
1805
- const base = resolveButtonsLayoutTheme(buttonsTheme);
1816
+ const base = themeBundle?.buttonsLayout ?? resolveButtonsLayoutTheme(buttonsTheme);
1806
1817
  if (!buttonsStylesOverride) return base;
1807
1818
  return {
1808
1819
  ...base,
@@ -1814,7 +1825,8 @@ function SplitCardFormInner({
1814
1825
  submitButton: { ...base.submitButton, ...buttonsStylesOverride.submitButton },
1815
1826
  title: { ...base.title, ...buttonsStylesOverride.title }
1816
1827
  };
1817
- }, [buttonsTheme, buttonsStylesOverride]);
1828
+ }, [themeBundle, buttonsTheme, buttonsStylesOverride]);
1829
+ const appearance = appearanceOverride ?? themeBundle?.appearance;
1818
1830
  const isInlineSessionPatchProcessing = checkout.inlineSessionPatchProcessing ?? false;
1819
1831
  const isSubmitting = (externalProcessing ?? processing) || isInlineSessionPatchProcessing;
1820
1832
  const isSelfContained = !onTokenizedBody;
@@ -2342,17 +2354,24 @@ function SplitCardFormInner({
2342
2354
  return /* @__PURE__ */ jsx6("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." });
2343
2355
  }
2344
2356
  const isButtons = layout === "buttons";
2345
- const resolvedBorder = isButtons ? bStyles.cardInputBorder ?? "#e5e7eb" : "#A4A4FF";
2346
- const cardBg = isButtons ? bStyles.cardFormContainer?.backgroundColor ?? "white" : "#EDEDFF";
2347
- const cardInputBg = isButtons ? bStyles.cardInputBackground ?? "white" : "white";
2357
+ const appearanceVars = appearance?.variables;
2358
+ const SDK_DEFAULT_WHITES = /* @__PURE__ */ new Set(["#FFFFFF", "#ffffff", "#fff", "#FFF", "white"]);
2359
+ const appearanceColorBg = appearanceVars?.colorBackground;
2360
+ const themedWrapperBg = appearanceColorBg && !SDK_DEFAULT_WHITES.has(appearanceColorBg) ? appearanceColorBg : void 0;
2361
+ const resolvedBorder = bStyles.cardInputBorder ?? (isButtons ? "#e5e7eb" : "#A4A4FF");
2362
+ const cardBg = bStyles.cardFormContainer?.backgroundColor ?? themedWrapperBg ?? (isButtons ? "white" : "#EDEDFF");
2363
+ const cardInputBg = bStyles.cardInputBackground ?? appearanceVars?.colorBackground ?? "white";
2348
2364
  const hideBackButtonLabel = isEmptySlotContent(cardBackButtonContent);
2349
2365
  const hideTitle = isEmptySlotContent(cardTitleContent);
2350
- const nameInputOverrides = isButtons ? bStyles.nameInput : void 0;
2351
- const resolvedInputFontSize = bStyles.cardInputFontSize ?? toCssSize(nameInputOverrides?.fontSize) ?? "16px";
2352
- const resolvedInputFontFamily = typeof nameInputOverrides?.fontFamily === "string" ? nameInputOverrides.fontFamily : "Poppins, sans-serif";
2366
+ const nameInputOverrides = bStyles.nameInput;
2367
+ const resolvedInputFontSize = bStyles.cardInputFontSize ?? toCssSize(nameInputOverrides?.fontSize) ?? appearanceVars?.fontSizeBase ?? "16px";
2368
+ const resolvedInputFontFamily = typeof nameInputOverrides?.fontFamily === "string" ? nameInputOverrides.fontFamily : appearanceVars?.fontFamily ?? "Poppins, sans-serif";
2353
2369
  const resolvedInputFontWeight = toCssWeight(nameInputOverrides?.fontWeight) ?? 400;
2354
- const resolvedInputColor = bStyles.cardInputColor ?? (typeof nameInputOverrides?.color === "string" ? nameInputOverrides.color : void 0) ?? "#262833";
2370
+ const resolvedInputColor = bStyles.cardInputColor ?? (typeof nameInputOverrides?.color === "string" ? nameInputOverrides.color : void 0) ?? appearanceVars?.colorText ?? "#262833";
2355
2371
  const resolvedPlaceholderColor = bStyles.cardInputPlaceholderColor ?? "#9ca3af";
2372
+ const resolvedBorderRadius = appearanceVars?.borderRadius ?? "8px";
2373
+ const resolvedPrimaryColor = appearanceVars?.colorPrimary ?? "#4A49FF";
2374
+ const resolvedTitleColor = appearanceVars?.colorText ?? "#262833";
2356
2375
  const sharedInputTypography = {
2357
2376
  fontSize: resolvedInputFontSize,
2358
2377
  fontFamily: resolvedInputFontFamily,
@@ -2382,12 +2401,14 @@ function SplitCardFormInner({
2382
2401
  invalid: { color: "#ef4444" }
2383
2402
  }
2384
2403
  };
2404
+ const containerOverrides = bStyles.cardFormContainer ?? {};
2405
+ const containerPadding = containerOverrides.padding ?? (isButtons ? "0" : "1rem");
2406
+ const containerRadius = containerOverrides.borderRadius ?? resolvedBorderRadius;
2385
2407
  const cardFormBlock = /* @__PURE__ */ jsxs4("div", { style: {
2386
2408
  backgroundColor: cardBg,
2387
- borderRadius: "8px",
2388
- padding: isButtons ? "0" : "1rem",
2389
- ...isButtons ? bStyles.cardFormContainer : {},
2390
- ...isButtons ? { padding: bStyles.cardFormContainer?.padding ?? "0" } : {},
2409
+ borderRadius: containerRadius,
2410
+ ...containerOverrides,
2411
+ padding: containerPadding,
2391
2412
  ...sharedInputPlaceholderVars
2392
2413
  }, children: [
2393
2414
  /* @__PURE__ */ jsx6("style", { children: `
@@ -2451,7 +2472,14 @@ function SplitCardFormInner({
2451
2472
  ...bStyles.title
2452
2473
  }, children: /* @__PURE__ */ jsx6(TitleContentSlot, { content: cardTitleContent }) })
2453
2474
  ] }),
2454
- !isButtons && !hideTitle && /* @__PURE__ */ jsx6("div", { style: { textAlign: "center", fontWeight: 600, fontSize: "1.1rem", padding: "0.5rem 0", color: "#262833" }, children: /* @__PURE__ */ jsx6(TitleContentSlot, { content: cardTitleContent }) }),
2475
+ !isButtons && !hideTitle && /* @__PURE__ */ jsx6("div", { style: {
2476
+ textAlign: "center",
2477
+ fontWeight: 600,
2478
+ fontSize: "1.1rem",
2479
+ padding: "0.5rem 0",
2480
+ color: resolvedTitleColor,
2481
+ ...bStyles.title
2482
+ }, children: /* @__PURE__ */ jsx6(TitleContentSlot, { content: cardTitleContent }) }),
2455
2483
  /* @__PURE__ */ jsx6("div", { style: {
2456
2484
  backgroundColor: cardInputBg,
2457
2485
  border: `1px solid ${resolvedBorder}`,
@@ -2708,7 +2736,7 @@ function SplitCardFormInner({
2708
2736
  display: "flex",
2709
2737
  alignItems: "center",
2710
2738
  gap: "0.5rem",
2711
- ...isButtons && bStyles.errorBanner ? bStyles.errorBanner : {}
2739
+ ...bStyles.errorBanner ? bStyles.errorBanner : {}
2712
2740
  }, children: [
2713
2741
  /* @__PURE__ */ jsx6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx6("path", { d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z", stroke: "#DC2626", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
2714
2742
  displayError
@@ -2723,29 +2751,19 @@ function SplitCardFormInner({
2723
2751
  width: "100%",
2724
2752
  padding: "0.875rem",
2725
2753
  marginTop: "1rem",
2726
- backgroundColor: "#4A49FF",
2754
+ backgroundColor: resolvedPrimaryColor,
2727
2755
  color: "white",
2728
2756
  border: "none",
2729
- borderRadius: "8px",
2730
- fontSize: isButtons && bStyles.submitButtonFontSize ? bStyles.submitButtonFontSize : "1rem",
2757
+ borderRadius: resolvedBorderRadius,
2758
+ fontSize: bStyles.submitButtonFontSize ?? "1rem",
2731
2759
  fontWeight: 600,
2732
2760
  cursor: !formReady || isSubmitting ? "not-allowed" : "pointer",
2733
2761
  opacity: !formReady || isSubmitting ? 0.5 : 1,
2734
- ...isButtons ? bStyles.submitButton : {}
2762
+ ...bStyles.submitButton
2735
2763
  },
2736
2764
  children: isSubmitting ? "PROCESSING..." : submitLabel
2737
2765
  }
2738
- ),
2739
- !isButtons && showSecurityFooter && /* @__PURE__ */ jsx6("div", { style: {
2740
- backgroundColor: "#EFF9F0",
2741
- borderRadius: "8px",
2742
- padding: "0.75rem",
2743
- marginTop: "0.75rem",
2744
- textAlign: "center",
2745
- fontSize: "0.85rem",
2746
- fontWeight: 600,
2747
- color: "#7DAD3A"
2748
- }, children: "Secure Card Checkout" })
2766
+ )
2749
2767
  ] });
2750
2768
  if (layout === "buttons") {
2751
2769
  const isButtonsView = viewState === "buttons" || viewState === "expanding";
@@ -2757,173 +2775,181 @@ function SplitCardFormInner({
2757
2775
  /* @__PURE__ */ jsx6(FloPayKeyframes, {}),
2758
2776
  overlayStatus && /* @__PURE__ */ jsx6(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
2759
2777
  /* @__PURE__ */ jsxs4("div", { style: { display: "grid" }, children: [
2760
- /* @__PURE__ */ jsxs4("div", { style: {
2761
- gridArea: "1 / 1",
2762
- display: "flex",
2763
- flexDirection: "column",
2764
- gap: "0.5rem",
2765
- // When card form is showing (and not transitioning), hide but keep mounted
2766
- ...!isButtonsView && !buttonsAnim ? { visibility: "hidden", position: "absolute", pointerEvents: "none", width: "100%" } : {},
2767
- ...buttonsAnim ? { animation: buttonsAnim, pointerEvents: "none" } : {}
2768
- }, children: [
2769
- debug && showPayPal && /* @__PURE__ */ jsx6(
2770
- "pre",
2771
- {
2772
- "data-testid": "flopay-direct-paypal-gate-debug",
2773
- style: {
2774
- margin: 0,
2775
- padding: "6px 8px",
2776
- background: "#eef2ff",
2777
- border: "1px solid #c7d2fe",
2778
- borderRadius: 6,
2779
- color: "#111827",
2780
- font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
2781
- whiteSpace: "pre-wrap",
2782
- wordBreak: "break-word"
2783
- },
2784
- children: [
2785
- "FloPay/DirectPayPal-debug (parent gate)",
2786
- ` showPayPal=${showPayPal}`,
2787
- ` directPaypalConfigured=${directPaypalConfigured}`,
2788
- ` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
2789
- ` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
2790
- ` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
2791
- ` hasPaypalStripeInstance=${!!paypalStripeInstance}`
2792
- ].join("\n")
2793
- }
2794
- ),
2795
- shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ jsxs4(Fragment2, { children: [
2796
- paypalDirectRetry && /* @__PURE__ */ jsx6(
2797
- "div",
2798
- {
2799
- "data-testid": "flopay-paypal-direct-retry-notice",
2800
- style: {
2801
- padding: "8px 10px",
2802
- background: "#fef3c7",
2803
- border: "1px solid #fcd34d",
2804
- borderRadius: 6,
2805
- color: "#78350f",
2806
- fontSize: 13,
2807
- lineHeight: 1.4
2808
- },
2809
- children: "Please confirm your PayPal payment to complete checkout."
2810
- }
2811
- ),
2812
- /* @__PURE__ */ jsx6(
2813
- DirectPayPalButton,
2814
- {
2815
- sessionId,
2816
- billingApiUrl: resolvedBillingApiUrl,
2817
- email: resolvedAccount.email,
2818
- clientId: directPaypal.clientId,
2819
- environment: directPaypal.environment,
2820
- currency: currency.toUpperCase(),
2821
- isSubscription,
2822
- onTokenizedBody: dispatchTokenizedBody,
2823
- onComplete,
2824
- onErrorChange: updateError,
2825
- onDecline,
2826
- onButtonClick,
2827
- runBeforeButtonClick,
2828
- isProcessing: isSubmitting,
2829
- onLoadStateChange: setDirectPaypalReady,
2830
- session: session ?? null,
2831
- existingOrderId: paypalDirectRetry?.orderId,
2832
- debug
2833
- },
2834
- paypalDirectRetry?.orderId ?? "fresh"
2835
- )
2836
- ] }),
2837
- shouldRenderStripePayPal && /* @__PURE__ */ jsx6(StripeElements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx6(
2838
- PayPalButtonInner,
2839
- {
2840
- sessionId,
2841
- email: resolvedAccount.email,
2842
- billingApiUrl: resolvedBillingApiUrl,
2843
- onTokenizedBody: dispatchTokenizedBody,
2844
- onErrorChange: updateError,
2845
- isProcessing: isSubmitting,
2846
- onButtonClick,
2847
- onDecline,
2848
- runBeforeButtonClick,
2849
- onLoadStateChange: setPaypalLoadState
2850
- }
2851
- ) }),
2852
- shouldRenderWallets ? /* @__PURE__ */ jsx6(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx6(
2853
- WalletButtonInner,
2854
- {
2855
- sessionId,
2856
- email: resolvedAccount.email,
2857
- billingApiUrl: resolvedBillingApiUrl,
2858
- showApplePay,
2859
- showGooglePay,
2860
- onTokenizedBody: dispatchTokenizedBody,
2861
- onErrorChange: updateError,
2862
- onButtonClick,
2863
- onDecline,
2864
- runBeforeButtonClick,
2865
- onLoadStateChange: setWalletLoadState
2866
- }
2867
- ) }) : shouldShowWallets ? /* @__PURE__ */ jsx6("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
2868
- /* @__PURE__ */ jsx6(
2869
- "button",
2870
- {
2871
- type: "button",
2872
- onClick: async () => {
2873
- if (isSubmitting) return;
2874
- const beforeClick = await runBeforeButtonClick("card");
2875
- if (!beforeClick.proceed) return;
2876
- onButtonClick?.("card");
2877
- expandToCard();
2878
- },
2879
- disabled: isSubmitting,
2880
- style: {
2881
- width: "100%",
2882
- ...cardButtonSizing,
2883
- backgroundColor: "white",
2884
- color: "#262833",
2885
- border: "1px solid #d1d5db",
2778
+ /* @__PURE__ */ jsxs4(
2779
+ "div",
2780
+ {
2781
+ "data-testid": "flopay-buttons-panel",
2782
+ "aria-hidden": !isButtonsView && !buttonsAnim ? true : void 0,
2783
+ style: {
2784
+ gridArea: "1 / 1",
2785
+ display: "flex",
2786
+ flexDirection: "column",
2787
+ gap: "0.5rem",
2788
+ // When card form is showing (and not transitioning), hide but keep mounted.
2789
+ ...!isButtonsView && !buttonsAnim ? BUTTONS_PANEL_HIDDEN_STYLE : {},
2790
+ ...buttonsAnim ? { animation: buttonsAnim, pointerEvents: "none" } : {}
2791
+ },
2792
+ children: [
2793
+ debug && showPayPal && /* @__PURE__ */ jsx6(
2794
+ "pre",
2795
+ {
2796
+ "data-testid": "flopay-direct-paypal-gate-debug",
2797
+ style: {
2798
+ margin: 0,
2799
+ padding: "6px 8px",
2800
+ background: "#eef2ff",
2801
+ border: "1px solid #c7d2fe",
2802
+ borderRadius: 6,
2803
+ color: "#111827",
2804
+ font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
2805
+ whiteSpace: "pre-wrap",
2806
+ wordBreak: "break-word"
2807
+ },
2808
+ children: [
2809
+ "FloPay/DirectPayPal-debug (parent gate)",
2810
+ ` showPayPal=${showPayPal}`,
2811
+ ` directPaypalConfigured=${directPaypalConfigured}`,
2812
+ ` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
2813
+ ` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
2814
+ ` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
2815
+ ` hasPaypalStripeInstance=${!!paypalStripeInstance}`
2816
+ ].join("\n")
2817
+ }
2818
+ ),
2819
+ shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ jsxs4(Fragment2, { children: [
2820
+ paypalDirectRetry && /* @__PURE__ */ jsx6(
2821
+ "div",
2822
+ {
2823
+ "data-testid": "flopay-paypal-direct-retry-notice",
2824
+ style: {
2825
+ padding: "8px 10px",
2826
+ background: "#fef3c7",
2827
+ border: "1px solid #fcd34d",
2828
+ borderRadius: 6,
2829
+ color: "#78350f",
2830
+ fontSize: 13,
2831
+ lineHeight: 1.4
2832
+ },
2833
+ children: "Please confirm your PayPal payment to complete checkout."
2834
+ }
2835
+ ),
2836
+ /* @__PURE__ */ jsx6(
2837
+ DirectPayPalButton,
2838
+ {
2839
+ sessionId,
2840
+ billingApiUrl: resolvedBillingApiUrl,
2841
+ email: resolvedAccount.email,
2842
+ clientId: directPaypal.clientId,
2843
+ environment: directPaypal.environment,
2844
+ currency: currency.toUpperCase(),
2845
+ isSubscription,
2846
+ onTokenizedBody: dispatchTokenizedBody,
2847
+ onComplete,
2848
+ onErrorChange: updateError,
2849
+ onDecline,
2850
+ onButtonClick,
2851
+ runBeforeButtonClick,
2852
+ isProcessing: isSubmitting,
2853
+ onLoadStateChange: setDirectPaypalReady,
2854
+ session: session ?? null,
2855
+ existingOrderId: paypalDirectRetry?.orderId,
2856
+ debug
2857
+ },
2858
+ paypalDirectRetry?.orderId ?? "fresh"
2859
+ )
2860
+ ] }),
2861
+ shouldRenderStripePayPal && /* @__PURE__ */ jsx6(StripeElements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx6(
2862
+ PayPalButtonInner,
2863
+ {
2864
+ sessionId,
2865
+ email: resolvedAccount.email,
2866
+ billingApiUrl: resolvedBillingApiUrl,
2867
+ onTokenizedBody: dispatchTokenizedBody,
2868
+ onErrorChange: updateError,
2869
+ isProcessing: isSubmitting,
2870
+ onButtonClick,
2871
+ onDecline,
2872
+ runBeforeButtonClick,
2873
+ onLoadStateChange: setPaypalLoadState
2874
+ }
2875
+ ) }),
2876
+ shouldRenderWallets ? /* @__PURE__ */ jsx6(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx6(
2877
+ WalletButtonInner,
2878
+ {
2879
+ sessionId,
2880
+ email: resolvedAccount.email,
2881
+ billingApiUrl: resolvedBillingApiUrl,
2882
+ showApplePay,
2883
+ showGooglePay,
2884
+ onTokenizedBody: dispatchTokenizedBody,
2885
+ onErrorChange: updateError,
2886
+ onButtonClick,
2887
+ onDecline,
2888
+ runBeforeButtonClick,
2889
+ onLoadStateChange: setWalletLoadState
2890
+ }
2891
+ ) }) : shouldShowWallets ? /* @__PURE__ */ jsx6("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
2892
+ /* @__PURE__ */ jsx6(
2893
+ "button",
2894
+ {
2895
+ type: "button",
2896
+ onClick: async () => {
2897
+ if (isSubmitting) return;
2898
+ const beforeClick = await runBeforeButtonClick("card");
2899
+ if (!beforeClick.proceed) return;
2900
+ onButtonClick?.("card");
2901
+ expandToCard();
2902
+ },
2903
+ disabled: isSubmitting,
2904
+ style: {
2905
+ width: "100%",
2906
+ ...cardButtonSizing,
2907
+ backgroundColor: "white",
2908
+ color: "#262833",
2909
+ border: "1px solid #d1d5db",
2910
+ borderRadius: "8px",
2911
+ fontSize: bStyles.cardButtonFontSize ?? "0.95rem",
2912
+ fontWeight: 600,
2913
+ cursor: isSubmitting ? "not-allowed" : "pointer",
2914
+ display: "flex",
2915
+ alignItems: "center",
2916
+ justifyContent: "center",
2917
+ gap: "0.625rem",
2918
+ transition: "border-color 0.2s, box-shadow 0.2s, transform 0.1s",
2919
+ boxShadow: "0 1px 2px rgba(0,0,0,0.04)",
2920
+ position: "relative",
2921
+ opacity: isSubmitting ? 0.6 : 1,
2922
+ ...bStyles.cardButton
2923
+ },
2924
+ onMouseDown: (e) => {
2925
+ e.currentTarget.style.transform = "scale(0.985)";
2926
+ },
2927
+ onMouseUp: (e) => {
2928
+ e.currentTarget.style.transform = "scale(1)";
2929
+ },
2930
+ children: /* @__PURE__ */ jsx6(CardButtonContentSlot, { content: cardButtonContent })
2931
+ }
2932
+ ),
2933
+ displayError && viewState === "buttons" && /* @__PURE__ */ jsxs4("div", { role: "alert", "data-testid": "flopay-error", style: {
2934
+ margin: "0.25rem 0",
2935
+ padding: "0.625rem 0.875rem",
2936
+ background: "#FEF2F2",
2937
+ border: "1px solid #FECACA",
2886
2938
  borderRadius: "8px",
2887
- fontSize: bStyles.cardButtonFontSize ?? "0.95rem",
2939
+ color: "#991B1B",
2940
+ fontSize: "0.85rem",
2888
2941
  fontWeight: 600,
2889
- cursor: isSubmitting ? "not-allowed" : "pointer",
2890
2942
  display: "flex",
2891
2943
  alignItems: "center",
2892
- justifyContent: "center",
2893
- gap: "0.625rem",
2894
- transition: "border-color 0.2s, box-shadow 0.2s, transform 0.1s",
2895
- boxShadow: "0 1px 2px rgba(0,0,0,0.04)",
2896
- position: "relative",
2897
- opacity: isSubmitting ? 0.6 : 1,
2898
- ...bStyles.cardButton
2899
- },
2900
- onMouseDown: (e) => {
2901
- e.currentTarget.style.transform = "scale(0.985)";
2902
- },
2903
- onMouseUp: (e) => {
2904
- e.currentTarget.style.transform = "scale(1)";
2905
- },
2906
- children: /* @__PURE__ */ jsx6(CardButtonContentSlot, { content: cardButtonContent })
2907
- }
2908
- ),
2909
- displayError && viewState === "buttons" && /* @__PURE__ */ jsxs4("div", { role: "alert", "data-testid": "flopay-error", style: {
2910
- margin: "0.25rem 0",
2911
- padding: "0.625rem 0.875rem",
2912
- background: "#FEF2F2",
2913
- border: "1px solid #FECACA",
2914
- borderRadius: "8px",
2915
- color: "#991B1B",
2916
- fontSize: "0.85rem",
2917
- fontWeight: 600,
2918
- display: "flex",
2919
- alignItems: "center",
2920
- gap: "0.5rem",
2921
- ...bStyles.errorBanner ? bStyles.errorBanner : {}
2922
- }, children: [
2923
- /* @__PURE__ */ jsx6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx6("path", { d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z", stroke: "#DC2626", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
2924
- displayError
2925
- ] })
2926
- ] }),
2944
+ gap: "0.5rem",
2945
+ ...bStyles.errorBanner ? bStyles.errorBanner : {}
2946
+ }, children: [
2947
+ /* @__PURE__ */ jsx6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx6("path", { d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z", stroke: "#DC2626", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
2948
+ displayError
2949
+ ] })
2950
+ ]
2951
+ }
2952
+ ),
2927
2953
  isCardView && /* @__PURE__ */ jsx6("div", { style: {
2928
2954
  gridArea: "1 / 1",
2929
2955
  ...cardAnim ? { animation: cardAnim } : {},
@@ -3262,105 +3288,6 @@ async function processSavedPaymentForMode({
3262
3288
  }
3263
3289
  );
3264
3290
  }
3265
- async function processSavedPaymentWithIntent({
3266
- billingApiUrl,
3267
- sessionId,
3268
- session,
3269
- paymentMethodId,
3270
- flopay,
3271
- returnUrl
3272
- }) {
3273
- const customerEmail = session.customer?.email ?? session.accountData?.email ?? "";
3274
- if (!customerEmail) {
3275
- throw Object.assign(
3276
- new FloPayError4("Customer email is required to create a payment intent.", "validation_error", {
3277
- param: "email"
3278
- }),
3279
- { checkoutMethod: "card" }
3280
- );
3281
- }
3282
- const api = new PaymentAPI3(billingApiUrl);
3283
- const intentResponse = await retryOnceOnFetchFailure(() => api.createPaymentIntent(
3284
- sessionId,
3285
- customerEmail,
3286
- paymentMethodId
3287
- ));
3288
- const intentJson = await intentResponse.json().catch(() => null);
3289
- if (!intentResponse.ok) {
3290
- const intentError = buildFloPayApiError(
3291
- intentJson,
3292
- "Failed to create payment intent."
3293
- );
3294
- throw Object.assign(
3295
- intentError,
3296
- { checkoutMethod: "card" }
3297
- );
3298
- }
3299
- const intentClientSecret = getRedirectTokenFromProcessResponse(intentJson, {
3300
- requirePaymentIntentClientSecret: true
3301
- });
3302
- if (!intentClientSecret) {
3303
- throw Object.assign(
3304
- new FloPayError4("No client secret in payment intent response.", "api_error"),
3305
- { checkoutMethod: "card" }
3306
- );
3307
- }
3308
- const confirmResult = await flopay.confirmCardPayment({
3309
- clientSecret: intentClientSecret,
3310
- paymentMethodId
3311
- });
3312
- if (confirmResult.error) {
3313
- throw Object.assign(
3314
- confirmResult.error,
3315
- { checkoutMethod: "card" }
3316
- );
3317
- }
3318
- const rawProvider = typeof flopay.getRawProvider === "function" ? flopay.getRawProvider() : null;
3319
- const confirmedPaymentIntent = await retrievePaymentIntentFromProvider(
3320
- rawProvider,
3321
- intentClientSecret
3322
- );
3323
- const confirmedPaymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
3324
- const confirmedPaymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? paymentMethodId;
3325
- if (!confirmedPaymentIntentId || confirmResult.status !== "succeeded" && confirmResult.status !== "processing" && confirmResult.status !== "requires_capture") {
3326
- throw Object.assign(
3327
- new FloPayError4(
3328
- `Unfortunately, your payment could not be processed. Please try again using a different payment method or contact your bank for assistance. If the issue persists, feel free to reach out to us for support.`,
3329
- "api_error",
3330
- {
3331
- code: confirmResult.status === "requires_action" ? "authentication_required" : void 0
3332
- }
3333
- ),
3334
- { checkoutMethod: "card" }
3335
- );
3336
- }
3337
- const followUp = await processSavedPaymentForMode({
3338
- billingApiUrl,
3339
- sessionId,
3340
- session,
3341
- tokenizedData: {
3342
- id: confirmedPaymentMethodId,
3343
- type: "card",
3344
- threeDSecureActionResultTokenId: confirmedPaymentIntentId
3345
- },
3346
- returnUrl
3347
- });
3348
- const finalResult = followUp.type === "success" ? followUp.result : await handleSavedPaymentRedirectResult(followUp, {
3349
- flopay,
3350
- paypalFlopay: null,
3351
- attempt3DS: true,
3352
- billingApiUrl,
3353
- sessionId,
3354
- session,
3355
- returnUrl
3356
- });
3357
- return {
3358
- ...finalResult,
3359
- paymentIntentId: finalResult.paymentIntentId ?? confirmedPaymentIntentId,
3360
- paymentMethodId: finalResult.paymentMethodId ?? confirmedPaymentMethodId,
3361
- checkoutMethod: finalResult.checkoutMethod ?? "card"
3362
- };
3363
- }
3364
3291
  async function handleSavedPaymentRedirectResult(redirectResult, {
3365
3292
  flopay,
3366
3293
  paypalFlopay,
@@ -3682,7 +3609,7 @@ function FloPayCheckout({
3682
3609
  sessionId: sessionIdProp,
3683
3610
  createSession: createSessionParams,
3684
3611
  billingApiUrl,
3685
- appearance,
3612
+ appearance: appearanceOverride,
3686
3613
  locale,
3687
3614
  loading: loadingNode,
3688
3615
  error: errorNode,
@@ -3697,12 +3624,13 @@ function FloPayCheckout({
3697
3624
  showGooglePay = true,
3698
3625
  debug = false,
3699
3626
  layout,
3627
+ theme,
3700
3628
  buttonsTheme,
3701
3629
  buttonsStyles,
3702
3630
  cardButtonContent,
3703
3631
  cardBackButtonContent,
3704
3632
  cardTitleContent,
3705
- showSecurityFooter = true,
3633
+ showSecurityFooter: _showSecurityFooter,
3706
3634
  onButtonClick,
3707
3635
  onBeforeButtonClick,
3708
3636
  enableAVS,
@@ -3717,6 +3645,8 @@ function FloPayCheckout({
3717
3645
  onSessionCompleted
3718
3646
  }) {
3719
3647
  const resolvedBillingUrl = resolveBillingApiUrl3(billingApiUrl);
3648
+ const themeBundle = useMemo4(() => resolveTheme2(theme), [theme]);
3649
+ const appearance = appearanceOverride ?? themeBundle?.appearance;
3720
3650
  const checkoutType = createSessionParams ? "embedded_checkout" : "standard_checkout";
3721
3651
  const checkoutLayout = children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout";
3722
3652
  const [unified, setUnified] = useState4(null);
@@ -4479,6 +4409,7 @@ function FloPayCheckout({
4479
4409
  showPayPal,
4480
4410
  showApplePay,
4481
4411
  showGooglePay,
4412
+ theme,
4482
4413
  buttonsTheme,
4483
4414
  buttonsStyles,
4484
4415
  cardButtonContent,
@@ -4623,12 +4554,13 @@ function FloPayCheckout({
4623
4554
  showApplePay,
4624
4555
  showGooglePay,
4625
4556
  layout,
4557
+ theme,
4626
4558
  buttonsTheme,
4627
4559
  buttonsStyles,
4560
+ appearance,
4628
4561
  cardButtonContent,
4629
4562
  cardBackButtonContent,
4630
4563
  cardTitleContent,
4631
- showSecurityFooter,
4632
4564
  onButtonClick,
4633
4565
  onBeforeButtonClick,
4634
4566
  enableAVS,
@@ -4685,6 +4617,7 @@ function InterimButtonsView({
4685
4617
  showPayPal,
4686
4618
  showApplePay,
4687
4619
  showGooglePay,
4620
+ theme,
4688
4621
  buttonsTheme,
4689
4622
  buttonsStyles: stylesOverride,
4690
4623
  cardButtonContent,
@@ -4698,8 +4631,9 @@ function InterimButtonsView({
4698
4631
  setShowCardForm(cardOpen);
4699
4632
  }
4700
4633
  }, [cardOpen, isCardOpenControlled]);
4634
+ const themeBundle = useMemo4(() => resolveTheme2(theme), [theme]);
4701
4635
  const bStyles = useMemo4(() => {
4702
- const base = resolveButtonsLayoutTheme2(buttonsTheme);
4636
+ const base = themeBundle?.buttonsLayout ?? resolveButtonsLayoutTheme2(buttonsTheme);
4703
4637
  if (!stylesOverride) return base;
4704
4638
  return {
4705
4639
  ...base,
@@ -4711,7 +4645,7 @@ function InterimButtonsView({
4711
4645
  submitButton: { ...base.submitButton, ...stylesOverride.submitButton },
4712
4646
  title: { ...base.title, ...stylesOverride.title }
4713
4647
  };
4714
- }, [buttonsTheme, stylesOverride]);
4648
+ }, [themeBundle, buttonsTheme, stylesOverride]);
4715
4649
  const skeleton = (h) => /* @__PURE__ */ jsx7("div", { style: {
4716
4650
  height: h,
4717
4651
  borderRadius: 8,
@@ -5407,10 +5341,9 @@ function PayPalButton({
5407
5341
  // src/automatic-payment-button.tsx
5408
5342
  import { useCallback as useCallback5, useEffect as useEffect8, useMemo as useMemo5, useRef as useRef6, useState as useState7 } from "react";
5409
5343
  import { PaymentAPI as PaymentAPI7 } from "@flopay/js";
5410
- import { FloPayError as FloPayError8, resolveBillingApiUrl as resolveBillingApiUrl4, resolveButtonsLayoutTheme as resolveButtonsLayoutTheme3 } from "@flopay/shared";
5344
+ import { FloPayError as FloPayError8, resolveBillingApiUrl as resolveBillingApiUrl4, resolveButtonsLayoutTheme as resolveButtonsLayoutTheme3, resolveTheme as resolveTheme3 } from "@flopay/shared";
5411
5345
  import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
5412
5346
  var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3 = 44;
5413
- var PAYPAL_RESUME_STORAGE_KEY2 = "flopay_automatic_payment_button_resume";
5414
5347
  function sleep2(ms) {
5415
5348
  return new Promise((resolve) => setTimeout(resolve, ms));
5416
5349
  }
@@ -5423,9 +5356,6 @@ function coerceError(err, fallbackMessage) {
5423
5356
  "api_error"
5424
5357
  );
5425
5358
  }
5426
- function canUseStorage2() {
5427
- return typeof window !== "undefined" && typeof window.sessionStorage !== "undefined";
5428
- }
5429
5359
  function shouldShowFallbackCheckout(error, sessionId) {
5430
5360
  if (!sessionId) return false;
5431
5361
  if (error.type === "validation_error") return false;
@@ -5434,47 +5364,6 @@ function shouldShowFallbackCheckout(error, sessionId) {
5434
5364
  }
5435
5365
  return true;
5436
5366
  }
5437
- function readPayPalResumeState2() {
5438
- if (!canUseStorage2()) return null;
5439
- try {
5440
- const raw = window.sessionStorage.getItem(PAYPAL_RESUME_STORAGE_KEY2);
5441
- if (!raw) return null;
5442
- return JSON.parse(raw);
5443
- } catch {
5444
- return null;
5445
- }
5446
- }
5447
- function persistPayPalResumeState2(state) {
5448
- if (!canUseStorage2()) return;
5449
- try {
5450
- window.sessionStorage.setItem(PAYPAL_RESUME_STORAGE_KEY2, JSON.stringify(state));
5451
- } catch (error) {
5452
- console.warn("[FloPayAutomaticPaymentButton] Failed to persist PayPal resume state.", error);
5453
- }
5454
- }
5455
- function clearPayPalResumeState2() {
5456
- if (!canUseStorage2()) return;
5457
- try {
5458
- window.sessionStorage.removeItem(PAYPAL_RESUME_STORAGE_KEY2);
5459
- } catch (error) {
5460
- console.warn("[FloPayAutomaticPaymentButton] Failed to clear PayPal resume state.", error);
5461
- }
5462
- }
5463
- function clearPayPalRedirectParams2() {
5464
- if (typeof window === "undefined") return;
5465
- const url = new URL(window.location.href);
5466
- const keys = ["payment_intent", "payment_intent_client_secret", "redirect_status"];
5467
- let changed = false;
5468
- for (const key of keys) {
5469
- if (url.searchParams.has(key)) {
5470
- url.searchParams.delete(key);
5471
- changed = true;
5472
- }
5473
- }
5474
- if (changed) {
5475
- window.history.replaceState({}, "", url.toString());
5476
- }
5477
- }
5478
5367
  function resolveCreateSessionDraft(props) {
5479
5368
  if (props.createSession) {
5480
5369
  return {
@@ -5501,8 +5390,10 @@ function resolveCreateSessionDraft(props) {
5501
5390
  function FloPayAutomaticPaymentButton({
5502
5391
  sessionId,
5503
5392
  createSession,
5504
- paymentMethodId,
5505
- checkoutMethod,
5393
+ // Deprecated — accepted for back-compat and silently ignored. Backend
5394
+ // resolves the customer's latest payment method server-side.
5395
+ paymentMethodId: _deprecatedPaymentMethodId,
5396
+ checkoutMethod: _deprecatedCheckoutMethod,
5506
5397
  clientId,
5507
5398
  items,
5508
5399
  subscriptions,
@@ -5514,6 +5405,7 @@ function FloPayAutomaticPaymentButton({
5514
5405
  utmMetadata,
5515
5406
  billingApiUrl,
5516
5407
  locale,
5408
+ theme,
5517
5409
  buttonsTheme,
5518
5410
  buttonsStyles: stylesOverride,
5519
5411
  onSuccess,
@@ -5559,20 +5451,7 @@ function FloPayAutomaticPaymentButton({
5559
5451
  const [overlayStatus, setOverlayStatus] = useState7(null);
5560
5452
  const [overlayError, setOverlayError] = useState7(null);
5561
5453
  const [fallbackSession, setFallbackSession] = useState7(null);
5562
- const automaticPaymentToken = useMemo5(
5563
- () => paymentMethodId ? {
5564
- id: paymentMethodId,
5565
- // Saved PayPal `user_payment_method` records are submitted with
5566
- // `type: 'paypal'` so the backend routes the upsell through the
5567
- // direct PayPal gateway's vaulted-token flow. Card and wallet PMs
5568
- // continue to use `type: 'card'`.
5569
- type: checkoutMethod === "paypal" ? "paypal" : "card",
5570
- ...checkoutMethod === "paypal" ? { isPaypal: true } : {}
5571
- } : void 0,
5572
- [checkoutMethod, paymentMethodId]
5573
- );
5574
5454
  const isMountedRef = useRef6(true);
5575
- const resumeAttemptedRef = useRef6(false);
5576
5455
  const fallbackSessionRef = useRef6(fallbackSession);
5577
5456
  const onSuccessRef = useRef6(onSuccess);
5578
5457
  const onErrorRef = useRef6(onError);
@@ -5653,10 +5532,6 @@ function FloPayAutomaticPaymentButton({
5653
5532
  });
5654
5533
  }
5655
5534
  try {
5656
- let paymentResult = null;
5657
- const redirectResult = getRedirectResultFromCheckoutProcessError(apiResult.autoProcessingError);
5658
- const shouldTreatCreateSessionFlowAsServerAutoAttempt = options?.fromCreateSession && (apiResult.autoProcessingAttempted === true || !!apiResult.autoProcessingError || !!redirectResult);
5659
- const shouldRetryPayPalClientSide = checkoutMethod === "paypal" && automaticPaymentToken?.isPaypal === true && options?.fromCreateSession === true;
5660
5535
  if (apiResult.autoProcessingPending) {
5661
5536
  const api = new PaymentAPI7(resolvedBillingUrl);
5662
5537
  const completed = await api.waitForCheckoutSessionCompletion(apiResult.autoProcessingPending.sessionId, {
@@ -5669,50 +5544,14 @@ function FloPayAutomaticPaymentButton({
5669
5544
  });
5670
5545
  }
5671
5546
  await showSuccess({
5672
- result: {
5673
- status: "succeeded",
5674
- paymentMethodId: paymentMethodId ?? void 0,
5675
- checkoutMethod
5676
- },
5547
+ result: { status: "succeeded" },
5677
5548
  session: completedSession,
5678
5549
  sessionId: completedSession.id || resolvedSessionId,
5679
5550
  autoCompleted: false
5680
5551
  });
5681
5552
  return;
5682
5553
  }
5683
- if (redirectResult) {
5684
- const {
5685
- publishableKey,
5686
- paypalPublishableKey
5687
- } = resolveSavedPaymentPublishableKeys(apiResult);
5688
- if (redirectResult.type === "paypal_redirect_required" && publishableKey) {
5689
- persistPayPalResumeState2({
5690
- sessionId: session.id || resolvedSessionId,
5691
- publishableKey,
5692
- paypalPublishableKey
5693
- });
5694
- }
5695
- const {
5696
- flopay,
5697
- paypalFlopay
5698
- } = await loadSavedPaymentProviders({
5699
- publishableKey,
5700
- paypalPublishableKey,
5701
- billingApiUrl: resolvedBillingUrl,
5702
- locale
5703
- });
5704
- paymentResult = await handleSavedPaymentRedirectResult(redirectResult, {
5705
- flopay,
5706
- paypalFlopay,
5707
- attempt3DS: true,
5708
- billingApiUrl: resolvedBillingUrl,
5709
- sessionId: session.id || resolvedSessionId,
5710
- session
5711
- });
5712
- if (redirectResult.type === "paypal_redirect_required") {
5713
- clearPayPalResumeState2();
5714
- }
5715
- } else if (apiResult.autoProcessingError && !shouldRetryPayPalClientSide) {
5554
+ if (apiResult.autoProcessingError) {
5716
5555
  throw checkoutProcessErrorToFloPayError(
5717
5556
  apiResult.autoProcessingError,
5718
5557
  "Automatic payment failed. Please try again.",
@@ -5720,7 +5559,22 @@ function FloPayAutomaticPaymentButton({
5720
5559
  checkoutMethod: apiResult.autoProcessingError.checkoutMethod
5721
5560
  }
5722
5561
  );
5723
- } else if (shouldTreatCreateSessionFlowAsServerAutoAttempt && !shouldRetryPayPalClientSide) {
5562
+ }
5563
+ if (options?.fromCreateSession && apiResult.autoProcessingAttempted === true) {
5564
+ throw checkoutProcessErrorToFloPayError(
5565
+ {
5566
+ type: "unknown",
5567
+ message: "Automatic payment failed. Please try again."
5568
+ },
5569
+ "Automatic payment failed. Please try again."
5570
+ );
5571
+ }
5572
+ const result = await processSavedPaymentForMode({
5573
+ billingApiUrl: resolvedBillingUrl,
5574
+ sessionId: resolvedSessionId ?? session.id,
5575
+ session
5576
+ });
5577
+ if (result.type !== "success") {
5724
5578
  throw checkoutProcessErrorToFloPayError(
5725
5579
  {
5726
5580
  type: "unknown",
@@ -5728,121 +5582,16 @@ function FloPayAutomaticPaymentButton({
5728
5582
  },
5729
5583
  "Automatic payment failed. Please try again."
5730
5584
  );
5731
- } else {
5732
- const result = await processSavedPaymentForMode({
5733
- billingApiUrl: resolvedBillingUrl,
5734
- sessionId: resolvedSessionId ?? session.id,
5735
- session,
5736
- tokenizedData: automaticPaymentToken
5737
- });
5738
- paymentResult = result.type === "success" ? result.result : null;
5739
- if (result.type !== "success") {
5740
- const {
5741
- publishableKey,
5742
- paypalPublishableKey
5743
- } = resolveSavedPaymentPublishableKeys(apiResult);
5744
- if (result.type === "paypal_redirect_required" && publishableKey) {
5745
- persistPayPalResumeState2({
5746
- sessionId: session.id || resolvedSessionId,
5747
- publishableKey,
5748
- paypalPublishableKey
5749
- });
5750
- }
5751
- const {
5752
- flopay,
5753
- paypalFlopay
5754
- } = await loadSavedPaymentProviders({
5755
- publishableKey,
5756
- paypalPublishableKey,
5757
- billingApiUrl: resolvedBillingUrl,
5758
- locale
5759
- });
5760
- paymentResult = await handleSavedPaymentRedirectResult(result, {
5761
- flopay,
5762
- paypalFlopay,
5763
- attempt3DS: true,
5764
- billingApiUrl: resolvedBillingUrl,
5765
- sessionId: session.id || resolvedSessionId,
5766
- session
5767
- });
5768
- if (result.type === "paypal_redirect_required") {
5769
- clearPayPalResumeState2();
5770
- }
5771
- }
5772
5585
  }
5773
5586
  await showSuccess({
5774
- result: paymentResult ? {
5775
- ...paymentResult,
5776
- paymentMethodId: paymentResult.paymentMethodId ?? paymentMethodId,
5777
- checkoutMethod: paymentResult.checkoutMethod ?? checkoutMethod
5778
- } : {
5779
- status: "succeeded",
5780
- paymentMethodId: paymentMethodId ?? void 0,
5781
- checkoutMethod
5782
- },
5587
+ result: result.result,
5783
5588
  session,
5784
5589
  sessionId: session.id || resolvedSessionId,
5785
5590
  autoCompleted: false
5786
5591
  });
5787
5592
  } catch (err) {
5788
- let floPayErr = normalizeSavedPaymentError(err);
5593
+ const floPayErr = normalizeSavedPaymentError(err);
5789
5594
  const fallbackSessionId = session.id || resolvedSessionId;
5790
- const shouldTreatCreateSessionFlowAsServerAutoAttempt = options?.fromCreateSession && apiResult.autoProcessingAttempted === true;
5791
- if (!shouldTreatCreateSessionFlowAsServerAutoAttempt && floPayErr.code === "authentication_required" && fallbackSessionId && automaticPaymentToken?.id && automaticPaymentToken.id.startsWith("pm_")) {
5792
- try {
5793
- const {
5794
- publishableKey,
5795
- paypalPublishableKey
5796
- } = resolveSavedPaymentPublishableKeys(apiResult);
5797
- const {
5798
- flopay
5799
- } = await loadSavedPaymentProviders({
5800
- publishableKey,
5801
- paypalPublishableKey,
5802
- billingApiUrl: resolvedBillingUrl,
5803
- locale
5804
- });
5805
- if (!flopay) {
5806
- throw new FloPayError8(
5807
- "Stripe is not available for 3DS authentication.",
5808
- "api_error",
5809
- { code: "authentication_required" }
5810
- );
5811
- }
5812
- const paymentResult = await processSavedPaymentWithIntent({
5813
- billingApiUrl: resolvedBillingUrl,
5814
- sessionId: fallbackSessionId,
5815
- session,
5816
- paymentMethodId: automaticPaymentToken.id,
5817
- flopay
5818
- });
5819
- await showSuccess({
5820
- result: {
5821
- ...paymentResult,
5822
- paymentMethodId: paymentResult.paymentMethodId ?? paymentMethodId,
5823
- checkoutMethod: paymentResult.checkoutMethod ?? checkoutMethod
5824
- },
5825
- session,
5826
- sessionId: fallbackSessionId,
5827
- autoCompleted: false
5828
- });
5829
- return;
5830
- } catch (intentRecoveryErr) {
5831
- floPayErr = normalizeSavedPaymentError(intentRecoveryErr);
5832
- }
5833
- }
5834
- const inResumeWindow = typeof window !== "undefined" && new URLSearchParams(window.location.search).has("payment_intent_client_secret") && !!readPayPalResumeState2();
5835
- if (floPayErr.code === "payment_intent_unexpected_state" && inResumeWindow) {
5836
- return;
5837
- }
5838
- const isSilentFallbackCase = (floPayErr.code === "paypal_requires_user_interaction" || floPayErr.code === "payment_intent_unexpected_state") && shouldShowFallbackCheckout(floPayErr, fallbackSessionId) && !!fallbackSessionId && isMountedRef.current;
5839
- if (isSilentFallbackCase) {
5840
- setFallbackSession({
5841
- sessionId: fallbackSessionId,
5842
- errorMessage: ""
5843
- });
5844
- return;
5845
- }
5846
5595
  await showError(floPayErr, {
5847
5596
  emitDecline: true,
5848
5597
  method: floPayErr.checkoutMethod ?? DEFAULT_SAVED_PAYMENT_DECLINE_METHOD
@@ -5855,10 +5604,6 @@ function FloPayAutomaticPaymentButton({
5855
5604
  }
5856
5605
  }
5857
5606
  }, [
5858
- checkoutMethod,
5859
- locale,
5860
- automaticPaymentToken,
5861
- paymentMethodId,
5862
5607
  resolvedBillingUrl,
5863
5608
  showError,
5864
5609
  showSuccess
@@ -5905,8 +5650,7 @@ function FloPayAutomaticPaymentButton({
5905
5650
  }
5906
5651
  try {
5907
5652
  const result = await api.createAndFetchSession({
5908
- ...createSessionDraft,
5909
- ...automaticPaymentToken ? { tokenizedData: automaticPaymentToken } : {}
5653
+ ...createSessionDraft
5910
5654
  });
5911
5655
  await processResolvedSession(result, result.data.session?.id ?? null, {
5912
5656
  fromCreateSession: true
@@ -5961,146 +5705,16 @@ function FloPayAutomaticPaymentButton({
5961
5705
  const handleFallbackDecline = useCallback5((decline) => {
5962
5706
  onDeclineRef.current?.(decline);
5963
5707
  }, []);
5964
- useEffect8(() => {
5965
- if (typeof window === "undefined" || resumeAttemptedRef.current) {
5966
- return;
5967
- }
5968
- const params = new URLSearchParams(window.location.search);
5969
- const clientSecret = params.get("payment_intent_client_secret");
5970
- if (!clientSecret) {
5971
- return;
5972
- }
5973
- const resumeState = readPayPalResumeState2();
5974
- if (!resumeState) {
5975
- return;
5976
- }
5977
- resumeAttemptedRef.current = true;
5978
- void (async () => {
5979
- setIsProcessing(true);
5980
- setOverlayError(null);
5981
- setOverlayStatus("processing");
5982
- try {
5983
- if (params.get("redirect_status") === "failed") {
5984
- throw Object.assign(
5985
- new FloPayError8("PayPal payment was declined. Please try again.", "api_error"),
5986
- { checkoutMethod: "paypal" }
5987
- );
5988
- }
5989
- const {
5990
- flopay,
5991
- paypalFlopay
5992
- } = await loadSavedPaymentProviders({
5993
- publishableKey: resumeState.publishableKey,
5994
- paypalPublishableKey: resumeState.paypalPublishableKey,
5995
- billingApiUrl: resolvedBillingUrl,
5996
- locale
5997
- });
5998
- const paypalStripe = (paypalFlopay ?? flopay)?.getRawProvider();
5999
- if (!paypalStripe) {
6000
- throw Object.assign(
6001
- new FloPayError8("PayPal is not available.", "api_error"),
6002
- { checkoutMethod: "paypal" }
6003
- );
6004
- }
6005
- const { paymentIntent, error } = await paypalStripe.retrievePaymentIntent(clientSecret);
6006
- if (error) {
6007
- throw Object.assign(
6008
- new FloPayError8(
6009
- error.message ?? "Failed to retrieve PayPal payment status.",
6010
- "api_error",
6011
- { code: error.code }
6012
- ),
6013
- { checkoutMethod: "paypal" }
6014
- );
6015
- }
6016
- const resultStatus = mapPayPalIntentStatusToPaymentResult(paymentIntent?.status);
6017
- if (!paymentIntent || resultStatus === "failed") {
6018
- throw Object.assign(
6019
- new FloPayError8("PayPal payment was not completed. Please try again.", "api_error"),
6020
- { checkoutMethod: "paypal" }
6021
- );
6022
- }
6023
- const paymentMethodId2 = typeof paymentIntent.payment_method === "string" ? paymentIntent.payment_method : paymentIntent.payment_method?.id;
6024
- if (!resumeState.sessionId) {
6025
- throw Object.assign(
6026
- new FloPayError8("Missing session id on PayPal resume.", "api_error"),
6027
- { checkoutMethod: "paypal" }
6028
- );
6029
- }
6030
- const api = new PaymentAPI7(resolvedBillingUrl);
6031
- const sessionResult = await api.getUnifiedCheckoutSession(resumeState.sessionId);
6032
- let resumeSession = sessionResult.data.session;
6033
- if (!resumeSession) {
6034
- throw Object.assign(
6035
- new FloPayError8("Could not load session to capture PayPal payment.", "api_error"),
6036
- { checkoutMethod: "paypal" }
6037
- );
6038
- }
6039
- let finalResultStatus = resultStatus;
6040
- if (resumeSession.status !== "complete") {
6041
- const processResult = await processSavedPaymentForMode({
6042
- billingApiUrl: resolvedBillingUrl,
6043
- sessionId: resumeState.sessionId,
6044
- session: resumeSession,
6045
- tokenizedData: {
6046
- id: paymentMethodId2 ?? paymentIntent.id,
6047
- type: "card",
6048
- threeDSecureActionResultTokenId: paymentIntent.id,
6049
- isPaypal: true
6050
- }
6051
- });
6052
- if (processResult.type !== "success") {
6053
- throw Object.assign(
6054
- new FloPayError8("Failed to finalize PayPal payment.", "api_error"),
6055
- { checkoutMethod: "paypal" }
6056
- );
6057
- }
6058
- finalResultStatus = processResult.result.status;
6059
- try {
6060
- const refreshed = await api.getUnifiedCheckoutSession(resumeState.sessionId);
6061
- if (refreshed.data.session) {
6062
- resumeSession = refreshed.data.session;
6063
- }
6064
- } catch {
6065
- }
6066
- }
6067
- await showSuccess({
6068
- result: {
6069
- status: finalResultStatus,
6070
- paymentIntentId: paymentIntent.id,
6071
- paymentMethodId: paymentMethodId2,
6072
- checkoutMethod: "paypal"
6073
- },
6074
- session: resumeSession,
6075
- sessionId: resumeState.sessionId,
6076
- autoCompleted: false
6077
- });
6078
- } catch (err) {
6079
- const floPayErr = normalizeSavedPaymentError(err);
6080
- await showError(floPayErr, {
6081
- emitDecline: true,
6082
- method: floPayErr.checkoutMethod ?? "paypal"
6083
- });
6084
- } finally {
6085
- clearPayPalResumeState2();
6086
- clearPayPalRedirectParams2();
6087
- if (isMountedRef.current) {
6088
- setOverlayStatus(null);
6089
- setOverlayError(null);
6090
- setIsProcessing(false);
6091
- }
6092
- }
6093
- })();
6094
- }, [locale, resolvedBillingUrl, showError, showSuccess]);
5708
+ const themeBundle = useMemo5(() => resolveTheme3(theme), [theme]);
6095
5709
  const bStyles = useMemo5(() => {
6096
- const base = resolveButtonsLayoutTheme3(buttonsTheme);
5710
+ const base = themeBundle?.buttonsLayout ?? resolveButtonsLayoutTheme3(buttonsTheme);
6097
5711
  if (!stylesOverride) return base;
6098
5712
  return {
6099
5713
  ...base,
6100
5714
  ...stylesOverride,
6101
5715
  cardButton: { ...base.cardButton, ...stylesOverride.cardButton }
6102
5716
  };
6103
- }, [buttonsTheme, stylesOverride]);
5717
+ }, [themeBundle, buttonsTheme, stylesOverride]);
6104
5718
  const cardButtonSizing = children === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
6105
5719
  return /* @__PURE__ */ jsxs8(Fragment6, { children: [
6106
5720
  /* @__PURE__ */ jsx10(
@@ -6197,9 +5811,12 @@ function FloPayAutomaticPaymentButton({
6197
5811
  sessionId: fallbackSession.sessionId,
6198
5812
  checkoutMode: "full",
6199
5813
  billingApiUrl: resolvedBillingUrl,
5814
+ locale,
5815
+ theme,
5816
+ buttonsTheme,
5817
+ buttonsStyles: stylesOverride,
6200
5818
  initialErrorMessage: fallbackSession.errorMessage,
6201
5819
  cardTitleContent: null,
6202
- showSecurityFooter: false,
6203
5820
  onComplete: handleFallbackComplete,
6204
5821
  onError: handleFallbackError,
6205
5822
  onDecline: handleFallbackDecline