@flopay/react 0.3.14 → 0.3.17

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.d.cts CHANGED
@@ -72,6 +72,12 @@ interface FloPayCheckoutProps {
72
72
  onError?: (error: FloPayError) => void;
73
73
  /** Called when a payment is declined or the authentication step fails. */
74
74
  onDecline?: (decline: DeclineEvent) => void;
75
+ /** Called when the full cardholder name input changes. */
76
+ onFullNameChange?: (value: string) => void;
77
+ /** Called when the AVS country dropdown changes. */
78
+ onCountryChange?: (country: string) => void;
79
+ /** Called when the AVS ZIP/postcode input changes. */
80
+ onZipChange?: (zip: string) => void;
75
81
  /** Whether to show the PayPal button (default: true). */
76
82
  showPayPal?: boolean;
77
83
  /** Whether to show Apple Pay button (default: true). Only renders on supported devices. */
@@ -152,7 +158,7 @@ interface FloPayCheckoutProps {
152
158
  * />
153
159
  * ```
154
160
  */
155
- declare function FloPayCheckout({ sessionId: sessionIdProp, createSession: createSessionParams, billingApiUrl, appearance, locale, fallbackPublishableKey, loading: loadingNode, error: errorNode, onComplete, onError, onDecline, showPayPal, showApplePay, showGooglePay, layout, buttonsTheme, buttonsStyles, cardButtonContent, cardBackButtonContent, cardTitleContent, onButtonClick, onBeforeButtonClick, enableAVS, avsLayout, submitLabel, className, children, checkoutMode: checkoutModeProp, confirmLabel, renderConfirmButton, onSessionCompleted, }: FloPayCheckoutProps): React.ReactElement;
161
+ declare function FloPayCheckout({ sessionId: sessionIdProp, createSession: createSessionParams, billingApiUrl, appearance, locale, fallbackPublishableKey, loading: loadingNode, error: errorNode, onComplete, onError, onDecline, onFullNameChange, onCountryChange, onZipChange, showPayPal, showApplePay, showGooglePay, layout, buttonsTheme, buttonsStyles, cardButtonContent, cardBackButtonContent, cardTitleContent, onButtonClick, onBeforeButtonClick, enableAVS, avsLayout, submitLabel, className, children, checkoutMode: checkoutModeProp, confirmLabel, renderConfirmButton, onSessionCompleted, }: FloPayCheckoutProps): React.ReactElement;
156
162
 
157
163
  /**
158
164
  * Returns the current `FloPay` instance, or `null` if the provider
@@ -366,6 +372,8 @@ interface SplitCardFormProps {
366
372
  error?: string | null;
367
373
  /** Called when internal error state changes. */
368
374
  onErrorChange?: (error: string | null) => void;
375
+ /** Callback when the full cardholder name input changes. */
376
+ onFullNameChange?: (value: string) => void;
369
377
  /** Callback when first name changes (from the name input). */
370
378
  onFirstNameChange?: (value: string) => void;
371
379
  /** Callback when last name changes (from the name input). */
package/dist/index.d.ts CHANGED
@@ -72,6 +72,12 @@ interface FloPayCheckoutProps {
72
72
  onError?: (error: FloPayError) => void;
73
73
  /** Called when a payment is declined or the authentication step fails. */
74
74
  onDecline?: (decline: DeclineEvent) => void;
75
+ /** Called when the full cardholder name input changes. */
76
+ onFullNameChange?: (value: string) => void;
77
+ /** Called when the AVS country dropdown changes. */
78
+ onCountryChange?: (country: string) => void;
79
+ /** Called when the AVS ZIP/postcode input changes. */
80
+ onZipChange?: (zip: string) => void;
75
81
  /** Whether to show the PayPal button (default: true). */
76
82
  showPayPal?: boolean;
77
83
  /** Whether to show Apple Pay button (default: true). Only renders on supported devices. */
@@ -152,7 +158,7 @@ interface FloPayCheckoutProps {
152
158
  * />
153
159
  * ```
154
160
  */
155
- declare function FloPayCheckout({ sessionId: sessionIdProp, createSession: createSessionParams, billingApiUrl, appearance, locale, fallbackPublishableKey, loading: loadingNode, error: errorNode, onComplete, onError, onDecline, showPayPal, showApplePay, showGooglePay, layout, buttonsTheme, buttonsStyles, cardButtonContent, cardBackButtonContent, cardTitleContent, onButtonClick, onBeforeButtonClick, enableAVS, avsLayout, submitLabel, className, children, checkoutMode: checkoutModeProp, confirmLabel, renderConfirmButton, onSessionCompleted, }: FloPayCheckoutProps): React.ReactElement;
161
+ declare function FloPayCheckout({ sessionId: sessionIdProp, createSession: createSessionParams, billingApiUrl, appearance, locale, fallbackPublishableKey, loading: loadingNode, error: errorNode, onComplete, onError, onDecline, onFullNameChange, onCountryChange, onZipChange, showPayPal, showApplePay, showGooglePay, layout, buttonsTheme, buttonsStyles, cardButtonContent, cardBackButtonContent, cardTitleContent, onButtonClick, onBeforeButtonClick, enableAVS, avsLayout, submitLabel, className, children, checkoutMode: checkoutModeProp, confirmLabel, renderConfirmButton, onSessionCompleted, }: FloPayCheckoutProps): React.ReactElement;
156
162
 
157
163
  /**
158
164
  * Returns the current `FloPay` instance, or `null` if the provider
@@ -366,6 +372,8 @@ interface SplitCardFormProps {
366
372
  error?: string | null;
367
373
  /** Called when internal error state changes. */
368
374
  onErrorChange?: (error: string | null) => void;
375
+ /** Callback when the full cardholder name input changes. */
376
+ onFullNameChange?: (value: string) => void;
369
377
  /** Callback when first name changes (from the name input). */
370
378
  onFirstNameChange?: (value: string) => void;
371
379
  /** Callback when last name changes (from the name input). */
package/dist/index.mjs CHANGED
@@ -206,7 +206,7 @@ import {
206
206
  useStripe as useStripeRaw
207
207
  } from "@stripe/react-stripe-js";
208
208
  import { resolveButtonsLayoutTheme, getPostalCodeLabel, COUNTRY_OPTIONS } from "@flopay/shared";
209
- import { forwardRef, useCallback, useEffect as useEffect3, useImperativeHandle, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
209
+ import { forwardRef, useCallback, useContext as useContext3, useEffect as useEffect3, useImperativeHandle, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
210
210
 
211
211
  // src/hooks.ts
212
212
  import { useContext as useContext2 } from "react";
@@ -307,15 +307,6 @@ function buildSyntheticSession(params, checkoutModeOverride) {
307
307
  }))
308
308
  };
309
309
  }
310
- function ensureInlineSessionReady(params) {
311
- if (!params.account.email?.trim()) {
312
- throw new FloPayError(
313
- "Email is required before continuing with card checkout.",
314
- "validation_error",
315
- { param: "createSession.account.email" }
316
- );
317
- }
318
- }
319
310
  function mergeAccountPatch(base, patch) {
320
311
  if (!patch) return base;
321
312
  return {
@@ -370,6 +361,52 @@ function toCssWeight(value) {
370
361
  if (typeof value === "number" || typeof value === "string") return value;
371
362
  return void 0;
372
363
  }
364
+ function resolveExpressCheckoutLoadState(event, methods) {
365
+ const available = event.availablePaymentMethods;
366
+ if (!available) return "unavailable";
367
+ return methods.some((method) => available[method]) ? "ready" : "unavailable";
368
+ }
369
+ function ExpressCheckoutReadySwap({
370
+ state,
371
+ placeholderTestId,
372
+ children
373
+ }) {
374
+ if (state === "unavailable") return null;
375
+ return /* @__PURE__ */ jsxs2("div", { style: { position: "relative", minHeight: 44 }, children: [
376
+ /* @__PURE__ */ jsx4(
377
+ "div",
378
+ {
379
+ "data-testid": placeholderTestId,
380
+ "aria-hidden": state === "ready",
381
+ style: {
382
+ position: "absolute",
383
+ inset: 0,
384
+ height: 44,
385
+ borderRadius: 8,
386
+ background: "#e5e7eb",
387
+ animation: state === "ready" ? void 0 : "flopay-pulse 1.5s ease-in-out infinite",
388
+ opacity: state === "ready" ? 0 : 1,
389
+ transform: state === "ready" ? "scale(0.985)" : "scale(1)",
390
+ transition: "opacity 140ms ease-out, transform 140ms ease-out",
391
+ pointerEvents: "none"
392
+ }
393
+ }
394
+ ),
395
+ /* @__PURE__ */ jsx4(
396
+ "div",
397
+ {
398
+ style: {
399
+ minHeight: 44,
400
+ opacity: state === "ready" ? 1 : 0,
401
+ transform: state === "ready" ? "translateY(0)" : "translateY(2px)",
402
+ transition: "opacity 140ms ease-out, transform 140ms ease-out",
403
+ pointerEvents: state === "ready" ? "auto" : "none"
404
+ },
405
+ children
406
+ }
407
+ )
408
+ ] });
409
+ }
373
410
  function ProcessingOverlay({ status, errorMessage }) {
374
411
  return /* @__PURE__ */ jsx4("div", { style: {
375
412
  position: "fixed",
@@ -487,7 +524,7 @@ function PayPalButtonInner({
487
524
  }) {
488
525
  const stripe = useStripeRaw();
489
526
  const elements = useStripeElements();
490
- const [ready, setReady] = useState2(false);
527
+ const [loadState, setLoadState] = useState2("loading");
491
528
  const [submitting, setSubmitting] = useState2(false);
492
529
  const paypalResumeAttempted = useRef2(false);
493
530
  const baseUrl = billingApiUrl.replace(/\/+$/, "");
@@ -599,12 +636,11 @@ function PayPalButtonInner({
599
636
  }
600
637
  }, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]);
601
638
  return /* @__PURE__ */ jsxs2(Fragment2, { children: [
602
- /* @__PURE__ */ jsx4("div", { children: /* @__PURE__ */ jsx4(
639
+ /* @__PURE__ */ jsx4(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ jsx4(
603
640
  ExpressCheckoutElement,
604
641
  {
605
- onReady: () => setReady(true),
606
- onLoadError: () => {
607
- },
642
+ onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
643
+ onLoadError: () => setLoadState("unavailable"),
608
644
  onConfirm: handlePayPalConfirm,
609
645
  onCancel: () => {
610
646
  onDecline?.(buildDeclineEvent("paypal", "PayPal checkout was cancelled."));
@@ -636,7 +672,7 @@ function WalletButtonInner({
636
672
  }) {
637
673
  const stripe = useStripeRaw();
638
674
  const elements = useStripeElements();
639
- const [ready, setReady] = useState2(false);
675
+ const [loadState, setLoadState] = useState2("loading");
640
676
  const [submitting, setSubmitting] = useState2(false);
641
677
  const baseUrl = billingApiUrl.replace(/\/+$/, "");
642
678
  const lastWalletMethodRef = useRef2("card");
@@ -702,12 +738,11 @@ function WalletButtonInner({
702
738
  [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]
703
739
  );
704
740
  return /* @__PURE__ */ jsxs2(Fragment2, { children: [
705
- /* @__PURE__ */ jsx4("div", { children: /* @__PURE__ */ jsx4(
741
+ /* @__PURE__ */ jsx4(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ jsx4(
706
742
  ExpressCheckoutElement,
707
743
  {
708
- onReady: () => setReady(true),
709
- onLoadError: () => {
710
- },
744
+ onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["applePay", "googlePay"])),
745
+ onLoadError: () => setLoadState("unavailable"),
711
746
  onClick: (event) => {
712
747
  lastWalletMethodRef.current = event.expressPaymentType === "apple_pay" ? "apple_pay" : "google_pay";
713
748
  event.resolve();
@@ -751,6 +786,7 @@ function SplitCardFormInner({
751
786
  isProcessing: externalProcessing,
752
787
  error: externalError,
753
788
  onErrorChange,
789
+ onFullNameChange,
754
790
  onFirstNameChange,
755
791
  onLastNameChange,
756
792
  showPayPal = true,
@@ -777,6 +813,7 @@ function SplitCardFormInner({
777
813
  }) {
778
814
  const flopay = useFloPay();
779
815
  const elements = useElements();
816
+ const checkout = useContext3(CheckoutContext);
780
817
  const contextBillingUrl = useBillingApiUrl();
781
818
  const [processing, setProcessing] = useState2(false);
782
819
  const [error, setError] = useState2(null);
@@ -822,7 +859,8 @@ function SplitCardFormInner({
822
859
  title: { ...base.title, ...buttonsStylesOverride.title }
823
860
  };
824
861
  }, [buttonsTheme, buttonsStylesOverride]);
825
- const isSubmitting = externalProcessing ?? processing;
862
+ const isInlineSessionPatchProcessing = checkout.inlineSessionPatchProcessing ?? false;
863
+ const isSubmitting = (externalProcessing ?? processing) || isInlineSessionPatchProcessing;
826
864
  const isSelfContained = !onTokenizedBody;
827
865
  const baseUrl = resolvedBillingApiUrl.replace(/\/+$/, "");
828
866
  const resolvedAccount = useMemo2(() => mergeAccountPatch({
@@ -867,10 +905,11 @@ function SplitCardFormInner({
867
905
  const showWallets = showApplePay || showGooglePay;
868
906
  const handleNameChange = useCallback((value) => {
869
907
  setFullName(value);
908
+ onFullNameChange?.(value);
870
909
  const parts = value.trim().split(/\s+/);
871
910
  onFirstNameChange?.(parts[0] ?? "");
872
911
  onLastNameChange?.(parts.length > 1 ? parts.slice(1).join(" ") : "");
873
- }, [onFirstNameChange, onLastNameChange]);
912
+ }, [onFullNameChange, onFirstNameChange, onLastNameChange]);
874
913
  const runBeforeCardButtonClick = useCallback(async () => {
875
914
  if (!onBeforeButtonClick) return true;
876
915
  try {
@@ -881,8 +920,11 @@ function SplitCardFormInner({
881
920
  if (result === false) {
882
921
  return false;
883
922
  }
884
- if (result?.account) {
885
- setAccountPatch((prev) => ({ ...prev ?? {}, ...result.account }));
923
+ if (result && typeof result === "object") {
924
+ await checkout.applyInlineSessionPatch?.(result);
925
+ if (result.account) {
926
+ setAccountPatch((prev) => ({ ...prev ?? {}, ...result.account }));
927
+ }
886
928
  }
887
929
  return true;
888
930
  } catch (err) {
@@ -894,7 +936,7 @@ function SplitCardFormInner({
894
936
  onError?.(floPayErr);
895
937
  return false;
896
938
  }
897
- }, [onBeforeButtonClick, sessionId, updateError, onError]);
939
+ }, [checkout.applyInlineSessionPatch, onBeforeButtonClick, sessionId, updateError, onError]);
898
940
  const processPaymentInternal = useCallback(
899
941
  async (tokenizedBody) => {
900
942
  if (processingRef.current) return;
@@ -1503,11 +1545,13 @@ function SplitCardFormInner({
1503
1545
  {
1504
1546
  type: "button",
1505
1547
  onClick: async () => {
1548
+ if (isSubmitting) return;
1506
1549
  const shouldContinue = await runBeforeCardButtonClick();
1507
1550
  if (!shouldContinue) return;
1508
1551
  onButtonClick?.("card");
1509
1552
  expandToCard();
1510
1553
  },
1554
+ disabled: isSubmitting,
1511
1555
  style: {
1512
1556
  width: "100%",
1513
1557
  padding: "0.9rem 1rem",
@@ -1517,7 +1561,7 @@ function SplitCardFormInner({
1517
1561
  borderRadius: "8px",
1518
1562
  fontSize: bStyles.cardButtonFontSize ?? "0.95rem",
1519
1563
  fontWeight: 600,
1520
- cursor: "pointer",
1564
+ cursor: isSubmitting ? "not-allowed" : "pointer",
1521
1565
  display: "flex",
1522
1566
  alignItems: "center",
1523
1567
  justifyContent: "center",
@@ -1525,6 +1569,7 @@ function SplitCardFormInner({
1525
1569
  transition: "border-color 0.2s, box-shadow 0.2s, transform 0.1s",
1526
1570
  boxShadow: "0 1px 2px rgba(0,0,0,0.04)",
1527
1571
  position: "relative",
1572
+ opacity: isSubmitting ? 0.6 : 1,
1528
1573
  ...bStyles.cardButton
1529
1574
  },
1530
1575
  onMouseDown: (e) => {
@@ -1608,6 +1653,12 @@ function SplitCardFormInner({
1608
1653
 
1609
1654
  // src/flopay-checkout.tsx
1610
1655
  import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1656
+ function hasInlineSessionPatchData(patch) {
1657
+ if (!patch) return false;
1658
+ return Boolean(
1659
+ patch.account && Object.keys(patch.account).length > 0 || patch.couponCodes !== void 0 || patch.tagsData !== void 0 || patch.utmMetadata !== void 0
1660
+ );
1661
+ }
1611
1662
  function FloPayCheckout({
1612
1663
  sessionId: sessionIdProp,
1613
1664
  createSession: createSessionParams,
@@ -1620,6 +1671,9 @@ function FloPayCheckout({
1620
1671
  onComplete,
1621
1672
  onError,
1622
1673
  onDecline,
1674
+ onFullNameChange,
1675
+ onCountryChange,
1676
+ onZipChange,
1623
1677
  showPayPal = true,
1624
1678
  showApplePay = true,
1625
1679
  showGooglePay = true,
@@ -1655,7 +1709,6 @@ function FloPayCheckout({
1655
1709
  const [createSessionPatch, setCreateSessionPatch] = useState3(void 0);
1656
1710
  const [createSessionPatchBaseHash, setCreateSessionPatchBaseHash] = useState3("");
1657
1711
  const [cardBootstrapPending, setCardBootstrapPending] = useState3(false);
1658
- const [deferredCardOpen, setDeferredCardOpen] = useState3(false);
1659
1712
  const autoCheckoutAttempted = useRef3(false);
1660
1713
  const onCompleteRef = useRef3(onComplete);
1661
1714
  onCompleteRef.current = onComplete;
@@ -1790,9 +1843,6 @@ function FloPayCheckout({
1790
1843
  );
1791
1844
  const inflightRef = useRef3(/* @__PURE__ */ new Map());
1792
1845
  const initializedHashRef = useRef3(null);
1793
- const deferInlineSessionUntilCardClick = Boolean(
1794
- effectiveCreateSession && !children && layout === "buttons" && onBeforeButtonClick && (effectiveCreateSession.checkoutMode ?? checkoutModeProp ?? "full") === "full"
1795
- );
1796
1846
  function hashCreateParams(params) {
1797
1847
  const key = JSON.stringify({
1798
1848
  c: params?.clientId,
@@ -1822,7 +1872,6 @@ function FloPayCheckout({
1822
1872
  setResolvedSessionId(sessionIdProp ?? "");
1823
1873
  }, [sessionIdProp]);
1824
1874
  async function resolveInlineSession(params, cacheKey) {
1825
- ensureInlineSessionReady(params);
1826
1875
  const api = new PaymentAPI(resolvedBillingUrl);
1827
1876
  let sid = typeof window !== "undefined" ? window.sessionStorage.getItem(cacheKey) : null;
1828
1877
  let realResult = null;
@@ -1867,104 +1916,64 @@ function FloPayCheckout({
1867
1916
  } finally {
1868
1917
  inflightRef.current.delete(cacheKey);
1869
1918
  }
1870
- if (patch) {
1871
- setCreateSessionPatchBaseHash(baseCreateSessionHash);
1872
- setCreateSessionPatch((prev) => mergeInlineSessionPatches(prev, patch));
1873
- }
1874
- const { sid, result: realResult } = resolved;
1875
- setUnified(realResult);
1876
- if (realResult.data.session) {
1877
- setSession(realResult.data.session);
1878
- }
1879
- if (sid) {
1880
- setResolvedSessionId(sid);
1881
- }
1882
- let publishableKey;
1883
- if (realResult.provider === "stripe") {
1884
- publishableKey = realResult.data.stripe?.publishableKey;
1885
- }
1886
- if (!publishableKey) publishableKey = fallbackPublishableKey;
1887
- if (!publishableKey) {
1888
- throw new FloPayError3(
1889
- "No publishable key found. Provide fallbackPublishableKey or ensure the session includes gatewayData.publishableKey.",
1890
- "validation_error"
1891
- );
1892
- }
1893
- const instance = await loadFloPay(publishableKey, {
1894
- billingApiUrl: resolvedBillingUrl,
1895
- locale
1896
- });
1897
- flopayRef.current = instance;
1898
- setFloPay(instance);
1899
1919
  initializedHashRef.current = cacheKey;
1900
- setIsLoading(false);
1920
+ try {
1921
+ if (patch) {
1922
+ setCreateSessionPatchBaseHash(baseCreateSessionHash);
1923
+ setCreateSessionPatch((prev) => mergeInlineSessionPatches(prev, patch));
1924
+ }
1925
+ const { sid, result: realResult } = resolved;
1926
+ setUnified(realResult);
1927
+ if (realResult.data.session) {
1928
+ setSession(realResult.data.session);
1929
+ }
1930
+ if (sid) {
1931
+ setResolvedSessionId(sid);
1932
+ }
1933
+ let publishableKey;
1934
+ if (realResult.provider === "stripe") {
1935
+ publishableKey = realResult.data.stripe?.publishableKey;
1936
+ }
1937
+ if (!publishableKey) publishableKey = fallbackPublishableKey;
1938
+ if (!publishableKey) {
1939
+ throw new FloPayError3(
1940
+ "No publishable key found. Provide fallbackPublishableKey or ensure the session includes gatewayData.publishableKey.",
1941
+ "validation_error"
1942
+ );
1943
+ }
1944
+ const instance = await loadFloPay(publishableKey, {
1945
+ billingApiUrl: resolvedBillingUrl,
1946
+ locale
1947
+ });
1948
+ flopayRef.current = instance;
1949
+ setFloPay(instance);
1950
+ setIsLoading(false);
1951
+ } catch (err) {
1952
+ if (initializedHashRef.current === cacheKey) {
1953
+ initializedHashRef.current = null;
1954
+ }
1955
+ throw err;
1956
+ }
1901
1957
  return resolved;
1902
1958
  },
1903
1959
  [fallbackPublishableKey, locale, resolvedBillingUrl]
1904
1960
  );
1905
- const handleDeferredCardButtonClick = useCallback2(async () => {
1906
- if (cardBootstrapPending) return;
1907
- setLoadError(null);
1961
+ const handleInlineSessionPatch = useCallback2(async (patch) => {
1962
+ if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) return;
1908
1963
  setCardBootstrapPending(true);
1909
1964
  try {
1910
- const beforeClickResult = await onBeforeButtonClick?.({
1911
- method: "card",
1912
- createSession: effectiveCreateSession
1913
- });
1914
- if (beforeClickResult === false) {
1915
- setDeferredCardOpen(false);
1916
- return;
1917
- }
1918
- const patch = beforeClickResult && typeof beforeClickResult === "object" ? beforeClickResult : void 0;
1919
- const baseParams = createSessionParamsRef.current;
1920
- if (!baseParams) {
1921
- throw new FloPayError3(
1922
- "createSession is required to bootstrap checkout.",
1923
- "validation_error"
1924
- );
1925
- }
1926
- ensureInlineSessionReady(mergeInlineSessionPatch(baseParams, patch));
1927
- setDeferredCardOpen(true);
1928
- onButtonClick?.("card");
1929
1965
  await bootstrapInlineSession(patch);
1930
- } catch (err) {
1931
- setDeferredCardOpen(false);
1932
- const floPayErr = err instanceof FloPayError3 ? err : new FloPayError3(
1933
- err instanceof Error ? err.message : "Failed to start card checkout.",
1934
- "api_error"
1935
- );
1936
- setLoadError(floPayErr);
1937
- onErrorRef.current?.(floPayErr);
1938
1966
  } finally {
1939
1967
  setCardBootstrapPending(false);
1940
1968
  }
1941
1969
  }, [
1942
1970
  bootstrapInlineSession,
1943
- baseCreateSessionHash,
1944
- cardBootstrapPending,
1945
- effectiveCreateSession,
1946
- onButtonClick,
1947
- onBeforeButtonClick
1971
+ cardBootstrapPending
1948
1972
  ]);
1949
1973
  useEffect4(() => {
1950
1974
  let cancelled = false;
1951
1975
  setLoadError(null);
1952
1976
  if (createSessionHash) {
1953
- if (deferInlineSessionUntilCardClick) {
1954
- if (initializedHashRef.current !== createSessionHash) {
1955
- setSession(null);
1956
- setUnified(null);
1957
- setFloPay(null);
1958
- setResolvedSessionId("");
1959
- setDeferredCardOpen(false);
1960
- flopayRef.current = null;
1961
- }
1962
- setCurrentMode(createSessionParamsRef.current?.checkoutMode ?? checkoutModeProp ?? "full");
1963
- setIsLoading(false);
1964
- return () => {
1965
- cancelled = true;
1966
- };
1967
- }
1968
1977
  if (initializedHashRef.current === createSessionHash) return;
1969
1978
  const params = createSessionParamsRef.current;
1970
1979
  setSession(buildSyntheticSession(params, checkoutModeProp));
@@ -2060,7 +2069,7 @@ function FloPayCheckout({
2060
2069
  return () => {
2061
2070
  cancelled = true;
2062
2071
  };
2063
- }, [resolvedSessionId, createSessionHash, checkoutModeProp, deferInlineSessionUntilCardClick, bootstrapInlineSession]);
2072
+ }, [resolvedSessionId, createSessionHash, checkoutModeProp, bootstrapInlineSession]);
2064
2073
  const handleConfirmCheckout = useCallback2(async () => {
2065
2074
  if (confirmProcessing || !session) return;
2066
2075
  setConfirmProcessing(true);
@@ -2103,17 +2112,29 @@ function FloPayCheckout({
2103
2112
  }
2104
2113
  return opts;
2105
2114
  }, [unified, session, appearance, resolvedBillingUrl]);
2115
+ const shouldHandleInlineSessionPatch = Boolean(
2116
+ createSessionParams && !children && layout === "buttons" && onBeforeButtonClick && (effectiveCreateSession?.checkoutMode ?? checkoutModeProp ?? "full") === "full"
2117
+ );
2106
2118
  const checkoutValue = useMemo3(
2107
2119
  () => ({
2108
2120
  session,
2109
2121
  loading: isLoading,
2110
2122
  error: loadError,
2111
- checkoutMode: currentMode
2123
+ checkoutMode: currentMode,
2124
+ applyInlineSessionPatch: shouldHandleInlineSessionPatch ? handleInlineSessionPatch : void 0,
2125
+ inlineSessionPatchProcessing: cardBootstrapPending
2112
2126
  }),
2113
- [session, isLoading, loadError, currentMode]
2127
+ [
2128
+ session,
2129
+ isLoading,
2130
+ loadError,
2131
+ currentMode,
2132
+ shouldHandleInlineSessionPatch,
2133
+ handleInlineSessionPatch,
2134
+ cardBootstrapPending
2135
+ ]
2114
2136
  );
2115
2137
  const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && (!flopay || !providerOptions);
2116
- const shouldKeepDeferredInterimVisible = shouldShowInterimButtons && deferInlineSessionUntilCardClick;
2117
2138
  if (isLoading) {
2118
2139
  if (loadingNode) return /* @__PURE__ */ jsx5(Fragment3, { children: loadingNode });
2119
2140
  if (layout === "buttons") {
@@ -2142,7 +2163,7 @@ function FloPayCheckout({
2142
2163
  /* @__PURE__ */ jsx5("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
2143
2164
  ] });
2144
2165
  }
2145
- if (loadError && !shouldKeepDeferredInterimVisible) {
2166
+ if (loadError) {
2146
2167
  if (errorNode) return /* @__PURE__ */ jsx5(Fragment3, { children: errorNode(loadError) });
2147
2168
  return /* @__PURE__ */ jsx5(
2148
2169
  "div",
@@ -2162,13 +2183,9 @@ function FloPayCheckout({
2162
2183
  InterimButtonsView,
2163
2184
  {
2164
2185
  onButtonClick,
2165
- onCardButtonClick: deferInlineSessionUntilCardClick ? handleDeferredCardButtonClick : void 0,
2166
- cardLoading: cardBootstrapPending,
2167
- cardOpen: deferInlineSessionUntilCardClick ? deferredCardOpen : void 0,
2168
- errorMessage: shouldKeepDeferredInterimVisible ? loadError?.message ?? null : null,
2169
- showPayPal: deferInlineSessionUntilCardClick ? false : showPayPal,
2170
- showApplePay: deferInlineSessionUntilCardClick ? false : showApplePay,
2171
- showGooglePay: deferInlineSessionUntilCardClick ? false : showGooglePay,
2186
+ showPayPal,
2187
+ showApplePay,
2188
+ showGooglePay,
2172
2189
  buttonsTheme,
2173
2190
  buttonsStyles,
2174
2191
  cardButtonContent,
@@ -2255,6 +2272,7 @@ function FloPayCheckout({
2255
2272
  onComplete,
2256
2273
  onError,
2257
2274
  onDecline,
2275
+ onFullNameChange,
2258
2276
  showPayPal,
2259
2277
  showApplePay,
2260
2278
  showGooglePay,
@@ -2269,7 +2287,8 @@ function FloPayCheckout({
2269
2287
  enableAVS,
2270
2288
  avsLayout,
2271
2289
  country: session?.customer?.country,
2272
- initialCardOpen: deferredCardOpen,
2290
+ onCountryChange,
2291
+ onZipChange,
2273
2292
  submitLabel,
2274
2293
  className
2275
2294
  }