@ss-dev/agnostic-checkout 0.1.12
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/README.md +439 -0
- package/dist/components/accordion-layout.d.ts +3 -0
- package/dist/components/accordion-layout.d.ts.map +1 -0
- package/dist/components/checkout-content.d.ts +5 -0
- package/dist/components/checkout-content.d.ts.map +1 -0
- package/dist/components/checkout-layout.d.ts +3 -0
- package/dist/components/checkout-layout.d.ts.map +1 -0
- package/dist/components/checkout.d.ts +4 -0
- package/dist/components/checkout.d.ts.map +1 -0
- package/dist/components/dev-tools.d.ts +3 -0
- package/dist/components/dev-tools.d.ts.map +1 -0
- package/dist/components/feedback-screen.d.ts +3 -0
- package/dist/components/feedback-screen.d.ts.map +1 -0
- package/dist/components/mobile-bar.d.ts +3 -0
- package/dist/components/mobile-bar.d.ts.map +1 -0
- package/dist/components/mobile-order-bar.d.ts +3 -0
- package/dist/components/mobile-order-bar.d.ts.map +1 -0
- package/dist/components/order-sidebar-summary.d.ts +3 -0
- package/dist/components/order-sidebar-summary.d.ts.map +1 -0
- package/dist/components/order-summary.d.ts +4 -0
- package/dist/components/order-summary.d.ts.map +1 -0
- package/dist/components/payment-form.d.ts +2 -0
- package/dist/components/payment-form.d.ts.map +1 -0
- package/dist/components/payment-methods.d.ts +4 -0
- package/dist/components/payment-methods.d.ts.map +1 -0
- package/dist/components/shipping-methods.d.ts +3 -0
- package/dist/components/shipping-methods.d.ts.map +1 -0
- package/dist/components/types.d.ts +105 -0
- package/dist/components/types.d.ts.map +1 -0
- package/dist/components/ui/badge.d.ts +9 -0
- package/dist/components/ui/badge.d.ts.map +1 -0
- package/dist/components/ui/button.d.ts +16 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/card.d.ts +19 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/index.d.ts +6 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/selectable-card.d.ts +15 -0
- package/dist/components/ui/selectable-card.d.ts.map +1 -0
- package/dist/components/ui/spinner.d.ts +7 -0
- package/dist/components/ui/spinner.d.ts.map +1 -0
- package/dist/core/checkout-context.d.ts +67 -0
- package/dist/core/checkout-context.d.ts.map +1 -0
- package/dist/core/checkout-machine.d.ts +3 -0
- package/dist/core/checkout-machine.d.ts.map +1 -0
- package/dist/core/event-system.d.ts +35 -0
- package/dist/core/event-system.d.ts.map +1 -0
- package/dist/core/i18n-context.d.ts +17 -0
- package/dist/core/i18n-context.d.ts.map +1 -0
- package/dist/core/license.d.ts +18 -0
- package/dist/core/license.d.ts.map +1 -0
- package/dist/core/provider.interface.d.ts +7 -0
- package/dist/core/provider.interface.d.ts.map +1 -0
- package/dist/core/types.d.ts +76 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/hooks/useCheckout.d.ts +37 -0
- package/dist/hooks/useCheckout.d.ts.map +1 -0
- package/dist/hooks/useLicense.d.ts +8 -0
- package/dist/hooks/useLicense.d.ts.map +1 -0
- package/dist/index.cjs +157 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5069 -0
- package/dist/locales/en.d.ts +3 -0
- package/dist/locales/en.d.ts.map +1 -0
- package/dist/locales/es.d.ts +3 -0
- package/dist/locales/es.d.ts.map +1 -0
- package/dist/locales/index.d.ts +14 -0
- package/dist/locales/index.d.ts.map +1 -0
- package/dist/locales/pt-BR.d.ts +3 -0
- package/dist/locales/pt-BR.d.ts.map +1 -0
- package/dist/locales/types.d.ts +46 -0
- package/dist/locales/types.d.ts.map +1 -0
- package/dist/plugins/cart-edit-plugin.d.ts +10 -0
- package/dist/plugins/cart-edit-plugin.d.ts.map +1 -0
- package/dist/plugins/discount-plugin.d.ts +4 -0
- package/dist/plugins/discount-plugin.d.ts.map +1 -0
- package/dist/plugins/index.d.ts +8 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/plugin-context.d.ts +10 -0
- package/dist/plugins/plugin-context.d.ts.map +1 -0
- package/dist/plugins/shipping-plugin.d.ts +27 -0
- package/dist/plugins/shipping-plugin.d.ts.map +1 -0
- package/dist/plugins/types.d.ts +35 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/theme/color-utils.d.ts +39 -0
- package/dist/theme/color-utils.d.ts.map +1 -0
- package/dist/theme/theme-provider.d.ts +11 -0
- package/dist/theme/theme-provider.d.ts.map +1 -0
- package/dist/theme/tokens.d.ts +30 -0
- package/dist/theme/tokens.d.ts.map +1 -0
- package/dist/utils/utils.d.ts +7 -0
- package/dist/utils/utils.d.ts.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
# ⚡ Agnostic Checkout SDK
|
|
2
|
+
|
|
3
|
+
A provider-agnostic, embeddable React checkout component with dynamic theming, plugin architecture, and full TypeScript support.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 🛒 **Embeddable checkout component** — drop into any React app
|
|
10
|
+
- 🎨 **Theme system** — 5 built-in presets (`light`, `dark`, `minimal`, `corporate`, `neon`)
|
|
11
|
+
- 🎯 **Brand Auto Theme** — generate a full theme from a single brand color
|
|
12
|
+
- 🔌 **Plugin architecture** — extend checkout behavior without modifying core code
|
|
13
|
+
- 🏷️ **Discount Plugin** — coupon input, apply/remove with event-driven updates
|
|
14
|
+
- ✏️ **Cart Edit Plugin** — quantity stepper, item removal with configurable limits
|
|
15
|
+
- 🌍 **i18n** — built-in locales (`en`, `es`, `pt-BR`, `auto`)
|
|
16
|
+
- 💱 **Multi-currency** — 25+ currencies with automatic formatting
|
|
17
|
+
- 📱 **Responsive** — mobile-first layout with collapsible order summary
|
|
18
|
+
- 🔒 **Provider-agnostic** — works with any payment backend
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install agnostic-checkout
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { Checkout } from "agnostic-checkout";
|
|
34
|
+
|
|
35
|
+
function App() {
|
|
36
|
+
const items = [
|
|
37
|
+
{
|
|
38
|
+
id: "item_1",
|
|
39
|
+
name: "Pro Plan",
|
|
40
|
+
unitPrice: 49.00,
|
|
41
|
+
quantity: 1,
|
|
42
|
+
total: 49.00,
|
|
43
|
+
image: "https://example.com/pro-plan.png",
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const totals = {
|
|
48
|
+
subtotal: 49.00,
|
|
49
|
+
taxes: 4.90,
|
|
50
|
+
total: 53.90,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const paymentMethods = [
|
|
54
|
+
{
|
|
55
|
+
id: "pm_card",
|
|
56
|
+
label: "Credit Card",
|
|
57
|
+
type: "card",
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Checkout
|
|
63
|
+
items={items}
|
|
64
|
+
totals={totals}
|
|
65
|
+
paymentMethods={paymentMethods}
|
|
66
|
+
provider={yourPaymentProvider}
|
|
67
|
+
currency="USD"
|
|
68
|
+
locale="en"
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
| Prop | Description |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `items` | Array of cart items to display |
|
|
77
|
+
| `totals` | Object with subtotal, taxes, shipping, discount, and total |
|
|
78
|
+
| `paymentMethods` | Available payment methods |
|
|
79
|
+
| `provider` | Your `PaymentProvider` implementation |
|
|
80
|
+
| `currency` | Currency code for formatting (`"USD"`, `"EUR"`, etc.) |
|
|
81
|
+
| `locale` | Language for UI text (`"en"`, `"es"`, `"pt-BR"`, `"auto"`) |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Theming
|
|
86
|
+
|
|
87
|
+
The checkout uses CSS variables internally and supports three theming strategies with the following priority chain:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
customTheme (overrides)
|
|
91
|
+
↓
|
|
92
|
+
brandColor (auto-generated theme)
|
|
93
|
+
↓
|
|
94
|
+
theme preset ("light" | "dark" | ...)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Preset Themes
|
|
98
|
+
|
|
99
|
+
Choose from 5 built-in themes:
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
<Checkout theme="light" />
|
|
103
|
+
<Checkout theme="dark" />
|
|
104
|
+
<Checkout theme="minimal" />
|
|
105
|
+
<Checkout theme="corporate" />
|
|
106
|
+
<Checkout theme="neon" />
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Brand Auto Theme
|
|
110
|
+
|
|
111
|
+
Generate a complete theme from a single brand color. The SDK automatically derives background, surface, text, border, and accent colors:
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
<Checkout brandColor="#6366F1" />
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Custom Theme Overrides
|
|
118
|
+
|
|
119
|
+
Override specific tokens on top of any base theme:
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
<Checkout
|
|
123
|
+
theme="light"
|
|
124
|
+
customTheme={{
|
|
125
|
+
colors: {
|
|
126
|
+
primary: "#ff0055",
|
|
127
|
+
success: "#00cc88",
|
|
128
|
+
},
|
|
129
|
+
radius: "1rem",
|
|
130
|
+
}}
|
|
131
|
+
/>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Combine with `brandColor`:
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
<Checkout
|
|
138
|
+
brandColor="#6366F1"
|
|
139
|
+
customTheme={{
|
|
140
|
+
radius: "20px",
|
|
141
|
+
fontFamily: "'Poppins', sans-serif",
|
|
142
|
+
}}
|
|
143
|
+
/>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Theme Tokens
|
|
147
|
+
|
|
148
|
+
| Token | CSS Variable | Description |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| `colors.primary` | `--color-primary` | Buttons, links, active states |
|
|
151
|
+
| `colors.background` | `--color-background` | Page background |
|
|
152
|
+
| `colors.surface` | `--color-surface` | Card/panel backgrounds |
|
|
153
|
+
| `colors.text` | `--color-text` | Primary text color |
|
|
154
|
+
| `colors.border` | `--color-border` | Borders and dividers |
|
|
155
|
+
| `colors.success` | `--color-success` | Success states, discounts |
|
|
156
|
+
| `colors.error` | `--color-error` | Error states, remove actions |
|
|
157
|
+
| `radius` | `--theme-radius` | Border radius for cards/buttons |
|
|
158
|
+
| `fontFamily` | `--theme-font` | Font family stack |
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Plugin System
|
|
163
|
+
|
|
164
|
+
Plugins extend checkout functionality through a **slot-based architecture**. Plugins inject UI into predefined areas and communicate via events — they never modify state directly.
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
import { createDiscountPlugin, createCartEditPlugin } from "agnostic-checkout/plugins";
|
|
168
|
+
|
|
169
|
+
<Checkout
|
|
170
|
+
plugins={[
|
|
171
|
+
createDiscountPlugin(handleEvent),
|
|
172
|
+
createCartEditPlugin(handleEvent, { allowRemove: true }),
|
|
173
|
+
]}
|
|
174
|
+
onEvent={handleEvent}
|
|
175
|
+
/>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Plugins emit events. Your `onEvent` handler processes them and updates `items`/`totals` externally:
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
const handleEvent = (event) => {
|
|
182
|
+
switch (event.type) {
|
|
183
|
+
case "COUPON_APPLY_REQUESTED":
|
|
184
|
+
// Validate event.code, update items/totals
|
|
185
|
+
break;
|
|
186
|
+
case "ITEM_REMOVE_REQUESTED":
|
|
187
|
+
// Remove item by event.itemId
|
|
188
|
+
break;
|
|
189
|
+
case "ITEM_QUANTITY_UPDATE_REQUESTED":
|
|
190
|
+
// Update quantity for event.itemId to event.quantity
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Discount Plugin
|
|
199
|
+
|
|
200
|
+
Adds a coupon input field to the order summary. Users can type a discount code, apply it, and remove it via a trash icon.
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
import { createDiscountPlugin } from "agnostic-checkout/plugins";
|
|
204
|
+
|
|
205
|
+
const plugins = [
|
|
206
|
+
createDiscountPlugin(handleEvent),
|
|
207
|
+
];
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Events emitted:**
|
|
211
|
+
|
|
212
|
+
| Event | Payload | Description |
|
|
213
|
+
|---|---|---|
|
|
214
|
+
| `COUPON_APPLY_REQUESTED` | `{ code: string }` | User submitted a coupon code |
|
|
215
|
+
| `COUPON_REMOVE_REQUESTED` | — | User clicked the remove button |
|
|
216
|
+
|
|
217
|
+
The plugin does **not** calculate discounts. Your `onEvent` handler validates the code and updates `items`/`totals` with the new discount values.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Cart Edit Plugin
|
|
222
|
+
|
|
223
|
+
Allows users to modify item quantities and/or remove items from the cart.
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
import { createCartEditPlugin } from "agnostic-checkout/plugins";
|
|
227
|
+
|
|
228
|
+
const plugins = [
|
|
229
|
+
createCartEditPlugin(handleEvent, {
|
|
230
|
+
allowRemove: true,
|
|
231
|
+
allowQuantityEdit: true,
|
|
232
|
+
minQuantity: 1,
|
|
233
|
+
maxQuantity: 10,
|
|
234
|
+
}),
|
|
235
|
+
];
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Options
|
|
239
|
+
|
|
240
|
+
| Option | Type | Default | Description |
|
|
241
|
+
|---|---|---|---|
|
|
242
|
+
| `allowRemove` | `boolean` | `false` | Show remove button per item |
|
|
243
|
+
| `allowQuantityEdit` | `boolean` | `false` | Show quantity stepper per item |
|
|
244
|
+
| `minQuantity` | `number` | `1` | Minimum allowed quantity |
|
|
245
|
+
| `maxQuantity` | `number` | `99` | Maximum allowed quantity |
|
|
246
|
+
|
|
247
|
+
**Events emitted:**
|
|
248
|
+
|
|
249
|
+
| Event | Payload | Description |
|
|
250
|
+
|---|---|---|
|
|
251
|
+
| `ITEM_QUANTITY_UPDATE_REQUESTED` | `{ itemId, quantity }` | User changed item quantity |
|
|
252
|
+
| `ITEM_REMOVE_REQUESTED` | `{ itemId }` | User clicked remove |
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Payment Provider
|
|
257
|
+
|
|
258
|
+
The checkout is payment-agnostic. Implement the `PaymentProvider` interface to connect any backend:
|
|
259
|
+
|
|
260
|
+
```tsx
|
|
261
|
+
interface PaymentProvider {
|
|
262
|
+
initialize?(config: unknown): Promise<void>;
|
|
263
|
+
createPayment(data: unknown): Promise<PaymentResult>;
|
|
264
|
+
confirmPayment?(data: unknown): Promise<PaymentResult>;
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
class StripeProvider implements PaymentProvider {
|
|
270
|
+
async createPayment(data) {
|
|
271
|
+
const response = await fetch("/api/payments", {
|
|
272
|
+
method: "POST",
|
|
273
|
+
body: JSON.stringify(data),
|
|
274
|
+
});
|
|
275
|
+
return { status: "success" };
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
<Checkout provider={new StripeProvider()} />
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## API Reference
|
|
285
|
+
|
|
286
|
+
### `<Checkout />` Props
|
|
287
|
+
|
|
288
|
+
| Prop | Type | Required | Default | Description |
|
|
289
|
+
|---|---|---|---|---|
|
|
290
|
+
| `items` | `CheckoutItem[]` | ✅ | — | Cart items |
|
|
291
|
+
| `totals` | `CheckoutTotals` | ✅ | — | Order totals |
|
|
292
|
+
| `paymentMethods` | `PaymentMethod[]` | ✅ | — | Available payment methods |
|
|
293
|
+
| `provider` | `PaymentProvider` | ✅ | — | Payment provider implementation |
|
|
294
|
+
| `currency` | `SupportedCurrency` | ✅ | — | Currency code |
|
|
295
|
+
| `locale` | `CheckoutLocale` | — | `"es"` | UI language |
|
|
296
|
+
| `theme` | `CheckoutThemeName \| Partial<CheckoutTheme>` | — | `"light"` | Theme preset or partial theme object |
|
|
297
|
+
| `brandColor` | `string` | — | — | Auto-generate theme from hex color |
|
|
298
|
+
| `customTheme` | `Partial<CheckoutTheme>` | — | — | Override specific theme tokens |
|
|
299
|
+
| `onEvent` | `EventHandler` | — | — | Callback for checkout events |
|
|
300
|
+
| `plugins` | `CheckoutPlugin[]` | — | `[]` | Plugins to extend functionality |
|
|
301
|
+
| `messages` | `Partial<CheckoutMessages>` | — | — | Override default UI text |
|
|
302
|
+
| `formatters` | `CheckoutFormatters` | — | — | Custom currency formatter |
|
|
303
|
+
| `devTools` | `boolean` | — | `false` | Show dev tools panel |
|
|
304
|
+
| `initialState` | `PaymentResult` | — | — | Start in a specific state |
|
|
305
|
+
|
|
306
|
+
### `CheckoutItem`
|
|
307
|
+
|
|
308
|
+
```tsx
|
|
309
|
+
interface CheckoutItem {
|
|
310
|
+
id: string;
|
|
311
|
+
name: string;
|
|
312
|
+
quantity: number;
|
|
313
|
+
unitPrice: number;
|
|
314
|
+
total: number;
|
|
315
|
+
image?: string;
|
|
316
|
+
discount?: {
|
|
317
|
+
type: "percentage" | "fixed";
|
|
318
|
+
value: number;
|
|
319
|
+
label?: string;
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### `CheckoutTotals`
|
|
325
|
+
|
|
326
|
+
```tsx
|
|
327
|
+
interface CheckoutTotals {
|
|
328
|
+
subtotal: number;
|
|
329
|
+
discount?: number;
|
|
330
|
+
taxes?: number;
|
|
331
|
+
shipping?: number;
|
|
332
|
+
total: number;
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Events
|
|
337
|
+
|
|
338
|
+
| Event | Description |
|
|
339
|
+
|---|---|
|
|
340
|
+
| `CHECKOUT_VIEWED` | Checkout component mounted |
|
|
341
|
+
| `STEP_CHANGED` | User navigated to a new step |
|
|
342
|
+
| `PAYMENT_METHOD_SELECTED` | User selected a payment method |
|
|
343
|
+
| `PAYMENT_SUBMITTED` | Payment form submitted |
|
|
344
|
+
| `PAYMENT_SUCCESS` | Payment completed successfully |
|
|
345
|
+
| `PAYMENT_ERROR` | Payment failed |
|
|
346
|
+
| `COUPON_APPLY_REQUESTED` | Coupon code submitted (Discount Plugin) |
|
|
347
|
+
| `COUPON_REMOVE_REQUESTED` | Coupon removed (Discount Plugin) |
|
|
348
|
+
| `ITEM_QUANTITY_UPDATE_REQUESTED` | Quantity changed (Cart Edit Plugin) |
|
|
349
|
+
| `ITEM_REMOVE_REQUESTED` | Item removed (Cart Edit Plugin) |
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Internationalization
|
|
354
|
+
|
|
355
|
+
Built-in support for three locales plus automatic detection:
|
|
356
|
+
|
|
357
|
+
```tsx
|
|
358
|
+
<Checkout locale="en" /> // English
|
|
359
|
+
<Checkout locale="es" /> // Spanish
|
|
360
|
+
<Checkout locale="pt-BR" /> // Portuguese (Brazil)
|
|
361
|
+
<Checkout locale="auto" /> // Auto-detect from browser
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Override specific messages:
|
|
365
|
+
|
|
366
|
+
```tsx
|
|
367
|
+
<Checkout
|
|
368
|
+
messages={{
|
|
369
|
+
payNow: "Complete Purchase",
|
|
370
|
+
continueToPay: "Proceed to Payment",
|
|
371
|
+
}}
|
|
372
|
+
/>
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Custom currency formatter:
|
|
376
|
+
|
|
377
|
+
```tsx
|
|
378
|
+
<Checkout
|
|
379
|
+
formatters={{
|
|
380
|
+
currency: (amount) => `US$ ${amount.toFixed(2)}`,
|
|
381
|
+
}}
|
|
382
|
+
/>
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## Demo
|
|
388
|
+
|
|
389
|
+
A built-in demo page is available with interactive controls:
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
npm run dev
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
The demo includes a **Settings toolbar** to test:
|
|
396
|
+
|
|
397
|
+
- Theme switching (5 presets + Brand Auto Theme)
|
|
398
|
+
- Locale and currency changes
|
|
399
|
+
- Item count adjustments
|
|
400
|
+
- Plugin enable/disable toggles
|
|
401
|
+
- Brand color picker with 12 presets
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Development
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
# Install dependencies
|
|
409
|
+
npm install
|
|
410
|
+
|
|
411
|
+
# Start development server
|
|
412
|
+
npm run dev
|
|
413
|
+
|
|
414
|
+
# Type checking
|
|
415
|
+
npx tsc --noEmit
|
|
416
|
+
|
|
417
|
+
# Build
|
|
418
|
+
npm run build
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Project Structure
|
|
422
|
+
|
|
423
|
+
```
|
|
424
|
+
src/
|
|
425
|
+
├── core/ # State machine, context, events, types
|
|
426
|
+
├── theme/ # Theme system, tokens, color utilities
|
|
427
|
+
├── locales/ # i18n messages (en, es, pt-BR)
|
|
428
|
+
├── plugins/ # Plugin system, discount & cart-edit plugins
|
|
429
|
+
├── ui/ # React components (Checkout, Layout, Summary, etc.)
|
|
430
|
+
├── hooks/ # useCheckout hook
|
|
431
|
+
├── lib/ # Utilities (cn, formatNumber)
|
|
432
|
+
└── mock/ # Demo app, mock provider, toolbar
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## License
|
|
438
|
+
|
|
439
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accordion-layout.d.ts","sourceRoot":"","sources":["../../src/components/accordion-layout.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD,eAAO,MAAM,eAAe,GAAI,iBAAiB,oBAAoB,4CA4OpE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout-content.d.ts","sourceRoot":"","sources":["../../src/components/checkout-content.tsx"],"names":[],"mappings":"AAgBA,eAAO,MAAM,eAAe,GAAI,uBAG7B;IACC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,aAAa,GAAG,WAAW,CAAC;CACxC,4CAuFA,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout-layout.d.ts","sourceRoot":"","sources":["../../src/components/checkout-layout.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD,eAAO,MAAM,cAAc,GAAI,4CAA4C,mBAAmB,4CA8B7F,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../../src/components/checkout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAkD5C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-tools.d.ts","sourceRoot":"","sources":["../../src/components/dev-tools.tsx"],"names":[],"mappings":"AAeA,eAAO,MAAM,QAAQ,+CAsGpB,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback-screen.d.ts","sourceRoot":"","sources":["../../src/components/feedback-screen.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAiB,MAAM,SAAS,CAAC;AA4BlE,eAAO,MAAM,cAAc,GAAI,oEAO5B,mBAAmB,4CAwFrB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mobile-bar.d.ts","sourceRoot":"","sources":["../../src/components/mobile-bar.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,eAAO,MAAM,SAAS,GAAI,+BAA+C,cAAc,mDAgDtF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mobile-order-bar.d.ts","sourceRoot":"","sources":["../../src/components/mobile-order-bar.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD,eAAO,MAAM,cAAc,GAAI,qEAM5B,mBAAmB,4CAuHrB,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { OrderSidebarSummaryProps } from './types';
|
|
2
|
+
export declare const OrderSidebarSummary: ({ showItems: propShowItems, isLoading, hasShipping, layout }: OrderSidebarSummaryProps) => import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
//# sourceMappingURL=order-sidebar-summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"order-sidebar-summary.d.ts","sourceRoot":"","sources":["../../src/components/order-sidebar-summary.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAGxD,eAAO,MAAM,mBAAmB,GAAI,8DAA8E,wBAAwB,4CA8HzI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"order-summary.d.ts","sourceRoot":"","sources":["../../src/components/order-summary.tsx"],"names":[],"mappings":"AAMA,eAAO,MAAM,YAAY,GAAI,iBAAgB;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,4CA+EzE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment-form.d.ts","sourceRoot":"","sources":["../../src/components/payment-form.tsx"],"names":[],"mappings":"AAKA,eAAO,MAAM,WAAW,+CA+FvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment-methods.d.ts","sourceRoot":"","sources":["../../src/components/payment-methods.tsx"],"names":[],"mappings":"AAiBA,eAAO,MAAM,cAAc,GAAI,iBAAgB;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,4CA4E3E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shipping-methods.d.ts","sourceRoot":"","sources":["../../src/components/shipping-methods.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD,eAAO,MAAM,eAAe,GAAI,yBAAyB,oBAAoB,4CAyD5E,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { EventHandler } from '../core/event-system';
|
|
3
|
+
import { PaymentProvider } from '../core/provider.interface';
|
|
4
|
+
import { CartController, CheckoutItem, CheckoutTotals, FractalButtonVariant, PaymentMethod, PaymentResult } from '../core/types';
|
|
5
|
+
import { CheckoutTheme, CheckoutThemeName } from '../theme/tokens';
|
|
6
|
+
import { CheckoutMessages, CheckoutFormatters, SupportedCurrency, CheckoutLocale } from '../locales/types';
|
|
7
|
+
import { CheckoutPlugin } from '../plugins/types';
|
|
8
|
+
import { ShippingMethod } from '../plugins/shipping-plugin';
|
|
9
|
+
export interface CheckoutProps {
|
|
10
|
+
/** Array of items currently in the cart to be displayed in the order summary. */
|
|
11
|
+
items: CheckoutItem[];
|
|
12
|
+
/** Calculated totals including subtotal, taxes, shipping, discounts, and final total. */
|
|
13
|
+
totals: CheckoutTotals;
|
|
14
|
+
/** Available payment methods to present to the user (e.g., credit card, PayPal, etc.). */
|
|
15
|
+
paymentMethods: PaymentMethod[];
|
|
16
|
+
/** The core payment provider integration responsible for processing the payment. */
|
|
17
|
+
provider: PaymentProvider;
|
|
18
|
+
/** Currency code used for formatting prices (e.g., 'USD', 'EUR', 'ARS'). */
|
|
19
|
+
currency: SupportedCurrency;
|
|
20
|
+
/** Locale applied for internationalization and formatting (e.g., 'en', 'es'). Defaults to 'en'. */
|
|
21
|
+
locale?: CheckoutLocale;
|
|
22
|
+
/** UI theme preset to use, or partial theme configuration to override the default. */
|
|
23
|
+
theme?: CheckoutThemeName | Partial<CheckoutTheme>;
|
|
24
|
+
/** Base brand color used to auto-generate a custom theme palette. */
|
|
25
|
+
brandColor?: string;
|
|
26
|
+
/** Specific custom theme tokens to override properties of the active theme. */
|
|
27
|
+
customTheme?: Partial<CheckoutTheme>;
|
|
28
|
+
/** Callback function triggered when various core checkout actions occur (e.g., item update, payment submitted). */
|
|
29
|
+
onEvent?: EventHandler;
|
|
30
|
+
/** Optional controller to handle external cart actions programmatically. */
|
|
31
|
+
cartController?: CartController;
|
|
32
|
+
/** If provided, initializes the checkout directly into a feedback state (e.g., success, error) instead of the review step. */
|
|
33
|
+
initialState?: Extract<PaymentResult, {
|
|
34
|
+
status: "success" | "error" | "pending";
|
|
35
|
+
}>;
|
|
36
|
+
/** Enable Developer Tools panel to mock scenarios and intercept events. */
|
|
37
|
+
devTools?: boolean;
|
|
38
|
+
/** Custom override text messages to tailor the localization. */
|
|
39
|
+
messages?: Partial<CheckoutMessages>;
|
|
40
|
+
/** Optional custom formatting functions for prices and dates instead of defaults. */
|
|
41
|
+
formatters?: CheckoutFormatters;
|
|
42
|
+
/** Array of plugins to extend the core functionality (like shipping, cart editing, discounts). */
|
|
43
|
+
plugins?: CheckoutPlugin[];
|
|
44
|
+
/** Defines the visual structure of the checkout page. Defaults to 'single-page'. */
|
|
45
|
+
layout?: "single-page" | "accordion";
|
|
46
|
+
/** Pre-selected shipping method ID. Useful if the integrator wants to default a shipping option. */
|
|
47
|
+
defaultShippingMethodId?: string;
|
|
48
|
+
/** Pre-selected payment method ID. Useful if the integrator wants to default a payment option. */
|
|
49
|
+
defaultPaymentMethodId?: string;
|
|
50
|
+
/** License key to validate checkout feature flags against a remote Convex API. */
|
|
51
|
+
licenseKey?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface CheckoutLayoutProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
54
|
+
children: React.ReactNode;
|
|
55
|
+
sidebar?: React.ReactNode;
|
|
56
|
+
}
|
|
57
|
+
export interface FeedbackScreenProps {
|
|
58
|
+
title: string;
|
|
59
|
+
description?: string;
|
|
60
|
+
actions?: ButtonProps[];
|
|
61
|
+
actionsLayout?: "row" | "column";
|
|
62
|
+
variant?: PaymentResult["status"];
|
|
63
|
+
children?: ReactNode;
|
|
64
|
+
}
|
|
65
|
+
export type VariantConfig = {
|
|
66
|
+
icon: ReactNode;
|
|
67
|
+
iconBg: string;
|
|
68
|
+
iconColor: string;
|
|
69
|
+
};
|
|
70
|
+
export interface ButtonProps {
|
|
71
|
+
label: string;
|
|
72
|
+
onPress: () => void;
|
|
73
|
+
variant?: FractalButtonVariant;
|
|
74
|
+
icon?: ReactNode;
|
|
75
|
+
disabled?: boolean;
|
|
76
|
+
className?: string;
|
|
77
|
+
type?: "button" | "submit";
|
|
78
|
+
}
|
|
79
|
+
export interface OrderSidebarSummaryProps {
|
|
80
|
+
showItems?: boolean;
|
|
81
|
+
isLoading?: boolean;
|
|
82
|
+
hasShipping?: boolean;
|
|
83
|
+
layout?: "single-page" | "accordion";
|
|
84
|
+
}
|
|
85
|
+
export type MockScenario = 'success' | 'pending' | 'error' | 'redirect';
|
|
86
|
+
export interface MobileOrderBarProps {
|
|
87
|
+
onAction?: () => void;
|
|
88
|
+
actionLabel?: string;
|
|
89
|
+
actionDisabled?: boolean;
|
|
90
|
+
isSubmitting?: boolean;
|
|
91
|
+
showItems?: boolean;
|
|
92
|
+
}
|
|
93
|
+
export interface ShippingMethodsProps {
|
|
94
|
+
methods: ShippingMethod[];
|
|
95
|
+
hideHeader?: boolean;
|
|
96
|
+
}
|
|
97
|
+
export interface AccordionLayoutProps {
|
|
98
|
+
hasShipping: boolean;
|
|
99
|
+
}
|
|
100
|
+
export interface MobileBarProps {
|
|
101
|
+
step: string;
|
|
102
|
+
hasShipping?: boolean;
|
|
103
|
+
layout?: "single-page" | "accordion";
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/components/types.ts"],"names":[],"mappings":"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"}
|