@flopay/react 0.3.20 → 0.4.0

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
@@ -8,6 +8,12 @@ export { BeforeButtonClickEvent, CheckoutButtonMethod, DeclineEvent, InlineSessi
8
8
  interface FloPayProviderProps {
9
9
  /** A `FloPay` instance or a promise that resolves to one (from `loadFloPay()`). */
10
10
  flopay: Promise<FloPay> | FloPay;
11
+ /**
12
+ * Optional dedicated `FloPay` instance for PayPal, loaded with
13
+ * `gatewayData.paypalPublishableKey`. When omitted or `null`, PayPal is
14
+ * disabled (the button is not rendered).
15
+ */
16
+ paypalFlopay?: Promise<FloPay> | FloPay | null;
11
17
  /** Optional configuration applied when creating the elements group. */
12
18
  options?: {
13
19
  locale?: string;
@@ -35,7 +41,7 @@ interface FloPayProviderProps {
35
41
  * </FloPayProvider>
36
42
  * ```
37
43
  */
38
- declare function FloPayProvider({ flopay: floPayProp, options, children, }: FloPayProviderProps): React.ReactElement;
44
+ declare function FloPayProvider({ flopay: floPayProp, paypalFlopay: paypalFloPayProp, options, children, }: FloPayProviderProps): React.ReactElement;
39
45
 
40
46
  /** Props for the all-in-one `FloPayCheckout` wrapper. */
41
47
  interface FloPayCheckoutProps {
@@ -167,6 +173,14 @@ declare function FloPayCheckout({ sessionId: sessionIdProp, createSession: creat
167
173
  * Must be called within a `<FloPayProvider>`.
168
174
  */
169
175
  declare function useFloPay(): FloPay | null;
176
+ /**
177
+ * Returns the dedicated PayPal `FloPay` instance (loaded with
178
+ * `gatewayData.paypalPublishableKey`), or `null` if PayPal is disabled
179
+ * for this session.
180
+ *
181
+ * Must be called within a `<FloPayProvider>`.
182
+ */
183
+ declare function usePayPalFloPay(): FloPay | null;
170
184
  /**
171
185
  * Returns the current `FloPayElements` instance, or `null` if the
172
186
  * provider is still loading.
@@ -507,4 +521,4 @@ interface PayPalButtonProps {
507
521
  */
508
522
  declare function PayPalButton({ sessionId, billingApiUrl, email, userId, firstName, lastName, chv, onTokenizedBody, onComplete, onErrorChange, isProcessing, }: PayPalButtonProps): React.ReactElement;
509
523
 
510
- export { AddressElement, CardCvcElement, CardElement, CardExpiryElement, CardNumberElement, CheckoutForm, type CheckoutFormProps, type CheckoutFormRef, type CheckoutState, type ElementComponentProps, FloPayCheckout, type FloPayCheckoutProps, FloPayProvider, type FloPayProviderProps, PayPalButton, type PayPalButtonProps, PaymentElement, SplitCardForm, type SplitCardFormProps, type SplitCardFormRef, useCheckout, useElements, useFloPay };
524
+ export { AddressElement, CardCvcElement, CardElement, CardExpiryElement, CardNumberElement, CheckoutForm, type CheckoutFormProps, type CheckoutFormRef, type CheckoutState, type ElementComponentProps, FloPayCheckout, type FloPayCheckoutProps, FloPayProvider, type FloPayProviderProps, PayPalButton, type PayPalButtonProps, PaymentElement, SplitCardForm, type SplitCardFormProps, type SplitCardFormRef, useCheckout, useElements, useFloPay, usePayPalFloPay };
package/dist/index.d.ts CHANGED
@@ -8,6 +8,12 @@ export { BeforeButtonClickEvent, CheckoutButtonMethod, DeclineEvent, InlineSessi
8
8
  interface FloPayProviderProps {
9
9
  /** A `FloPay` instance or a promise that resolves to one (from `loadFloPay()`). */
10
10
  flopay: Promise<FloPay> | FloPay;
11
+ /**
12
+ * Optional dedicated `FloPay` instance for PayPal, loaded with
13
+ * `gatewayData.paypalPublishableKey`. When omitted or `null`, PayPal is
14
+ * disabled (the button is not rendered).
15
+ */
16
+ paypalFlopay?: Promise<FloPay> | FloPay | null;
11
17
  /** Optional configuration applied when creating the elements group. */
12
18
  options?: {
13
19
  locale?: string;
@@ -35,7 +41,7 @@ interface FloPayProviderProps {
35
41
  * </FloPayProvider>
36
42
  * ```
37
43
  */
38
- declare function FloPayProvider({ flopay: floPayProp, options, children, }: FloPayProviderProps): React.ReactElement;
44
+ declare function FloPayProvider({ flopay: floPayProp, paypalFlopay: paypalFloPayProp, options, children, }: FloPayProviderProps): React.ReactElement;
39
45
 
40
46
  /** Props for the all-in-one `FloPayCheckout` wrapper. */
41
47
  interface FloPayCheckoutProps {
@@ -167,6 +173,14 @@ declare function FloPayCheckout({ sessionId: sessionIdProp, createSession: creat
167
173
  * Must be called within a `<FloPayProvider>`.
168
174
  */
169
175
  declare function useFloPay(): FloPay | null;
176
+ /**
177
+ * Returns the dedicated PayPal `FloPay` instance (loaded with
178
+ * `gatewayData.paypalPublishableKey`), or `null` if PayPal is disabled
179
+ * for this session.
180
+ *
181
+ * Must be called within a `<FloPayProvider>`.
182
+ */
183
+ declare function usePayPalFloPay(): FloPay | null;
170
184
  /**
171
185
  * Returns the current `FloPayElements` instance, or `null` if the
172
186
  * provider is still loading.
@@ -507,4 +521,4 @@ interface PayPalButtonProps {
507
521
  */
508
522
  declare function PayPalButton({ sessionId, billingApiUrl, email, userId, firstName, lastName, chv, onTokenizedBody, onComplete, onErrorChange, isProcessing, }: PayPalButtonProps): React.ReactElement;
509
523
 
510
- export { AddressElement, CardCvcElement, CardElement, CardExpiryElement, CardNumberElement, CheckoutForm, type CheckoutFormProps, type CheckoutFormRef, type CheckoutState, type ElementComponentProps, FloPayCheckout, type FloPayCheckoutProps, FloPayProvider, type FloPayProviderProps, PayPalButton, type PayPalButtonProps, PaymentElement, SplitCardForm, type SplitCardFormProps, type SplitCardFormRef, useCheckout, useElements, useFloPay };
524
+ export { AddressElement, CardCvcElement, CardElement, CardExpiryElement, CardNumberElement, CheckoutForm, type CheckoutFormProps, type CheckoutFormRef, type CheckoutState, type ElementComponentProps, FloPayCheckout, type FloPayCheckoutProps, FloPayProvider, type FloPayProviderProps, PayPalButton, type PayPalButtonProps, PaymentElement, SplitCardForm, type SplitCardFormProps, type SplitCardFormRef, useCheckout, useElements, useFloPay, usePayPalFloPay };
package/dist/index.mjs CHANGED
@@ -6,6 +6,7 @@ import { resolveBillingApiUrl } from "@flopay/shared";
6
6
  import { createContext } from "react";
7
7
  var FloPayContext = createContext({
8
8
  flopay: null,
9
+ paypalFlopay: null,
9
10
  elements: null,
10
11
  billingApiUrl: ""
11
12
  });
@@ -19,12 +20,16 @@ var CheckoutContext = createContext({
19
20
  import { jsx } from "react/jsx-runtime";
20
21
  function FloPayProvider({
21
22
  flopay: floPayProp,
23
+ paypalFlopay: paypalFloPayProp,
22
24
  options,
23
25
  children
24
26
  }) {
25
27
  const [flopay, setFloPay] = useState(
26
28
  floPayProp instanceof Promise ? null : floPayProp
27
29
  );
30
+ const [paypalFlopay, setPaypalFloPay] = useState(
31
+ paypalFloPayProp instanceof Promise || !paypalFloPayProp ? null : paypalFloPayProp
32
+ );
28
33
  const [elements, setElements] = useState(null);
29
34
  useEffect(() => {
30
35
  let cancelled = false;
@@ -41,6 +46,25 @@ function FloPayProvider({
41
46
  cancelled = true;
42
47
  };
43
48
  }, [floPayProp]);
49
+ useEffect(() => {
50
+ let cancelled = false;
51
+ if (!paypalFloPayProp) {
52
+ setPaypalFloPay(null);
53
+ return;
54
+ }
55
+ if (paypalFloPayProp instanceof Promise) {
56
+ paypalFloPayProp.then((instance) => {
57
+ if (!cancelled) {
58
+ setPaypalFloPay(instance);
59
+ }
60
+ });
61
+ } else {
62
+ setPaypalFloPay(paypalFloPayProp);
63
+ }
64
+ return () => {
65
+ cancelled = true;
66
+ };
67
+ }, [paypalFloPayProp]);
44
68
  useEffect(() => {
45
69
  if (!flopay) {
46
70
  setElements(null);
@@ -60,8 +84,8 @@ function FloPayProvider({
60
84
  }, [flopay, options?.appearance, options?.clientSecret, options?.amount, options?.currency]);
61
85
  const resolvedBillingApiUrl = resolveBillingApiUrl(options?.billingApiUrl);
62
86
  const value = useMemo(
63
- () => ({ flopay, elements, billingApiUrl: resolvedBillingApiUrl }),
64
- [flopay, elements, resolvedBillingApiUrl]
87
+ () => ({ flopay, paypalFlopay, elements, billingApiUrl: resolvedBillingApiUrl }),
88
+ [flopay, paypalFlopay, elements, resolvedBillingApiUrl]
65
89
  );
66
90
  return /* @__PURE__ */ jsx(FloPayContext.Provider, { value, children });
67
91
  }
@@ -215,6 +239,10 @@ function useFloPay() {
215
239
  const ctx = useContext2(FloPayContext);
216
240
  return ctx.flopay;
217
241
  }
242
+ function usePayPalFloPay() {
243
+ const ctx = useContext2(FloPayContext);
244
+ return ctx.paypalFlopay ?? null;
245
+ }
218
246
  function useElements() {
219
247
  const ctx = useContext2(FloPayContext);
220
248
  return ctx.elements;
@@ -903,6 +931,7 @@ function SplitCardFormInner({
903
931
  innerRef
904
932
  }) {
905
933
  const flopay = useFloPay();
934
+ const paypalFlopay = usePayPalFloPay();
906
935
  const elements = useElements();
907
936
  const checkout = useContext3(CheckoutContext);
908
937
  const contextBillingUrl = useBillingApiUrl();
@@ -966,6 +995,10 @@ function SplitCardFormInner({
966
995
  if (!flopay) return null;
967
996
  return flopay.getRawProvider();
968
997
  }, [flopay]);
998
+ const paypalStripeInstance = useMemo2(() => {
999
+ if (!paypalFlopay) return null;
1000
+ return paypalFlopay.getRawProvider();
1001
+ }, [paypalFlopay]);
969
1002
  const amountInCents = totalAmount || 100;
970
1003
  const walletOptions = useMemo2(() => ({
971
1004
  mode: "payment",
@@ -1135,9 +1168,9 @@ function SplitCardFormInner({
1135
1168
  return;
1136
1169
  }
1137
1170
  try {
1138
- const stripeInstance2 = flopay.getRawProvider();
1139
- if (!stripeInstance2) {
1140
- updateError("Payment provider not available.");
1171
+ const paypalStripe = paypalFlopay?.getRawProvider();
1172
+ if (!paypalStripe) {
1173
+ updateError("PayPal is not available.");
1141
1174
  return;
1142
1175
  }
1143
1176
  const confirmParams = {
@@ -1146,7 +1179,7 @@ function SplitCardFormInner({
1146
1179
  if (savedPmId) {
1147
1180
  confirmParams["payment_method"] = savedPmId;
1148
1181
  }
1149
- const { error: confirmError } = await stripeInstance2.confirmPayment({
1182
+ const { error: confirmError } = await paypalStripe.confirmPayment({
1150
1183
  clientSecret: secret,
1151
1184
  confirmParams,
1152
1185
  redirect: "if_required"
@@ -1183,7 +1216,7 @@ function SplitCardFormInner({
1183
1216
  processingRef.current = false;
1184
1217
  }
1185
1218
  },
1186
- [baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, onComplete, onError, updateError, emitDecline]
1219
+ [baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, paypalFlopay, onComplete, onError, updateError, emitDecline]
1187
1220
  );
1188
1221
  const dispatchTokenizedBody = useCallback(
1189
1222
  (tokenizedBody, overrides) => {
@@ -1633,7 +1666,7 @@ function SplitCardFormInner({
1633
1666
  ...!isButtonsView && !buttonsAnim ? { visibility: "hidden", position: "absolute", pointerEvents: "none", width: "100%" } : {},
1634
1667
  ...buttonsAnim ? { animation: buttonsAnim, pointerEvents: "none" } : {}
1635
1668
  }, children: [
1636
- showPayPal && stripeInstance ? /* @__PURE__ */ jsx4(StripeElements, { stripe: stripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx4(
1669
+ showPayPal && paypalStripeInstance && /* @__PURE__ */ jsx4(StripeElements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx4(
1637
1670
  PayPalButtonInner,
1638
1671
  {
1639
1672
  sessionId,
@@ -1646,7 +1679,7 @@ function SplitCardFormInner({
1646
1679
  onDecline,
1647
1680
  runBeforeButtonClick
1648
1681
  }
1649
- ) }) : 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,
1682
+ ) }),
1650
1683
  showWallets && stripeInstance ? /* @__PURE__ */ jsx4(StripeElements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ jsx4(
1651
1684
  WalletButtonInner,
1652
1685
  {
@@ -1745,7 +1778,7 @@ function SplitCardFormInner({
1745
1778
  onDecline
1746
1779
  }
1747
1780
  ) }),
1748
- showPayPal && stripeInstance && /* @__PURE__ */ jsx4(StripeElements, { stripe: stripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx4(
1781
+ showPayPal && paypalStripeInstance && /* @__PURE__ */ jsx4(StripeElements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ jsx4(
1749
1782
  PayPalButtonInner,
1750
1783
  {
1751
1784
  sessionId,
@@ -1757,7 +1790,7 @@ function SplitCardFormInner({
1757
1790
  onDecline
1758
1791
  }
1759
1792
  ) }),
1760
- (showWallets && stripeInstance || showPayPal && stripeInstance) && /* @__PURE__ */ jsxs2("div", { style: {
1793
+ (showWallets && stripeInstance || showPayPal && paypalStripeInstance) && /* @__PURE__ */ jsxs2("div", { style: {
1761
1794
  display: "flex",
1762
1795
  alignItems: "center",
1763
1796
  gap: "0.75rem",
@@ -1822,6 +1855,8 @@ function FloPayCheckout({
1822
1855
  const [unified, setUnified] = useState3(null);
1823
1856
  const [flopay, setFloPay] = useState3(null);
1824
1857
  const flopayRef = useRef3(null);
1858
+ const [paypalFlopay, setPaypalFloPay] = useState3(null);
1859
+ const paypalFlopayRef = useRef3(null);
1825
1860
  const [session, setSession] = useState3(null);
1826
1861
  const [resolvedSessionId, setResolvedSessionId] = useState3(sessionIdProp ?? "");
1827
1862
  const [isLoading, setIsLoading] = useState3(true);
@@ -1939,13 +1974,18 @@ function FloPayCheckout({
1939
1974
  return false;
1940
1975
  }
1941
1976
  if (redirectResult.type === "paypal_redirect_required") {
1977
+ const paypalStripe = paypalFlopayRef.current?.getRawProvider();
1978
+ if (!paypalStripe) {
1979
+ setModeError("PayPal is not available.");
1980
+ return false;
1981
+ }
1942
1982
  const confirmParams = {
1943
1983
  return_url: window.location.href
1944
1984
  };
1945
1985
  if (redirectResult.paymentMethodId) {
1946
1986
  confirmParams["payment_method"] = redirectResult.paymentMethodId;
1947
1987
  }
1948
- const { error } = await stripe.confirmPayment({
1988
+ const { error } = await paypalStripe.confirmPayment({
1949
1989
  clientSecret: redirectResult.threeDSecureToken,
1950
1990
  confirmParams,
1951
1991
  redirect: "if_required"
@@ -2054,8 +2094,10 @@ function FloPayCheckout({
2054
2094
  setResolvedSessionId(sid);
2055
2095
  }
2056
2096
  let publishableKey;
2097
+ let paypalPublishableKey;
2057
2098
  if (realResult.provider === "stripe") {
2058
2099
  publishableKey = realResult.data.stripe?.publishableKey;
2100
+ paypalPublishableKey = realResult.data.stripe?.paypalPublishableKey;
2059
2101
  }
2060
2102
  if (!publishableKey) publishableKey = fallbackPublishableKey;
2061
2103
  if (!publishableKey) {
@@ -2064,12 +2106,30 @@ function FloPayCheckout({
2064
2106
  "validation_error"
2065
2107
  );
2066
2108
  }
2067
- const instance = await loadFloPay(publishableKey, {
2068
- billingApiUrl: resolvedBillingUrl,
2069
- locale
2070
- });
2109
+ const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
2110
+ const [instance, paypalInstanceOrError] = await Promise.all([
2111
+ loadFloPay(publishableKey, {
2112
+ billingApiUrl: resolvedBillingUrl,
2113
+ locale
2114
+ }),
2115
+ needsSeparatePaypal ? loadFloPay(paypalPublishableKey, {
2116
+ billingApiUrl: resolvedBillingUrl,
2117
+ locale
2118
+ }).catch((err) => {
2119
+ console.warn("[FloPay] Failed to load PayPal Stripe instance:", err);
2120
+ return null;
2121
+ }) : Promise.resolve(null)
2122
+ ]);
2071
2123
  flopayRef.current = instance;
2072
2124
  setFloPay(instance);
2125
+ if (paypalPublishableKey) {
2126
+ const paypalInstance = needsSeparatePaypal ? paypalInstanceOrError : instance;
2127
+ paypalFlopayRef.current = paypalInstance;
2128
+ setPaypalFloPay(paypalInstance);
2129
+ } else {
2130
+ paypalFlopayRef.current = null;
2131
+ setPaypalFloPay(null);
2132
+ }
2073
2133
  setIsLoading(false);
2074
2134
  } catch (err) {
2075
2135
  if (initializedHashRef.current === cacheKey) {
@@ -2182,8 +2242,10 @@ function FloPayCheckout({
2182
2242
  }
2183
2243
  async function initStripe(result) {
2184
2244
  let publishableKey;
2245
+ let paypalPublishableKey;
2185
2246
  if (result.provider === "stripe") {
2186
2247
  publishableKey = result.data.stripe?.publishableKey;
2248
+ paypalPublishableKey = result.data.stripe?.paypalPublishableKey;
2187
2249
  }
2188
2250
  if (!publishableKey) publishableKey = fallbackPublishableKey;
2189
2251
  if (!publishableKey) {
@@ -2192,12 +2254,30 @@ function FloPayCheckout({
2192
2254
  "validation_error"
2193
2255
  );
2194
2256
  }
2195
- const instance = await loadFloPay(publishableKey, {
2196
- billingApiUrl: resolvedBillingUrl,
2197
- locale
2198
- });
2257
+ const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
2258
+ const [instance, paypalInstanceOrError] = await Promise.all([
2259
+ loadFloPay(publishableKey, {
2260
+ billingApiUrl: resolvedBillingUrl,
2261
+ locale
2262
+ }),
2263
+ needsSeparatePaypal ? loadFloPay(paypalPublishableKey, {
2264
+ billingApiUrl: resolvedBillingUrl,
2265
+ locale
2266
+ }).catch((err) => {
2267
+ console.warn("[FloPay] Failed to load PayPal Stripe instance:", err);
2268
+ return null;
2269
+ }) : Promise.resolve(null)
2270
+ ]);
2199
2271
  flopayRef.current = instance;
2200
2272
  setFloPay(instance);
2273
+ if (paypalPublishableKey) {
2274
+ const paypalInstance = needsSeparatePaypal ? paypalInstanceOrError : instance;
2275
+ paypalFlopayRef.current = paypalInstance;
2276
+ setPaypalFloPay(paypalInstance);
2277
+ } else {
2278
+ paypalFlopayRef.current = null;
2279
+ setPaypalFloPay(null);
2280
+ }
2201
2281
  }
2202
2282
  init();
2203
2283
  return () => {
@@ -2332,7 +2412,7 @@ function FloPayCheckout({
2332
2412
  }
2333
2413
  if (!flopay || !providerOptions) return /* @__PURE__ */ jsx5(Fragment3, {});
2334
2414
  if (currentMode === "confirm") {
2335
- return /* @__PURE__ */ jsx5(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx5(FloPayProvider, { flopay, options: providerOptions, children: /* @__PURE__ */ jsxs3("div", { className, children: [
2415
+ return /* @__PURE__ */ jsx5(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ jsx5(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: /* @__PURE__ */ jsxs3("div", { className, children: [
2336
2416
  modeError && /* @__PURE__ */ jsx5(
2337
2417
  "div",
2338
2418
  {
@@ -3163,6 +3243,7 @@ export {
3163
3243
  SplitCardForm,
3164
3244
  useCheckout,
3165
3245
  useElements,
3166
- useFloPay
3246
+ useFloPay,
3247
+ usePayPalFloPay
3167
3248
  };
3168
3249
  //# sourceMappingURL=index.mjs.map