@anpayeras/agnostic-checkout 0.1.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/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