@crediball/react 0.1.0 → 0.3.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/CrediballProvider.d.ts +19 -2
- package/dist/CrediballProvider.js +32 -7
- package/dist/PaywallModal.d.ts +26 -3
- package/dist/PaywallModal.js +6 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/usePaywall.d.ts +60 -0
- package/dist/usePaywall.js +44 -0
- package/package.json +1 -1
|
@@ -16,6 +16,10 @@ export interface CrediballProviderProps {
|
|
|
16
16
|
* `{ code: "insufficient_credits" }`) from any fetch() call and open the paywall
|
|
17
17
|
* automatically — no per-call wiring. Defaults to true. Set false to only open
|
|
18
18
|
* the paywall manually via useCrediball().showPaywall().
|
|
19
|
+
*
|
|
20
|
+
* Note: this only intercepts responses with HTTP 402. Streaming (SSE) routes that
|
|
21
|
+
* surface credit errors as stream events will not be caught automatically — call
|
|
22
|
+
* showPaywall() manually from your SSE error handler in those cases.
|
|
19
23
|
*/
|
|
20
24
|
watchFetch?: boolean;
|
|
21
25
|
/** Allow a free-form amount entry in the paywall. */
|
|
@@ -30,7 +34,11 @@ export interface CrediballProviderProps {
|
|
|
30
34
|
accentColor?: string;
|
|
31
35
|
}
|
|
32
36
|
interface CrediballContextValue {
|
|
33
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* Open the paywall modal. Always safe to call — never guard with "already shown"
|
|
39
|
+
* state. Calling while already open is a no-op; dismissing via "Not now" does not
|
|
40
|
+
* prevent the next showPaywall() call from reopening it.
|
|
41
|
+
*/
|
|
34
42
|
showPaywall: () => void;
|
|
35
43
|
/** Close the paywall modal. */
|
|
36
44
|
hidePaywall: () => void;
|
|
@@ -47,8 +55,17 @@ interface CrediballContextValue {
|
|
|
47
55
|
* Whenever any request returns 402 `insufficient_credits` (your server forwarding
|
|
48
56
|
* Crediball's error), the paywall appears automatically — no extra code per call.
|
|
49
57
|
* You can also open it yourself with useCrediball().showPaywall().
|
|
58
|
+
*
|
|
59
|
+
* For SSE/streaming routes: the 402 is surfaced as a stream event, not an HTTP status,
|
|
60
|
+
* so watchFetch won't catch it. Call showPaywall() manually from your SSE error handler.
|
|
50
61
|
*/
|
|
51
62
|
export declare function CrediballProvider({ children, amounts, onTopup, watchFetch, allowCustom, customMin, customMax, currencySymbol, title, description, accentColor, }: CrediballProviderProps): import("react").JSX.Element;
|
|
52
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* Access the paywall controls from anywhere inside <CrediballProvider>.
|
|
65
|
+
*
|
|
66
|
+
* Important: showPaywall() is always safe to call — never add a "paywallAlreadyShown"
|
|
67
|
+
* guard around it. Dismissing the modal ("Not now") does not prevent future calls
|
|
68
|
+
* from reopening it. Call showPaywall() unconditionally on every InsufficientCreditsError.
|
|
69
|
+
*/
|
|
53
70
|
export declare function useCrediball(): CrediballContextValue;
|
|
54
71
|
export {};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from "react";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
|
|
4
4
|
import { PaywallModal } from "./PaywallModal";
|
|
5
5
|
const CrediballContext = createContext(null);
|
|
6
|
+
// Symbol used to mark a patched fetch so double-mount in React Strict Mode (dev)
|
|
7
|
+
// or a second <CrediballProvider> doesn't stack intercepts.
|
|
8
|
+
const CREDIBALL_FETCH_PATCHED = Symbol.for("crediball.fetch.patched");
|
|
6
9
|
/**
|
|
7
10
|
* Pattern B, automated. Wrap your app once:
|
|
8
11
|
*
|
|
@@ -13,35 +16,51 @@ const CrediballContext = createContext(null);
|
|
|
13
16
|
* Whenever any request returns 402 `insufficient_credits` (your server forwarding
|
|
14
17
|
* Crediball's error), the paywall appears automatically — no extra code per call.
|
|
15
18
|
* You can also open it yourself with useCrediball().showPaywall().
|
|
19
|
+
*
|
|
20
|
+
* For SSE/streaming routes: the 402 is surfaced as a stream event, not an HTTP status,
|
|
21
|
+
* so watchFetch won't catch it. Call showPaywall() manually from your SSE error handler.
|
|
16
22
|
*/
|
|
17
23
|
export function CrediballProvider({ children, amounts = [5, 10, 20], onTopup, watchFetch = true, allowCustom = false, customMin, customMax, currencySymbol = "€", title, description, accentColor, }) {
|
|
18
24
|
const [open, setOpen] = useState(false);
|
|
25
|
+
// Stable callback refs so the fetch interceptor closure doesn't go stale.
|
|
19
26
|
const showPaywall = useCallback(() => setOpen(true), []);
|
|
20
27
|
const hidePaywall = useCallback(() => setOpen(false), []);
|
|
21
|
-
|
|
22
|
-
|
|
28
|
+
const showPaywallRef = useRef(showPaywall);
|
|
29
|
+
showPaywallRef.current = showPaywall;
|
|
23
30
|
useEffect(() => {
|
|
24
31
|
if (!watchFetch || typeof window === "undefined")
|
|
25
32
|
return;
|
|
33
|
+
// If another provider (or a double-invoke from React Strict Mode) already
|
|
34
|
+
// patched this window.fetch in the same tick, skip — the cleanup will restore.
|
|
35
|
+
const win = window;
|
|
36
|
+
if (win[CREDIBALL_FETCH_PATCHED])
|
|
37
|
+
return;
|
|
26
38
|
const original = window.fetch;
|
|
39
|
+
win[CREDIBALL_FETCH_PATCHED] = true;
|
|
27
40
|
window.fetch = async (...args) => {
|
|
28
41
|
const res = await original(...args);
|
|
29
42
|
if (res.status === 402) {
|
|
43
|
+
// Clone so the original response body is still readable by the caller.
|
|
30
44
|
res
|
|
31
45
|
.clone()
|
|
32
46
|
.json()
|
|
33
47
|
.then((body) => {
|
|
34
|
-
if (body && body.code === "insufficient_credits")
|
|
35
|
-
|
|
48
|
+
if (body && body.code === "insufficient_credits") {
|
|
49
|
+
showPaywallRef.current();
|
|
50
|
+
}
|
|
36
51
|
})
|
|
37
52
|
.catch(() => {
|
|
38
|
-
|
|
53
|
+
// Non-JSON 402 (e.g. Stripe webhook): open paywall anyway since any
|
|
54
|
+
// 402 from the app's own API routes is very likely a credit shortage.
|
|
55
|
+
// If the app has other 402 uses, set watchFetch=false and call
|
|
56
|
+
// showPaywall() manually.
|
|
39
57
|
});
|
|
40
58
|
}
|
|
41
59
|
return res;
|
|
42
60
|
};
|
|
43
61
|
return () => {
|
|
44
62
|
window.fetch = original;
|
|
63
|
+
delete win[CREDIBALL_FETCH_PATCHED];
|
|
45
64
|
};
|
|
46
65
|
}, [watchFetch]);
|
|
47
66
|
const ctx = useMemo(() => ({ showPaywall, hidePaywall, open }), [showPaywall, hidePaywall, open]);
|
|
@@ -55,7 +74,13 @@ export function CrediballProvider({ children, amounts = [5, 10, 20], onTopup, wa
|
|
|
55
74
|
}
|
|
56
75
|
return (_jsxs(CrediballContext.Provider, { value: ctx, children: [children, _jsx(PaywallModal, { open: open, amounts: amounts, amountPrefix: `Add ${currencySymbol}`, onAdd: handleAdd, onClose: hidePaywall, allowCustom: allowCustom, customMin: customMin, customMax: customMax, currencySymbol: currencySymbol, title: title, description: description, accentColor: accentColor })] }));
|
|
57
76
|
}
|
|
58
|
-
/**
|
|
77
|
+
/**
|
|
78
|
+
* Access the paywall controls from anywhere inside <CrediballProvider>.
|
|
79
|
+
*
|
|
80
|
+
* Important: showPaywall() is always safe to call — never add a "paywallAlreadyShown"
|
|
81
|
+
* guard around it. Dismissing the modal ("Not now") does not prevent future calls
|
|
82
|
+
* from reopening it. Call showPaywall() unconditionally on every InsufficientCreditsError.
|
|
83
|
+
*/
|
|
59
84
|
export function useCrediball() {
|
|
60
85
|
const ctx = useContext(CrediballContext);
|
|
61
86
|
if (!ctx) {
|
package/dist/PaywallModal.d.ts
CHANGED
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
import { type CSSProperties } from "react";
|
|
2
2
|
import { type CrediballThemeOverrides } from "./theme";
|
|
3
|
+
/** A purchasable credit bundle from the Crediball dashboard (returned by listPackages()). */
|
|
4
|
+
export interface PackageOption {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
price: number;
|
|
8
|
+
credits: number;
|
|
9
|
+
}
|
|
3
10
|
export interface PaywallModalProps extends CrediballThemeOverrides {
|
|
4
11
|
open: boolean;
|
|
5
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Preferred: pass the packages from `meter.listPackages()` so Crediball can
|
|
14
|
+
* resolve credits and record revenue automatically when the user checks out.
|
|
15
|
+
* The modal renders one button per package (e.g. "Starter — €5 / 10 cr").
|
|
16
|
+
*/
|
|
17
|
+
packages?: PackageOption[];
|
|
18
|
+
/**
|
|
19
|
+
* Called when the user selects a package. Use this with `packages` — call
|
|
20
|
+
* `meter.topup({ userId, packageId: pkg.id })` in your backend. No `amount`
|
|
21
|
+
* calculation needed; Crediball derives it from the package.
|
|
22
|
+
*/
|
|
23
|
+
onSelectPackage?: (pkg: PackageOption) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Legacy: flat list of euro amounts. Prefer `packages` + `onSelectPackage`.
|
|
26
|
+
* When both are provided, `packages` takes precedence.
|
|
27
|
+
*/
|
|
6
28
|
amounts?: number[];
|
|
7
|
-
/** Prefix shown on each
|
|
29
|
+
/** Prefix shown on each legacy amount button (default "Add €"). */
|
|
8
30
|
amountPrefix?: string;
|
|
9
31
|
title?: string;
|
|
10
32
|
description?: string;
|
|
33
|
+
/** Called when the user clicks a legacy amount button. */
|
|
11
34
|
onAdd?: (amount: number) => void;
|
|
12
35
|
onClose?: () => void;
|
|
13
36
|
/** When true, show a free-form amount field in addition to the preset buttons. */
|
|
@@ -29,4 +52,4 @@ export interface PaywallModalProps extends CrediballThemeOverrides {
|
|
|
29
52
|
currency?: string;
|
|
30
53
|
style?: CSSProperties;
|
|
31
54
|
}
|
|
32
|
-
export declare function PaywallModal({ open, amounts, amountPrefix, title, description, onAdd, onClose, allowCustom, customMin, customMax, currencySymbol, balance, balanceRate, currency, accentColor, style, }: PaywallModalProps): import("react").JSX.Element | null;
|
|
55
|
+
export declare function PaywallModal({ open, packages, onSelectPackage, amounts, amountPrefix, title, description, onAdd, onClose, allowCustom, customMin, customMax, currencySymbol, balance, balanceRate, currency, accentColor, style, }: PaywallModalProps): import("react").JSX.Element | null;
|
package/dist/PaywallModal.js
CHANGED
|
@@ -17,7 +17,7 @@ function fmtMoney(n, currency) {
|
|
|
17
17
|
return `${n.toFixed(2)} ${currency}`;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
export function PaywallModal({ open, amounts = [5, 10], amountPrefix = "Add €", title = "You need more credits to continue.", description = "Top up to keep using this feature.", onAdd, onClose, allowCustom = false, customMin = 1, customMax, currencySymbol = "€", balance, balanceRate, currency = "EUR", accentColor = tokens.primary, style, }) {
|
|
20
|
+
export function PaywallModal({ open, packages, onSelectPackage, amounts = [5, 10], amountPrefix = "Add €", title = "You need more credits to continue.", description = "Top up to keep using this feature.", onAdd, onClose, allowCustom = false, customMin = 1, customMax, currencySymbol = "€", balance, balanceRate, currency = "EUR", accentColor = tokens.primary, style, }) {
|
|
21
21
|
// Stack the top-up buttons one-per-line on narrow (mobile) screens.
|
|
22
22
|
const [narrow, setNarrow] = useState(false);
|
|
23
23
|
const [customValue, setCustomValue] = useState("");
|
|
@@ -92,10 +92,12 @@ export function PaywallModal({ open, amounts = [5, 10], amountPrefix = "Add €"
|
|
|
92
92
|
marginBottom: 4,
|
|
93
93
|
}, children: "Your balance" }), _jsxs("div", { style: { display: "flex", alignItems: "baseline", gap: 8, flexWrap: "wrap" }, children: [_jsxs("span", { style: { fontSize: 22, fontWeight: 600, color: tokens.ink }, children: [fmtCredits(balance), " credits"] }), balanceRate && balanceRate > 0 ? (_jsxs("span", { style: { fontSize: 13, color: tokens.inkMuted }, children: ["\u2248 ", fmtMoney(balance / balanceRate, currency)] })) : null] })] })), _jsx("h3", { style: { margin: 0, fontSize: 24, fontWeight: 600, color: tokens.ink, letterSpacing: "-0.01em" }, children: title }), _jsx("p", { style: { marginTop: 8, marginBottom: 0, fontSize: 14, color: tokens.inkMuted }, children: description }), _jsx("div", { style: {
|
|
94
94
|
display: "flex",
|
|
95
|
-
flexDirection:
|
|
96
|
-
gap:
|
|
95
|
+
flexDirection: "column",
|
|
96
|
+
gap: 10,
|
|
97
97
|
marginTop: 24,
|
|
98
|
-
}, children:
|
|
98
|
+
}, children: packages && packages.length > 0
|
|
99
|
+
? packages.map((pkg) => (_jsxs("button", { onClick: () => onSelectPackage?.(pkg), style: { ...buttonStyle, flex: "none", display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [_jsx("span", { children: pkg.name }), _jsxs("span", { style: { opacity: 0.85, fontSize: 14 }, children: [fmtMoney(pkg.price, currency), " \u00B7 ", fmtCredits(pkg.credits), " cr"] })] }, pkg.id)))
|
|
100
|
+
: (_jsx("div", { style: { display: "flex", flexDirection: narrow ? "column" : "row", gap: 12 }, children: amounts.map((amount) => (_jsxs("button", { onClick: () => onAdd?.(amount), style: buttonStyle, children: [amountPrefix, amount] }, amount))) })) }), allowCustom ? (_jsxs("div", { style: { marginTop: 12 }, children: [_jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [_jsx("span", { style: { fontSize: 17, color: tokens.inkMuted }, children: currencySymbol }), _jsx("input", { value: customValue, onChange: (e) => setCustomValue(e.target.value), inputMode: "decimal", placeholder: String(customMin), style: {
|
|
99
101
|
flex: 1,
|
|
100
102
|
minWidth: 0,
|
|
101
103
|
appearance: "none",
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { CreditsBadge, type CreditsBadgeProps } from "./CreditsBadge";
|
|
2
|
-
export { PaywallModal, type PaywallModalProps } from "./PaywallModal";
|
|
2
|
+
export { PaywallModal, type PaywallModalProps, type PackageOption } from "./PaywallModal";
|
|
3
3
|
export { CreditIndicator, type CreditIndicatorProps } from "./CreditIndicator";
|
|
4
4
|
export { CrediballProvider, useCrediball, type CrediballProviderProps, } from "./CrediballProvider";
|
|
5
|
+
export { usePaywall, type UsePaywallProps, type UsePaywallResult, } from "./usePaywall";
|
|
5
6
|
export { tokens, type CrediballThemeOverrides } from "./theme";
|
package/dist/index.js
CHANGED
|
@@ -4,4 +4,5 @@ export { CreditsBadge } from "./CreditsBadge";
|
|
|
4
4
|
export { PaywallModal } from "./PaywallModal";
|
|
5
5
|
export { CreditIndicator } from "./CreditIndicator";
|
|
6
6
|
export { CrediballProvider, useCrediball, } from "./CrediballProvider";
|
|
7
|
+
export { usePaywall, } from "./usePaywall";
|
|
7
8
|
export { tokens } from "./theme";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { type PaywallModalProps, type PackageOption } from "./PaywallModal";
|
|
3
|
+
export type UsePaywallProps = Pick<PaywallModalProps, "amounts" | "amountPrefix" | "packages" | "allowCustom" | "customMin" | "customMax" | "currencySymbol" | "title" | "description" | "accentColor" | "balance" | "balanceRate" | "currency"> & {
|
|
4
|
+
/** Called when the user picks a preset or custom top-up amount. */
|
|
5
|
+
onTopup?: (amount: number) => void | Promise<void>;
|
|
6
|
+
/** Called when the user picks a package from `packages`. */
|
|
7
|
+
onSelectPackage?: (pkg: PackageOption) => void | Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
export interface UsePaywallResult {
|
|
10
|
+
/**
|
|
11
|
+
* Open the paywall modal. Calling this is ALWAYS safe — it opens the modal
|
|
12
|
+
* whether or not it was previously dismissed. Never add a "paywallAlreadyShown"
|
|
13
|
+
* guard around this: it is idempotent (calling while already open is a no-op)
|
|
14
|
+
* and every InsufficientCreditsError should call it unconditionally.
|
|
15
|
+
*/
|
|
16
|
+
trigger: () => void;
|
|
17
|
+
/** Close the paywall without a purchase. The next trigger() call will re-open it. */
|
|
18
|
+
dismiss: () => void;
|
|
19
|
+
/** Whether the paywall is currently open. */
|
|
20
|
+
isOpen: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Drop this into your JSX tree — it renders the modal when open.
|
|
23
|
+
* It must be rendered for the paywall to appear; place it near the root of
|
|
24
|
+
* the component where you call `trigger()`.
|
|
25
|
+
*
|
|
26
|
+
* return (
|
|
27
|
+
* <div>
|
|
28
|
+
* <button onClick={generate}>Generate</button>
|
|
29
|
+
* {paywall}
|
|
30
|
+
* </div>
|
|
31
|
+
* );
|
|
32
|
+
*/
|
|
33
|
+
paywall: ReactElement;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Manages a Crediball paywall modal with a simple, misuse-proof API.
|
|
37
|
+
*
|
|
38
|
+
* The key rule: call `trigger()` unconditionally whenever you catch an
|
|
39
|
+
* InsufficientCreditsError — never guard it with "already shown" state.
|
|
40
|
+
* Dismissing the modal ("Not now") does NOT prevent the next trigger() from
|
|
41
|
+
* reopening it. This is what makes the paywall reliably reappear on retry.
|
|
42
|
+
*
|
|
43
|
+
* const { trigger, paywall } = usePaywall({
|
|
44
|
+
* amounts: [5, 10, 20],
|
|
45
|
+
* onTopup: async (eur) => checkout(eur),
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* try {
|
|
49
|
+
* const page = await meter.wrapMeteredAction(userId, "generate_page", async () => {
|
|
50
|
+
* const res = await streamAI(prompt);
|
|
51
|
+
* return { result: res, tokens: res.usage.totalTokens };
|
|
52
|
+
* });
|
|
53
|
+
* } catch (e) {
|
|
54
|
+
* if (e instanceof InsufficientCreditsError) trigger(); // always call — no guard
|
|
55
|
+
* else throw e;
|
|
56
|
+
* }
|
|
57
|
+
*
|
|
58
|
+
* return <div>...<button onClick={generate}>Generate</button>...{paywall}</div>;
|
|
59
|
+
*/
|
|
60
|
+
export declare function usePaywall({ amounts, amountPrefix, packages, onTopup, onSelectPackage, allowCustom, customMin, customMax, currencySymbol, title, description, accentColor, balance, balanceRate, currency, }?: UsePaywallProps): UsePaywallResult;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useState } from "react";
|
|
4
|
+
import { PaywallModal } from "./PaywallModal";
|
|
5
|
+
/**
|
|
6
|
+
* Manages a Crediball paywall modal with a simple, misuse-proof API.
|
|
7
|
+
*
|
|
8
|
+
* The key rule: call `trigger()` unconditionally whenever you catch an
|
|
9
|
+
* InsufficientCreditsError — never guard it with "already shown" state.
|
|
10
|
+
* Dismissing the modal ("Not now") does NOT prevent the next trigger() from
|
|
11
|
+
* reopening it. This is what makes the paywall reliably reappear on retry.
|
|
12
|
+
*
|
|
13
|
+
* const { trigger, paywall } = usePaywall({
|
|
14
|
+
* amounts: [5, 10, 20],
|
|
15
|
+
* onTopup: async (eur) => checkout(eur),
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* try {
|
|
19
|
+
* const page = await meter.wrapMeteredAction(userId, "generate_page", async () => {
|
|
20
|
+
* const res = await streamAI(prompt);
|
|
21
|
+
* return { result: res, tokens: res.usage.totalTokens };
|
|
22
|
+
* });
|
|
23
|
+
* } catch (e) {
|
|
24
|
+
* if (e instanceof InsufficientCreditsError) trigger(); // always call — no guard
|
|
25
|
+
* else throw e;
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* return <div>...<button onClick={generate}>Generate</button>...{paywall}</div>;
|
|
29
|
+
*/
|
|
30
|
+
export function usePaywall({ amounts, amountPrefix, packages, onTopup, onSelectPackage, allowCustom, customMin, customMax, currencySymbol, title, description, accentColor, balance, balanceRate, currency, } = {}) {
|
|
31
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
32
|
+
const trigger = useCallback(() => setIsOpen(true), []);
|
|
33
|
+
const dismiss = useCallback(() => setIsOpen(false), []);
|
|
34
|
+
const handleTopup = useCallback(async (amount) => {
|
|
35
|
+
setIsOpen(false);
|
|
36
|
+
await onTopup?.(amount);
|
|
37
|
+
}, [onTopup]);
|
|
38
|
+
const handleSelectPackage = useCallback(async (pkg) => {
|
|
39
|
+
setIsOpen(false);
|
|
40
|
+
await onSelectPackage?.(pkg);
|
|
41
|
+
}, [onSelectPackage]);
|
|
42
|
+
const paywall = (_jsx(PaywallModal, { open: isOpen, amounts: amounts, amountPrefix: amountPrefix, packages: packages, onAdd: handleTopup, onSelectPackage: handleSelectPackage, onClose: dismiss, allowCustom: allowCustom, customMin: customMin, customMax: customMax, currencySymbol: currencySymbol, title: title, description: description, accentColor: accentColor, balance: balance, balanceRate: balanceRate, currency: currency }));
|
|
43
|
+
return { trigger, dismiss, isOpen, paywall };
|
|
44
|
+
}
|
package/package.json
CHANGED