@flopay/react 0.3.15 → 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.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
  }
@@ -361,6 +380,52 @@ function toCssWeight(value) {
361
380
  if (typeof value === "number" || typeof value === "string") return value;
362
381
  return void 0;
363
382
  }
383
+ function resolveExpressCheckoutLoadState(event, methods) {
384
+ const available = event.availablePaymentMethods;
385
+ if (!available) return "unavailable";
386
+ return methods.some((method) => available[method]) ? "ready" : "unavailable";
387
+ }
388
+ function ExpressCheckoutReadySwap({
389
+ state,
390
+ placeholderTestId,
391
+ children
392
+ }) {
393
+ if (state === "unavailable") return null;
394
+ return /* @__PURE__ */ jsxs2("div", { style: { position: "relative", minHeight: 44 }, children: [
395
+ /* @__PURE__ */ jsx4(
396
+ "div",
397
+ {
398
+ "data-testid": placeholderTestId,
399
+ "aria-hidden": state === "ready",
400
+ style: {
401
+ position: "absolute",
402
+ inset: 0,
403
+ height: 44,
404
+ borderRadius: 8,
405
+ background: "#e5e7eb",
406
+ animation: state === "ready" ? void 0 : "flopay-pulse 1.5s ease-in-out infinite",
407
+ opacity: state === "ready" ? 0 : 1,
408
+ transform: state === "ready" ? "scale(0.985)" : "scale(1)",
409
+ transition: "opacity 140ms ease-out, transform 140ms ease-out",
410
+ pointerEvents: "none"
411
+ }
412
+ }
413
+ ),
414
+ /* @__PURE__ */ jsx4(
415
+ "div",
416
+ {
417
+ style: {
418
+ minHeight: 44,
419
+ opacity: state === "ready" ? 1 : 0,
420
+ transform: state === "ready" ? "translateY(0)" : "translateY(2px)",
421
+ transition: "opacity 140ms ease-out, transform 140ms ease-out",
422
+ pointerEvents: state === "ready" ? "auto" : "none"
423
+ },
424
+ children
425
+ }
426
+ )
427
+ ] });
428
+ }
364
429
  function ProcessingOverlay({ status, errorMessage }) {
365
430
  return /* @__PURE__ */ jsx4("div", { style: {
366
431
  position: "fixed",
@@ -474,13 +539,15 @@ function PayPalButtonInner({
474
539
  onErrorChange,
475
540
  isProcessing = false,
476
541
  onButtonClick,
477
- onDecline
542
+ onDecline,
543
+ runBeforeButtonClick
478
544
  }) {
479
545
  const stripe = useStripeRaw();
480
546
  const elements = useStripeElements();
481
- const [ready, setReady] = useState2(false);
547
+ const [loadState, setLoadState] = useState2("loading");
482
548
  const [submitting, setSubmitting] = useState2(false);
483
549
  const paypalResumeAttempted = useRef2(false);
550
+ const beforeClickRef = useRef2(null);
484
551
  const baseUrl = billingApiUrl.replace(/\/+$/, "");
485
552
  useEffect3(() => {
486
553
  if (!stripe || paypalResumeAttempted.current) return;
@@ -529,13 +596,50 @@ function PayPalButtonInner({
529
596
  }
530
597
  })();
531
598
  }, [stripe, onTokenizedBody, onErrorChange, onDecline]);
532
- 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) => {
533
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;
534
638
  onButtonClick?.("paypal");
535
639
  try {
536
640
  setSubmitting(true);
537
641
  onErrorChange?.(null);
538
- if (!sessionId || !email) {
642
+ if (!effectiveSessionId || !effectiveEmail) {
539
643
  throw new Error("Missing sessionId or email for PayPal payment");
540
644
  }
541
645
  const createPM = stripe.createPaymentMethod;
@@ -547,8 +651,8 @@ function PayPalButtonInner({
547
651
  method: "POST",
548
652
  headers: { "Content-Type": "application/json" },
549
653
  body: JSON.stringify({
550
- sessionId,
551
- email,
654
+ sessionId: effectiveSessionId,
655
+ email: effectiveEmail,
552
656
  paymentMethodType: paymentMethod?.id ?? "paypal",
553
657
  isPaypal: "true"
554
658
  })
@@ -582,22 +686,26 @@ function PayPalButtonInner({
582
686
  type: "card",
583
687
  threeDSecureActionResultTokenId: paymentIntent?.id,
584
688
  isPaypal: true
689
+ }, {
690
+ accountPatch: prepared?.accountPatch,
691
+ sessionId: effectiveSessionId
585
692
  });
586
693
  } catch (err) {
587
694
  onErrorChange?.(err instanceof Error ? err.message : "PayPal payment failed. Please try again.");
588
695
  } finally {
589
696
  setSubmitting(false);
590
697
  }
591
- }, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]);
698
+ }, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]);
592
699
  return /* @__PURE__ */ jsxs2(Fragment2, { children: [
593
- /* @__PURE__ */ jsx4("div", { children: /* @__PURE__ */ jsx4(
700
+ /* @__PURE__ */ jsx4(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ jsx4(
594
701
  ExpressCheckoutElement,
595
702
  {
596
- onReady: () => setReady(true),
597
- onLoadError: () => {
598
- },
703
+ onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
704
+ onLoadError: () => setLoadState("unavailable"),
705
+ onClick: handlePayPalClick,
599
706
  onConfirm: handlePayPalConfirm,
600
707
  onCancel: () => {
708
+ beforeClickRef.current = null;
601
709
  onDecline?.(buildDeclineEvent("paypal", "PayPal checkout was cancelled."));
602
710
  },
603
711
  options: {
@@ -623,18 +731,43 @@ function WalletButtonInner({
623
731
  onTokenizedBody,
624
732
  onErrorChange,
625
733
  onButtonClick,
626
- onDecline
734
+ onDecline,
735
+ runBeforeButtonClick
627
736
  }) {
628
737
  const stripe = useStripeRaw();
629
738
  const elements = useStripeElements();
630
- const [ready, setReady] = useState2(false);
739
+ const [loadState, setLoadState] = useState2("loading");
631
740
  const [submitting, setSubmitting] = useState2(false);
632
741
  const baseUrl = billingApiUrl.replace(/\/+$/, "");
633
742
  const lastWalletMethodRef = useRef2("card");
743
+ const beforeClickRef = useRef2(null);
634
744
  const handleWalletConfirm = useCallback(
635
- async (_event) => {
745
+ async (event) => {
636
746
  if (!stripe || !elements) return;
637
- 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;
638
771
  onButtonClick?.(walletType === "apple_pay" ? "apple_pay" : "google_pay");
639
772
  try {
640
773
  setSubmitting(true);
@@ -649,15 +782,15 @@ function WalletButtonInner({
649
782
  onErrorChange?.(pmError?.message ?? "Failed to create payment method.");
650
783
  return;
651
784
  }
652
- if (!sessionId || !email) {
785
+ if (!effectiveSessionId || !effectiveEmail) {
653
786
  throw new Error("Missing sessionId or email for wallet payment");
654
787
  }
655
788
  const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
656
789
  method: "POST",
657
790
  headers: { "Content-Type": "application/json" },
658
791
  body: JSON.stringify({
659
- sessionId,
660
- email,
792
+ sessionId: effectiveSessionId,
793
+ email: effectiveEmail,
661
794
  paymentMethodType: paymentMethod.id,
662
795
  isPaypal: false
663
796
  })
@@ -671,7 +804,6 @@ function WalletButtonInner({
671
804
  { payment_method: paymentMethod.id }
672
805
  );
673
806
  if (confirmError) {
674
- const method = walletType === "apple_pay" ? "apple_pay" : "google_pay";
675
807
  const message = confirmError.message ?? "Wallet payment failed.";
676
808
  onErrorChange?.(message);
677
809
  onDecline?.(buildDeclineEvent(method, message, {
@@ -683,6 +815,9 @@ function WalletButtonInner({
683
815
  id: paymentMethod.id,
684
816
  type: "card",
685
817
  threeDSecureActionResultTokenId: paymentIntent?.id
818
+ }, {
819
+ accountPatch: prepared?.accountPatch,
820
+ sessionId: effectiveSessionId
686
821
  });
687
822
  } catch (err) {
688
823
  onErrorChange?.(err instanceof Error ? err.message : "Wallet payment failed. Please try again.");
@@ -690,21 +825,31 @@ function WalletButtonInner({
690
825
  setSubmitting(false);
691
826
  }
692
827
  },
693
- [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline]
828
+ [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, onButtonClick, runBeforeButtonClick]
694
829
  );
695
830
  return /* @__PURE__ */ jsxs2(Fragment2, { children: [
696
- /* @__PURE__ */ jsx4("div", { children: /* @__PURE__ */ jsx4(
831
+ /* @__PURE__ */ jsx4(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ jsx4(
697
832
  ExpressCheckoutElement,
698
833
  {
699
- onReady: () => setReady(true),
700
- onLoadError: () => {
701
- },
702
- onClick: (event) => {
834
+ onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["applePay", "googlePay"])),
835
+ onLoadError: () => setLoadState("unavailable"),
836
+ onClick: async (event) => {
703
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
+ };
704
848
  event.resolve();
705
849
  },
706
850
  onConfirm: handleWalletConfirm,
707
851
  onCancel: () => {
852
+ beforeClickRef.current = null;
708
853
  onDecline?.(buildDeclineEvent(lastWalletMethodRef.current, "Wallet checkout was cancelled."));
709
854
  },
710
855
  options: {
@@ -742,6 +887,7 @@ function SplitCardFormInner({
742
887
  isProcessing: externalProcessing,
743
888
  error: externalError,
744
889
  onErrorChange,
890
+ onFullNameChange,
745
891
  onFirstNameChange,
746
892
  onLastNameChange,
747
893
  showPayPal = true,
@@ -860,59 +1006,96 @@ function SplitCardFormInner({
860
1006
  const showWallets = showApplePay || showGooglePay;
861
1007
  const handleNameChange = useCallback((value) => {
862
1008
  setFullName(value);
1009
+ onFullNameChange?.(value);
863
1010
  const parts = value.trim().split(/\s+/);
864
1011
  onFirstNameChange?.(parts[0] ?? "");
865
1012
  onLastNameChange?.(parts.length > 1 ? parts.slice(1).join(" ") : "");
866
- }, [onFirstNameChange, onLastNameChange]);
867
- const runBeforeCardButtonClick = useCallback(async () => {
868
- if (!onBeforeButtonClick) return true;
1013
+ }, [onFullNameChange, onFirstNameChange, onLastNameChange]);
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 };
869
1033
  try {
870
1034
  const result = await onBeforeButtonClick({
871
- method: "card",
872
- sessionId: sessionId || void 0
1035
+ method,
1036
+ sessionId: sessionId || void 0,
1037
+ createSession: checkout.inlineSessionDraft
873
1038
  });
874
1039
  if (result === false) {
875
- return false;
1040
+ return { proceed: false };
876
1041
  }
877
1042
  if (result && typeof result === "object") {
878
- await checkout.applyInlineSessionPatch?.(result);
879
1043
  if (result.account) {
880
1044
  setAccountPatch((prev) => ({ ...prev ?? {}, ...result.account }));
881
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
+ };
882
1066
  }
883
- return true;
1067
+ return { proceed: true };
884
1068
  } catch (err) {
885
- const floPayErr = err instanceof FloPayError2 ? err : new FloPayError2(
886
- err instanceof Error ? err.message : "Card before-click hook failed.",
887
- "validation_error"
888
- );
1069
+ const floPayErr = normalizeBeforeButtonClickError(method, err);
889
1070
  updateError(floPayErr.message);
890
1071
  onError?.(floPayErr);
891
- return false;
1072
+ return { proceed: false };
892
1073
  }
893
- }, [checkout.applyInlineSessionPatch, onBeforeButtonClick, sessionId, updateError, onError]);
1074
+ }, [applyInlineSessionPatch, checkout.inlineSessionDraft, onBeforeButtonClick, onError, sessionId, updateError]);
894
1075
  const processPaymentInternal = useCallback(
895
- async (tokenizedBody) => {
1076
+ async (tokenizedBody, overrides) => {
896
1077
  if (processingRef.current) return;
897
1078
  processingRef.current = true;
898
1079
  setProcessing(true);
899
1080
  setOverlayStatus("processing");
900
1081
  updateError(null);
1082
+ const effectiveSessionId = overrides?.sessionId ?? sessionId;
1083
+ const effectiveAccount = mergeAccountPatch(resolvedAccount, overrides?.accountPatch);
901
1084
  try {
902
1085
  const response = await fetch(`${baseUrl}/v1/checkouts/sessions/process`, {
903
1086
  method: "POST",
904
1087
  headers: {
905
1088
  "Content-Type": "application/json",
906
- "x-user-id": resolvedAccount.userId ?? ""
1089
+ "x-user-id": effectiveAccount.userId ?? ""
907
1090
  },
908
1091
  body: JSON.stringify({
909
- sessionId,
1092
+ sessionId: effectiveSessionId,
910
1093
  tokenizedData: tokenizedBody,
911
1094
  accountData: {
912
- userId: resolvedAccount.userId ?? "",
913
- email: resolvedAccount.email ?? "",
914
- firstName: resolvedAccount.firstName ?? fullName.trim().split(/\s+/)[0] ?? "",
915
- 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(" ") ?? "",
916
1099
  ...enableAVS ? { zip: zipCodeRef.current, country: selectedCountryRef.current } : {}
917
1100
  },
918
1101
  chv
@@ -1021,11 +1204,11 @@ function SplitCardFormInner({
1021
1204
  [baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, onComplete, onError, updateError, emitDecline]
1022
1205
  );
1023
1206
  const dispatchTokenizedBody = useCallback(
1024
- (tokenizedBody) => {
1207
+ (tokenizedBody, overrides) => {
1025
1208
  if (onTokenizedBody) {
1026
1209
  onTokenizedBody(tokenizedBody);
1027
1210
  } else {
1028
- processPaymentInternal(tokenizedBody);
1211
+ processPaymentInternal(tokenizedBody, overrides);
1029
1212
  }
1030
1213
  },
1031
1214
  [onTokenizedBody, processPaymentInternal]
@@ -1452,6 +1635,7 @@ function SplitCardFormInner({
1452
1635
  if (layout === "buttons") {
1453
1636
  const isButtonsView = viewState === "buttons" || viewState === "expanding";
1454
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" };
1455
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;
1456
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;
1457
1641
  return /* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
@@ -1477,9 +1661,10 @@ function SplitCardFormInner({
1477
1661
  onErrorChange: updateError,
1478
1662
  isProcessing: isSubmitting,
1479
1663
  onButtonClick,
1480
- onDecline
1664
+ onDecline,
1665
+ runBeforeButtonClick
1481
1666
  }
1482
- ) }) : 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,
1483
1668
  showWallets && stripeInstance ? /* @__PURE__ */ jsx4(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx4(
1484
1669
  WalletButtonInner,
1485
1670
  {
@@ -1491,24 +1676,25 @@ function SplitCardFormInner({
1491
1676
  onTokenizedBody: dispatchTokenizedBody,
1492
1677
  onErrorChange: updateError,
1493
1678
  onButtonClick,
1494
- onDecline
1679
+ onDecline,
1680
+ runBeforeButtonClick
1495
1681
  }
1496
- ) }) : 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,
1497
1683
  /* @__PURE__ */ jsx4(
1498
1684
  "button",
1499
1685
  {
1500
1686
  type: "button",
1501
1687
  onClick: async () => {
1502
1688
  if (isSubmitting) return;
1503
- const shouldContinue = await runBeforeCardButtonClick();
1504
- if (!shouldContinue) return;
1689
+ const beforeClick = await runBeforeButtonClick("card");
1690
+ if (!beforeClick.proceed) return;
1505
1691
  onButtonClick?.("card");
1506
1692
  expandToCard();
1507
1693
  },
1508
1694
  disabled: isSubmitting,
1509
1695
  style: {
1510
1696
  width: "100%",
1511
- padding: "0.9rem 1rem",
1697
+ ...cardButtonSizing,
1512
1698
  backgroundColor: "white",
1513
1699
  color: "#262833",
1514
1700
  border: "1px solid #d1d5db",
@@ -1607,6 +1793,7 @@ function SplitCardFormInner({
1607
1793
 
1608
1794
  // src/flopay-checkout.tsx
1609
1795
  import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1796
+ var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
1610
1797
  function hasInlineSessionPatchData(patch) {
1611
1798
  if (!patch) return false;
1612
1799
  return Boolean(
@@ -1625,6 +1812,9 @@ function FloPayCheckout({
1625
1812
  onComplete,
1626
1813
  onError,
1627
1814
  onDecline,
1815
+ onFullNameChange,
1816
+ onCountryChange,
1817
+ onZipChange,
1628
1818
  showPayPal = true,
1629
1819
  showApplePay = true,
1630
1820
  showGooglePay = true,
@@ -1910,16 +2100,27 @@ function FloPayCheckout({
1910
2100
  [fallbackPublishableKey, locale, resolvedBillingUrl]
1911
2101
  );
1912
2102
  const handleInlineSessionPatch = useCallback2(async (patch) => {
1913
- if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) return;
2103
+ if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) {
2104
+ return {
2105
+ sessionId: resolvedSessionId,
2106
+ session
2107
+ };
2108
+ }
1914
2109
  setCardBootstrapPending(true);
1915
2110
  try {
1916
- await bootstrapInlineSession(patch);
2111
+ const resolved = await bootstrapInlineSession(patch);
2112
+ return {
2113
+ sessionId: resolved.sid,
2114
+ session: resolved.result.data.session ?? null
2115
+ };
1917
2116
  } finally {
1918
2117
  setCardBootstrapPending(false);
1919
2118
  }
1920
2119
  }, [
1921
2120
  bootstrapInlineSession,
1922
- cardBootstrapPending
2121
+ cardBootstrapPending,
2122
+ resolvedSessionId,
2123
+ session
1923
2124
  ]);
1924
2125
  useEffect4(() => {
1925
2126
  let cancelled = false;
@@ -2072,6 +2273,7 @@ function FloPayCheckout({
2072
2273
  loading: isLoading,
2073
2274
  error: loadError,
2074
2275
  checkoutMode: currentMode,
2276
+ inlineSessionDraft: effectiveCreateSession,
2075
2277
  applyInlineSessionPatch: shouldHandleInlineSessionPatch ? handleInlineSessionPatch : void 0,
2076
2278
  inlineSessionPatchProcessing: cardBootstrapPending
2077
2279
  }),
@@ -2080,6 +2282,7 @@ function FloPayCheckout({
2080
2282
  isLoading,
2081
2283
  loadError,
2082
2284
  currentMode,
2285
+ effectiveCreateSession,
2083
2286
  shouldHandleInlineSessionPatch,
2084
2287
  handleInlineSessionPatch,
2085
2288
  cardBootstrapPending
@@ -2096,9 +2299,9 @@ function FloPayCheckout({
2096
2299
  animation: "flopay-loading-pulse 1.5s ease-in-out infinite"
2097
2300
  } });
2098
2301
  return /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
2099
- showPayPal && skeletonBar(44),
2100
- (showApplePay || showGooglePay) && skeletonBar(44),
2101
- 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),
2102
2305
  /* @__PURE__ */ jsx5("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
2103
2306
  ] });
2104
2307
  }
@@ -2223,6 +2426,7 @@ function FloPayCheckout({
2223
2426
  onComplete,
2224
2427
  onError,
2225
2428
  onDecline,
2429
+ onFullNameChange,
2226
2430
  showPayPal,
2227
2431
  showApplePay,
2228
2432
  showGooglePay,
@@ -2237,6 +2441,8 @@ function FloPayCheckout({
2237
2441
  enableAVS,
2238
2442
  avsLayout,
2239
2443
  country: session?.customer?.country,
2444
+ onCountryChange,
2445
+ onZipChange,
2240
2446
  submitLabel,
2241
2447
  className
2242
2448
  }
@@ -2309,6 +2515,7 @@ function InterimButtonsView({
2309
2515
  background: "#e5e7eb",
2310
2516
  animation: "flopay-interim-pulse 1.5s ease-in-out infinite"
2311
2517
  } });
2518
+ const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
2312
2519
  if (showCardForm) {
2313
2520
  const inputBorder = bStyles.cardInputBorder ?? "#e5e7eb";
2314
2521
  const inputBg = bStyles.cardInputBackground ?? "white";
@@ -2399,8 +2606,8 @@ function InterimButtonsView({
2399
2606
  ] });
2400
2607
  }
2401
2608
  return /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
2402
- showPayPal && skeleton(44),
2403
- (showApplePay || showGooglePay) && skeleton(44),
2609
+ showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2610
+ (showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
2404
2611
  /* @__PURE__ */ jsx5(
2405
2612
  "button",
2406
2613
  {
@@ -2417,7 +2624,7 @@ function InterimButtonsView({
2417
2624
  disabled: cardLoading,
2418
2625
  style: {
2419
2626
  width: "100%",
2420
- padding: "0.9rem 1rem",
2627
+ ...cardButtonSizing,
2421
2628
  backgroundColor: "white",
2422
2629
  color: "#262833",
2423
2630
  border: "1px solid #d1d5db",