@flopay/react 0.3.17 → 0.3.19

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
@@ -102,10 +102,10 @@ interface FloPayCheckoutProps {
102
102
  */
103
103
  onButtonClick?: (method: CheckoutButtonMethod) => void;
104
104
  /**
105
- * Called before the credit/debit card button continues.
106
- * Card only: this does not run for PayPal or wallet buttons.
105
+ * Called before a payment button continues in `layout="buttons"`.
106
+ * Runs for card, PayPal, Apple Pay, and Google Pay.
107
107
  * In `layout="buttons"` with `createSession`, the returned patch is merged
108
- * into the inline session params before the real card session is created.
108
+ * into the inline session params before the selected flow continues.
109
109
  */
110
110
  onBeforeButtonClick?: (event: BeforeButtonClickEvent) => void | false | Promise<void | false | InlineSessionPatch> | InlineSessionPatch;
111
111
  /**
@@ -417,8 +417,8 @@ interface SplitCardFormProps {
417
417
  */
418
418
  onButtonClick?: (method: CheckoutButtonMethod) => void;
419
419
  /**
420
- * Called before the credit/debit card button continues.
421
- * Card only: this does not run for PayPal or wallet buttons.
420
+ * Called before a payment button continues in `layout="buttons"`.
421
+ * Runs for card, PayPal, Apple Pay, and Google Pay.
422
422
  */
423
423
  onBeforeButtonClick?: (event: BeforeButtonClickEvent) => MaybePromise<void | false | InlineSessionPatch>;
424
424
  /**
package/dist/index.d.ts CHANGED
@@ -102,10 +102,10 @@ interface FloPayCheckoutProps {
102
102
  */
103
103
  onButtonClick?: (method: CheckoutButtonMethod) => void;
104
104
  /**
105
- * Called before the credit/debit card button continues.
106
- * Card only: this does not run for PayPal or wallet buttons.
105
+ * Called before a payment button continues in `layout="buttons"`.
106
+ * Runs for card, PayPal, Apple Pay, and Google Pay.
107
107
  * In `layout="buttons"` with `createSession`, the returned patch is merged
108
- * into the inline session params before the real card session is created.
108
+ * into the inline session params before the selected flow continues.
109
109
  */
110
110
  onBeforeButtonClick?: (event: BeforeButtonClickEvent) => void | false | Promise<void | false | InlineSessionPatch> | InlineSessionPatch;
111
111
  /**
@@ -417,8 +417,8 @@ interface SplitCardFormProps {
417
417
  */
418
418
  onButtonClick?: (method: CheckoutButtonMethod) => void;
419
419
  /**
420
- * Called before the credit/debit card button continues.
421
- * Card only: this does not run for PayPal or wallet buttons.
420
+ * Called before a payment button continues in `layout="buttons"`.
421
+ * Runs for card, PayPal, Apple Pay, and Google Pay.
422
422
  */
423
423
  onBeforeButtonClick?: (event: BeforeButtonClickEvent) => MaybePromise<void | false | InlineSessionPatch>;
424
424
  /**
package/dist/index.mjs CHANGED
@@ -350,6 +350,25 @@ var FLOPAY_KEYFRAMES = `
350
350
  100% { opacity: 0; transform: translateX(16px) scale(0.97); }
351
351
  }
352
352
  `;
353
+ var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT = 44;
354
+ function getButtonMethodLabel(method) {
355
+ switch (method) {
356
+ case "paypal":
357
+ return "PayPal";
358
+ case "apple_pay":
359
+ return "Apple Pay";
360
+ case "google_pay":
361
+ return "Google Pay";
362
+ default:
363
+ return "Card";
364
+ }
365
+ }
366
+ function normalizeBeforeButtonClickError(method, err) {
367
+ return err instanceof FloPayError2 ? err : new FloPayError2(
368
+ err instanceof Error ? err.message : `${getButtonMethodLabel(method)} before-click hook failed.`,
369
+ "validation_error"
370
+ );
371
+ }
353
372
  function FloPayKeyframes() {
354
373
  return /* @__PURE__ */ jsx4("style", { children: FLOPAY_KEYFRAMES });
355
374
  }
@@ -520,13 +539,15 @@ function PayPalButtonInner({
520
539
  onErrorChange,
521
540
  isProcessing = false,
522
541
  onButtonClick,
523
- onDecline
542
+ onDecline,
543
+ runBeforeButtonClick
524
544
  }) {
525
545
  const stripe = useStripeRaw();
526
546
  const elements = useStripeElements();
527
547
  const [loadState, setLoadState] = useState2("loading");
528
548
  const [submitting, setSubmitting] = useState2(false);
529
549
  const paypalResumeAttempted = useRef2(false);
550
+ const beforeClickRef = useRef2(null);
530
551
  const baseUrl = billingApiUrl.replace(/\/+$/, "");
531
552
  useEffect3(() => {
532
553
  if (!stripe || paypalResumeAttempted.current) return;
@@ -575,13 +596,50 @@ function PayPalButtonInner({
575
596
  }
576
597
  })();
577
598
  }, [stripe, onTokenizedBody, onErrorChange, onDecline]);
578
- const handlePayPalConfirm = useCallback(async (_event) => {
599
+ const handlePayPalClick = useCallback(async (event) => {
600
+ if (isProcessing || submitting) {
601
+ event.reject();
602
+ return;
603
+ }
604
+ const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick("paypal", { deferInlineSessionPatch: true }) : { proceed: true };
605
+ if (!beforeClick.proceed) {
606
+ beforeClickRef.current = null;
607
+ event.reject();
608
+ return;
609
+ }
610
+ beforeClickRef.current = {
611
+ accountPatch: beforeClick.accountPatch,
612
+ pendingInlinePatch: beforeClick.pendingInlinePatch
613
+ };
614
+ event.resolve();
615
+ }, [isProcessing, runBeforeButtonClick, submitting]);
616
+ const handlePayPalConfirm = useCallback(async (event) => {
579
617
  if (!stripe || !elements) return;
618
+ let prepared = beforeClickRef.current;
619
+ beforeClickRef.current = null;
620
+ if (!prepared && runBeforeButtonClick) {
621
+ const beforeClick = await runBeforeButtonClick("paypal");
622
+ if (!beforeClick.proceed) {
623
+ event.paymentFailed({ reason: "fail", message: "PayPal checkout was cancelled." });
624
+ return;
625
+ }
626
+ prepared = {
627
+ accountPatch: beforeClick.accountPatch,
628
+ pendingInlinePatch: beforeClick.pendingInlinePatch ?? Promise.resolve({ error: null, sessionId: beforeClick.sessionId ?? sessionId })
629
+ };
630
+ }
631
+ const patchResult = prepared?.pendingInlinePatch ? await prepared.pendingInlinePatch : { error: null, sessionId };
632
+ if (patchResult.error) {
633
+ event.paymentFailed({ reason: "fail", message: patchResult.error.message });
634
+ return;
635
+ }
636
+ const effectiveSessionId = patchResult.sessionId ?? sessionId;
637
+ const effectiveEmail = prepared?.accountPatch?.email ?? email;
580
638
  onButtonClick?.("paypal");
581
639
  try {
582
640
  setSubmitting(true);
583
641
  onErrorChange?.(null);
584
- if (!sessionId || !email) {
642
+ if (!effectiveSessionId || !effectiveEmail) {
585
643
  throw new Error("Missing sessionId or email for PayPal payment");
586
644
  }
587
645
  const createPM = stripe.createPaymentMethod;
@@ -593,8 +651,8 @@ function PayPalButtonInner({
593
651
  method: "POST",
594
652
  headers: { "Content-Type": "application/json" },
595
653
  body: JSON.stringify({
596
- sessionId,
597
- email,
654
+ sessionId: effectiveSessionId,
655
+ email: effectiveEmail,
598
656
  paymentMethodType: paymentMethod?.id ?? "paypal",
599
657
  isPaypal: "true"
600
658
  })
@@ -628,21 +686,26 @@ function PayPalButtonInner({
628
686
  type: "card",
629
687
  threeDSecureActionResultTokenId: paymentIntent?.id,
630
688
  isPaypal: true
689
+ }, {
690
+ accountPatch: prepared?.accountPatch,
691
+ sessionId: effectiveSessionId
631
692
  });
632
693
  } catch (err) {
633
694
  onErrorChange?.(err instanceof Error ? err.message : "PayPal payment failed. Please try again.");
634
695
  } finally {
635
696
  setSubmitting(false);
636
697
  }
637
- }, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]);
698
+ }, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]);
638
699
  return /* @__PURE__ */ jsxs2(Fragment2, { children: [
639
700
  /* @__PURE__ */ jsx4(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ jsx4(
640
701
  ExpressCheckoutElement,
641
702
  {
642
703
  onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
643
704
  onLoadError: () => setLoadState("unavailable"),
705
+ onClick: handlePayPalClick,
644
706
  onConfirm: handlePayPalConfirm,
645
707
  onCancel: () => {
708
+ beforeClickRef.current = null;
646
709
  onDecline?.(buildDeclineEvent("paypal", "PayPal checkout was cancelled."));
647
710
  },
648
711
  options: {
@@ -668,7 +731,8 @@ function WalletButtonInner({
668
731
  onTokenizedBody,
669
732
  onErrorChange,
670
733
  onButtonClick,
671
- onDecline
734
+ onDecline,
735
+ runBeforeButtonClick
672
736
  }) {
673
737
  const stripe = useStripeRaw();
674
738
  const elements = useStripeElements();
@@ -676,10 +740,34 @@ function WalletButtonInner({
676
740
  const [submitting, setSubmitting] = useState2(false);
677
741
  const baseUrl = billingApiUrl.replace(/\/+$/, "");
678
742
  const lastWalletMethodRef = useRef2("card");
743
+ const beforeClickRef = useRef2(null);
679
744
  const handleWalletConfirm = useCallback(
680
- async (_event) => {
745
+ async (event) => {
681
746
  if (!stripe || !elements) return;
682
- const walletType = _event.expressPaymentType;
747
+ const walletType = event.expressPaymentType;
748
+ let prepared = beforeClickRef.current;
749
+ beforeClickRef.current = null;
750
+ if (!prepared && runBeforeButtonClick) {
751
+ const beforeClick = await runBeforeButtonClick(
752
+ walletType === "apple_pay" ? "apple_pay" : "google_pay"
753
+ );
754
+ if (!beforeClick.proceed) {
755
+ event.paymentFailed({ reason: "fail", message: "Wallet checkout was cancelled." });
756
+ return;
757
+ }
758
+ prepared = {
759
+ accountPatch: beforeClick.accountPatch,
760
+ pendingInlinePatch: beforeClick.pendingInlinePatch ?? Promise.resolve({ error: null, sessionId: beforeClick.sessionId ?? sessionId })
761
+ };
762
+ }
763
+ const patchResult = prepared?.pendingInlinePatch ? await prepared.pendingInlinePatch : { error: null, sessionId };
764
+ if (patchResult.error) {
765
+ event.paymentFailed({ reason: "fail", message: patchResult.error.message });
766
+ return;
767
+ }
768
+ const method = walletType === "apple_pay" ? "apple_pay" : "google_pay";
769
+ const effectiveSessionId = patchResult.sessionId ?? sessionId;
770
+ const effectiveEmail = prepared?.accountPatch?.email ?? email;
683
771
  onButtonClick?.(walletType === "apple_pay" ? "apple_pay" : "google_pay");
684
772
  try {
685
773
  setSubmitting(true);
@@ -694,15 +782,15 @@ function WalletButtonInner({
694
782
  onErrorChange?.(pmError?.message ?? "Failed to create payment method.");
695
783
  return;
696
784
  }
697
- if (!sessionId || !email) {
785
+ if (!effectiveSessionId || !effectiveEmail) {
698
786
  throw new Error("Missing sessionId or email for wallet payment");
699
787
  }
700
788
  const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
701
789
  method: "POST",
702
790
  headers: { "Content-Type": "application/json" },
703
791
  body: JSON.stringify({
704
- sessionId,
705
- email,
792
+ sessionId: effectiveSessionId,
793
+ email: effectiveEmail,
706
794
  paymentMethodType: paymentMethod.id,
707
795
  isPaypal: false
708
796
  })
@@ -716,7 +804,6 @@ function WalletButtonInner({
716
804
  { payment_method: paymentMethod.id }
717
805
  );
718
806
  if (confirmError) {
719
- const method = walletType === "apple_pay" ? "apple_pay" : "google_pay";
720
807
  const message = confirmError.message ?? "Wallet payment failed.";
721
808
  onErrorChange?.(message);
722
809
  onDecline?.(buildDeclineEvent(method, message, {
@@ -728,6 +815,9 @@ function WalletButtonInner({
728
815
  id: paymentMethod.id,
729
816
  type: "card",
730
817
  threeDSecureActionResultTokenId: paymentIntent?.id
818
+ }, {
819
+ accountPatch: prepared?.accountPatch,
820
+ sessionId: effectiveSessionId
731
821
  });
732
822
  } catch (err) {
733
823
  onErrorChange?.(err instanceof Error ? err.message : "Wallet payment failed. Please try again.");
@@ -735,7 +825,7 @@ function WalletButtonInner({
735
825
  setSubmitting(false);
736
826
  }
737
827
  },
738
- [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]
828
+ [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]
739
829
  );
740
830
  return /* @__PURE__ */ jsxs2(Fragment2, { children: [
741
831
  /* @__PURE__ */ jsx4(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ jsx4(
@@ -743,12 +833,23 @@ function WalletButtonInner({
743
833
  {
744
834
  onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["applePay", "googlePay"])),
745
835
  onLoadError: () => setLoadState("unavailable"),
746
- onClick: (event) => {
836
+ onClick: async (event) => {
747
837
  lastWalletMethodRef.current = event.expressPaymentType === "apple_pay" ? "apple_pay" : "google_pay";
838
+ const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick(lastWalletMethodRef.current, { deferInlineSessionPatch: true }) : { proceed: true };
839
+ if (!beforeClick.proceed) {
840
+ beforeClickRef.current = null;
841
+ event.reject();
842
+ return;
843
+ }
844
+ beforeClickRef.current = {
845
+ accountPatch: beforeClick.accountPatch,
846
+ pendingInlinePatch: beforeClick.pendingInlinePatch
847
+ };
748
848
  event.resolve();
749
849
  },
750
850
  onConfirm: handleWalletConfirm,
751
851
  onCancel: () => {
852
+ beforeClickRef.current = null;
752
853
  onDecline?.(buildDeclineEvent(lastWalletMethodRef.current, "Wallet checkout was cancelled."));
753
854
  },
754
855
  options: {
@@ -910,55 +1011,91 @@ function SplitCardFormInner({
910
1011
  onFirstNameChange?.(parts[0] ?? "");
911
1012
  onLastNameChange?.(parts.length > 1 ? parts.slice(1).join(" ") : "");
912
1013
  }, [onFullNameChange, onFirstNameChange, onLastNameChange]);
913
- const runBeforeCardButtonClick = useCallback(async () => {
914
- if (!onBeforeButtonClick) return true;
1014
+ const applyInlineSessionPatch = useCallback(
1015
+ (patch, method) => {
1016
+ if (!checkout.applyInlineSessionPatch) {
1017
+ return Promise.resolve({ error: null, sessionId });
1018
+ }
1019
+ return checkout.applyInlineSessionPatch(patch).then((result) => ({
1020
+ error: null,
1021
+ sessionId: result.sessionId || sessionId
1022
+ })).catch((err) => {
1023
+ const floPayErr = normalizeBeforeButtonClickError(method, err);
1024
+ updateError(floPayErr.message);
1025
+ onError?.(floPayErr);
1026
+ return { error: floPayErr, sessionId };
1027
+ });
1028
+ },
1029
+ [checkout.applyInlineSessionPatch, onError, sessionId, updateError]
1030
+ );
1031
+ const runBeforeButtonClick = useCallback(async (method, options) => {
1032
+ if (!onBeforeButtonClick) return { proceed: true };
915
1033
  try {
916
1034
  const result = await onBeforeButtonClick({
917
- method: "card",
918
- sessionId: sessionId || void 0
1035
+ method,
1036
+ sessionId: sessionId || void 0,
1037
+ createSession: checkout.inlineSessionDraft
919
1038
  });
920
1039
  if (result === false) {
921
- return false;
1040
+ return { proceed: false };
922
1041
  }
923
1042
  if (result && typeof result === "object") {
924
- await checkout.applyInlineSessionPatch?.(result);
925
1043
  if (result.account) {
926
1044
  setAccountPatch((prev) => ({ ...prev ?? {}, ...result.account }));
927
1045
  }
1046
+ const pendingInlinePatch = applyInlineSessionPatch(result, method);
1047
+ if (options?.deferInlineSessionPatch) {
1048
+ return {
1049
+ proceed: true,
1050
+ accountPatch: result.account,
1051
+ pendingInlinePatch
1052
+ };
1053
+ }
1054
+ const patchResult = await pendingInlinePatch;
1055
+ if (patchResult.error) {
1056
+ return {
1057
+ proceed: false,
1058
+ accountPatch: result.account
1059
+ };
1060
+ }
1061
+ return {
1062
+ proceed: true,
1063
+ accountPatch: result.account,
1064
+ sessionId: patchResult.sessionId
1065
+ };
928
1066
  }
929
- return true;
1067
+ return { proceed: true };
930
1068
  } catch (err) {
931
- const floPayErr = err instanceof FloPayError2 ? err : new FloPayError2(
932
- err instanceof Error ? err.message : "Card before-click hook failed.",
933
- "validation_error"
934
- );
1069
+ const floPayErr = normalizeBeforeButtonClickError(method, err);
935
1070
  updateError(floPayErr.message);
936
1071
  onError?.(floPayErr);
937
- return false;
1072
+ return { proceed: false };
938
1073
  }
939
- }, [checkout.applyInlineSessionPatch, onBeforeButtonClick, sessionId, updateError, onError]);
1074
+ }, [applyInlineSessionPatch, checkout.inlineSessionDraft, onBeforeButtonClick, onError, sessionId, updateError]);
940
1075
  const processPaymentInternal = useCallback(
941
- async (tokenizedBody) => {
1076
+ async (tokenizedBody, overrides) => {
942
1077
  if (processingRef.current) return;
943
1078
  processingRef.current = true;
944
1079
  setProcessing(true);
945
1080
  setOverlayStatus("processing");
946
1081
  updateError(null);
1082
+ const effectiveSessionId = overrides?.sessionId ?? sessionId;
1083
+ const effectiveAccount = mergeAccountPatch(resolvedAccount, overrides?.accountPatch);
947
1084
  try {
948
1085
  const response = await fetch(`${baseUrl}/v1/checkouts/sessions/process`, {
949
1086
  method: "POST",
950
1087
  headers: {
951
1088
  "Content-Type": "application/json",
952
- "x-user-id": resolvedAccount.userId ?? ""
1089
+ "x-user-id": effectiveAccount.userId ?? ""
953
1090
  },
954
1091
  body: JSON.stringify({
955
- sessionId,
1092
+ sessionId: effectiveSessionId,
956
1093
  tokenizedData: tokenizedBody,
957
1094
  accountData: {
958
- userId: resolvedAccount.userId ?? "",
959
- email: resolvedAccount.email ?? "",
960
- firstName: resolvedAccount.firstName ?? fullName.trim().split(/\s+/)[0] ?? "",
961
- lastName: resolvedAccount.lastName ?? fullName.trim().split(/\s+/).slice(1).join(" ") ?? "",
1095
+ userId: effectiveAccount.userId ?? "",
1096
+ email: effectiveAccount.email ?? "",
1097
+ firstName: effectiveAccount.firstName ?? fullName.trim().split(/\s+/)[0] ?? "",
1098
+ lastName: effectiveAccount.lastName ?? fullName.trim().split(/\s+/).slice(1).join(" ") ?? "",
962
1099
  ...enableAVS ? { zip: zipCodeRef.current, country: selectedCountryRef.current } : {}
963
1100
  },
964
1101
  chv
@@ -1067,11 +1204,11 @@ function SplitCardFormInner({
1067
1204
  [baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, onComplete, onError, updateError, emitDecline]
1068
1205
  );
1069
1206
  const dispatchTokenizedBody = useCallback(
1070
- (tokenizedBody) => {
1207
+ (tokenizedBody, overrides) => {
1071
1208
  if (onTokenizedBody) {
1072
1209
  onTokenizedBody(tokenizedBody);
1073
1210
  } else {
1074
- processPaymentInternal(tokenizedBody);
1211
+ processPaymentInternal(tokenizedBody, overrides);
1075
1212
  }
1076
1213
  },
1077
1214
  [onTokenizedBody, processPaymentInternal]
@@ -1498,6 +1635,7 @@ function SplitCardFormInner({
1498
1635
  if (layout === "buttons") {
1499
1636
  const isButtonsView = viewState === "buttons" || viewState === "expanding";
1500
1637
  const isCardView = viewState === "expanding" || viewState === "card" || viewState === "collapsing";
1638
+ const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
1501
1639
  const buttonsAnim = viewState === "expanding" ? `flopay-buttons-exit ${TRANSITION_MS}ms cubic-bezier(0.4, 0, 0.2, 1) both` : viewState === "collapsing" ? `flopay-buttons-enter ${TRANSITION_MS}ms cubic-bezier(0, 0, 0.2, 1) both` : void 0;
1502
1640
  const cardAnim = viewState === "expanding" ? `flopay-card-enter ${TRANSITION_MS}ms cubic-bezier(0, 0, 0.2, 1) both` : viewState === "collapsing" ? `flopay-card-exit ${TRANSITION_MS}ms cubic-bezier(0.4, 0, 0.2, 1) both` : void 0;
1503
1641
  return /* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
@@ -1523,9 +1661,10 @@ function SplitCardFormInner({
1523
1661
  onErrorChange: updateError,
1524
1662
  isProcessing: isSubmitting,
1525
1663
  onButtonClick,
1526
- onDecline
1664
+ onDecline,
1665
+ runBeforeButtonClick
1527
1666
  }
1528
- ) }) : showPayPal ? /* @__PURE__ */ jsx4("div", { style: { height: 44, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
1667
+ ) }) : showPayPal ? /* @__PURE__ */ jsx4("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
1529
1668
  showWallets && stripeInstance ? /* @__PURE__ */ jsx4(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx4(
1530
1669
  WalletButtonInner,
1531
1670
  {
@@ -1537,24 +1676,25 @@ function SplitCardFormInner({
1537
1676
  onTokenizedBody: dispatchTokenizedBody,
1538
1677
  onErrorChange: updateError,
1539
1678
  onButtonClick,
1540
- onDecline
1679
+ onDecline,
1680
+ runBeforeButtonClick
1541
1681
  }
1542
- ) }) : showWallets ? /* @__PURE__ */ jsx4("div", { style: { height: 44, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
1682
+ ) }) : showWallets ? /* @__PURE__ */ jsx4("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
1543
1683
  /* @__PURE__ */ jsx4(
1544
1684
  "button",
1545
1685
  {
1546
1686
  type: "button",
1547
1687
  onClick: async () => {
1548
1688
  if (isSubmitting) return;
1549
- const shouldContinue = await runBeforeCardButtonClick();
1550
- if (!shouldContinue) return;
1689
+ const beforeClick = await runBeforeButtonClick("card");
1690
+ if (!beforeClick.proceed) return;
1551
1691
  onButtonClick?.("card");
1552
1692
  expandToCard();
1553
1693
  },
1554
1694
  disabled: isSubmitting,
1555
1695
  style: {
1556
1696
  width: "100%",
1557
- padding: "0.9rem 1rem",
1697
+ ...cardButtonSizing,
1558
1698
  backgroundColor: "white",
1559
1699
  color: "#262833",
1560
1700
  border: "1px solid #d1d5db",
@@ -1653,6 +1793,7 @@ function SplitCardFormInner({
1653
1793
 
1654
1794
  // src/flopay-checkout.tsx
1655
1795
  import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1796
+ var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
1656
1797
  function hasInlineSessionPatchData(patch) {
1657
1798
  if (!patch) return false;
1658
1799
  return Boolean(
@@ -1959,16 +2100,27 @@ function FloPayCheckout({
1959
2100
  [fallbackPublishableKey, locale, resolvedBillingUrl]
1960
2101
  );
1961
2102
  const handleInlineSessionPatch = useCallback2(async (patch) => {
1962
- if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) return;
2103
+ if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) {
2104
+ return {
2105
+ sessionId: resolvedSessionId,
2106
+ session
2107
+ };
2108
+ }
1963
2109
  setCardBootstrapPending(true);
1964
2110
  try {
1965
- await bootstrapInlineSession(patch);
2111
+ const resolved = await bootstrapInlineSession(patch);
2112
+ return {
2113
+ sessionId: resolved.sid,
2114
+ session: resolved.result.data.session ?? null
2115
+ };
1966
2116
  } finally {
1967
2117
  setCardBootstrapPending(false);
1968
2118
  }
1969
2119
  }, [
1970
2120
  bootstrapInlineSession,
1971
- cardBootstrapPending
2121
+ cardBootstrapPending,
2122
+ resolvedSessionId,
2123
+ session
1972
2124
  ]);
1973
2125
  useEffect4(() => {
1974
2126
  let cancelled = false;
@@ -2121,6 +2273,7 @@ function FloPayCheckout({
2121
2273
  loading: isLoading,
2122
2274
  error: loadError,
2123
2275
  checkoutMode: currentMode,
2276
+ inlineSessionDraft: effectiveCreateSession,
2124
2277
  applyInlineSessionPatch: shouldHandleInlineSessionPatch ? handleInlineSessionPatch : void 0,
2125
2278
  inlineSessionPatchProcessing: cardBootstrapPending
2126
2279
  }),
@@ -2129,6 +2282,7 @@ function FloPayCheckout({
2129
2282
  isLoading,
2130
2283
  loadError,
2131
2284
  currentMode,
2285
+ effectiveCreateSession,
2132
2286
  shouldHandleInlineSessionPatch,
2133
2287
  handleInlineSessionPatch,
2134
2288
  cardBootstrapPending
@@ -2145,9 +2299,9 @@ function FloPayCheckout({
2145
2299
  animation: "flopay-loading-pulse 1.5s ease-in-out infinite"
2146
2300
  } });
2147
2301
  return /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
2148
- showPayPal && skeletonBar(44),
2149
- (showApplePay || showGooglePay) && skeletonBar(44),
2150
- skeletonBar(48),
2302
+ showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2303
+ (showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2304
+ skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2151
2305
  /* @__PURE__ */ jsx5("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
2152
2306
  ] });
2153
2307
  }
@@ -2361,6 +2515,7 @@ function InterimButtonsView({
2361
2515
  background: "#e5e7eb",
2362
2516
  animation: "flopay-interim-pulse 1.5s ease-in-out infinite"
2363
2517
  } });
2518
+ const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
2364
2519
  if (showCardForm) {
2365
2520
  const inputBorder = bStyles.cardInputBorder ?? "#e5e7eb";
2366
2521
  const inputBg = bStyles.cardInputBackground ?? "white";
@@ -2451,8 +2606,8 @@ function InterimButtonsView({
2451
2606
  ] });
2452
2607
  }
2453
2608
  return /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
2454
- showPayPal && skeleton(44),
2455
- (showApplePay || showGooglePay) && skeleton(44),
2609
+ showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2610
+ (showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2456
2611
  /* @__PURE__ */ jsx5(
2457
2612
  "button",
2458
2613
  {
@@ -2469,7 +2624,7 @@ function InterimButtonsView({
2469
2624
  disabled: cardLoading,
2470
2625
  style: {
2471
2626
  width: "100%",
2472
- padding: "0.9rem 1rem",
2627
+ ...cardButtonSizing,
2473
2628
  backgroundColor: "white",
2474
2629
  color: "#262833",
2475
2630
  border: "1px solid #d1d5db",