flintn-checkout 0.0.7 → 0.0.9
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 +318 -56
- package/dist/index.d.mts +101 -14
- package/dist/index.d.ts +101 -14
- package/dist/index.js +426 -88
- package/dist/index.mjs +421 -87
- package/dist/react.d.mts +86 -12
- package/dist/react.d.ts +86 -12
- package/dist/react.js +667 -100
- package/dist/react.mjs +666 -98
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# flintn-checkout
|
|
2
2
|
|
|
3
|
-
FlintN Payment SDK —
|
|
3
|
+
FlintN Payment SDK — Embed payment forms via iframe checkout or headless hosted fields.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
```bash
|
|
7
7
|
npm install flintn-checkout
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Iframe Checkout
|
|
11
|
+
|
|
12
|
+
Full checkout UI rendered inside a single iframe. Includes card form, express payments (Apple Pay, Google Pay, PayPal), and 3DS handling.
|
|
11
13
|
|
|
12
14
|
### React
|
|
13
15
|
```tsx
|
|
@@ -25,14 +27,11 @@ function Checkout() {
|
|
|
25
27
|
console.log('Payment failed:', result.error);
|
|
26
28
|
}
|
|
27
29
|
},
|
|
28
|
-
onExpressPayment: (result) => {
|
|
29
|
-
console.log('Express payment:', result);
|
|
30
|
-
},
|
|
31
30
|
});
|
|
32
31
|
|
|
33
32
|
return (
|
|
34
33
|
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
|
35
|
-
<div ref={containerRef} style={{ width: '100%',
|
|
34
|
+
<div ref={containerRef} style={{ width: '100%', maxWidth: 440 }} />
|
|
36
35
|
</div>
|
|
37
36
|
);
|
|
38
37
|
}
|
|
@@ -53,9 +52,6 @@ const payment = new FlintNPayment({
|
|
|
53
52
|
console.log('Payment failed:', result.error);
|
|
54
53
|
}
|
|
55
54
|
},
|
|
56
|
-
onExpressPayment: (result) => {
|
|
57
|
-
console.log('Express payment:', result);
|
|
58
|
-
},
|
|
59
55
|
onReady: () => {
|
|
60
56
|
console.log('Widget ready');
|
|
61
57
|
},
|
|
@@ -76,7 +72,7 @@ payment.unmount();
|
|
|
76
72
|
<title>FlintN Checkout</title>
|
|
77
73
|
</head>
|
|
78
74
|
<body>
|
|
79
|
-
<div id="payment-container" style="max-width: 440px;
|
|
75
|
+
<div id="payment-container" style="max-width: 440px; margin: 0 auto;"></div>
|
|
80
76
|
|
|
81
77
|
<script type="module">
|
|
82
78
|
import { FlintNPayment } from 'flintn-checkout';
|
|
@@ -96,27 +92,36 @@ payment.unmount();
|
|
|
96
92
|
</html>
|
|
97
93
|
```
|
|
98
94
|
|
|
95
|
+
## Container Sizing
|
|
96
|
+
|
|
97
|
+
The widget auto-sizes to fit its content — you only need to set a width on the container. Height is managed by the SDK and updates automatically as the form changes state (loading, express view, card form, success).
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
<div ref={containerRef} style={{ width: '100%', maxWidth: 440 }} />
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Do **not** set a fixed `height` on the container — it will leave empty space below the widget when content is shorter than your hardcoded value, and the iframe never scrolls internally.
|
|
104
|
+
|
|
99
105
|
## Configuration
|
|
100
106
|
|
|
101
107
|
| Option | Type | Required | Default | Description |
|
|
102
108
|
|--------|------|----------|---------|-------------|
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
109
|
+
| `config` | `FlintNConfig` | Yes | — | Checkout configuration |
|
|
110
|
+
| `onPayment` | `(result: PaymentResult) => void` | No | — | Card payment result callback |
|
|
111
|
+
| `onReady` | `() => void` | No | — | Widget loaded and ready |
|
|
112
|
+
| `onError` | `(error: PaymentError) => void` | No | — | SDK initialization error |
|
|
113
|
+
| `debug` | `boolean` | No | `false` | Enable console debug logs |
|
|
107
114
|
|
|
108
|
-
|
|
115
|
+
### FlintNConfig
|
|
109
116
|
|
|
110
|
-
|
|
117
|
+
| Property | Type | Required | Description |
|
|
118
|
+
|----------|------|----------|-------------|
|
|
119
|
+
| `clientSessionId` | `string` | Yes | Client session ID from backend |
|
|
120
|
+
| `formFields` | `FormFields` | No | Form field visibility and requirements |
|
|
121
|
+
| `styles` | `FormStyles` | No | Custom styles for the checkout form |
|
|
122
|
+
| `successRedirectUrl` | `string` | No | Redirect URL after successful payment |
|
|
111
123
|
|
|
112
|
-
|
|
113
|
-
|----------|-------------|
|
|
114
|
-
| `onPayment` | Fired when card payment completes (success or error) |
|
|
115
|
-
| `onExpressPayment` | Fired when express payment completes (Apple Pay, Google Pay, PayPal) |
|
|
116
|
-
| `onReady` | Fired when widget is loaded and ready |
|
|
117
|
-
| `onError` | Fired on SDK initialization error |
|
|
118
|
-
|
|
119
|
-
## React Hook Return Values
|
|
124
|
+
### React Hook Return Values
|
|
120
125
|
|
|
121
126
|
| Value | Type | Description |
|
|
122
127
|
|-------|------|-------------|
|
|
@@ -125,7 +130,227 @@ payment.unmount();
|
|
|
125
130
|
| `paymentResult` | `PaymentResult \| null` | Result after payment attempt |
|
|
126
131
|
| `error` | `PaymentError \| null` | SDK error if any |
|
|
127
132
|
|
|
128
|
-
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Hosted Fields
|
|
136
|
+
|
|
137
|
+
Individual PCI-compliant input fields rendered as separate iframes. You control the layout, labels, and error display — the SDK handles card data securely.
|
|
138
|
+
|
|
139
|
+
Each field (card number, expiry, CVV) is a separate iframe. Raw card data never touches your page.
|
|
140
|
+
|
|
141
|
+
### React
|
|
142
|
+
```tsx
|
|
143
|
+
import { useState } from 'react';
|
|
144
|
+
import { useFlintNFields } from 'flintn-checkout/react';
|
|
145
|
+
|
|
146
|
+
function CheckoutForm() {
|
|
147
|
+
const [cardholderName, setCardholderName] = useState('');
|
|
148
|
+
|
|
149
|
+
const {
|
|
150
|
+
cardNumberRef,
|
|
151
|
+
expiryRef,
|
|
152
|
+
cvvRef,
|
|
153
|
+
isReady,
|
|
154
|
+
fieldErrors,
|
|
155
|
+
cardBrand,
|
|
156
|
+
paymentResult,
|
|
157
|
+
submit,
|
|
158
|
+
error,
|
|
159
|
+
} = useFlintNFields({
|
|
160
|
+
config: {
|
|
161
|
+
clientSessionId: 'your_client_session_id',
|
|
162
|
+
styles: {
|
|
163
|
+
inputBorderRadius: '8px',
|
|
164
|
+
inputBorderFocusColor: '#6366f1',
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
onPayment: (result) => {
|
|
168
|
+
if (result.status === 'PAYMENT_SUCCESS') {
|
|
169
|
+
console.log('Payment succeeded:', result.data);
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
debug: true,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
176
|
+
e.preventDefault();
|
|
177
|
+
const result = await submit({ cardholderName });
|
|
178
|
+
console.log('Payment result:', result);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<form onSubmit={handleSubmit}>
|
|
183
|
+
<label>Card Number {cardBrand && `(${cardBrand})`}</label>
|
|
184
|
+
<div ref={cardNumberRef} style={{ height: 40, marginBottom: 4 }} />
|
|
185
|
+
{fieldErrors['card-number'] && (
|
|
186
|
+
<span style={{ color: 'red' }}>{fieldErrors['card-number']}</span>
|
|
187
|
+
)}
|
|
188
|
+
|
|
189
|
+
<div style={{ display: 'flex', gap: 12 }}>
|
|
190
|
+
<div style={{ flex: 1 }}>
|
|
191
|
+
<label>Expiry</label>
|
|
192
|
+
<div ref={expiryRef} style={{ height: 40, marginBottom: 4 }} />
|
|
193
|
+
{fieldErrors['expiry'] && (
|
|
194
|
+
<span style={{ color: 'red' }}>{fieldErrors['expiry']}</span>
|
|
195
|
+
)}
|
|
196
|
+
</div>
|
|
197
|
+
<div style={{ flex: 1 }}>
|
|
198
|
+
<label>CVV</label>
|
|
199
|
+
<div ref={cvvRef} style={{ height: 40, marginBottom: 4 }} />
|
|
200
|
+
{fieldErrors['cvv'] && (
|
|
201
|
+
<span style={{ color: 'red' }}>{fieldErrors['cvv']}</span>
|
|
202
|
+
)}
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
<label>Cardholder Name</label>
|
|
207
|
+
<input
|
|
208
|
+
value={cardholderName}
|
|
209
|
+
onChange={(e) => setCardholderName(e.target.value)}
|
|
210
|
+
placeholder="John Doe"
|
|
211
|
+
/>
|
|
212
|
+
|
|
213
|
+
<button type="submit" disabled={!isReady}>
|
|
214
|
+
{isReady ? 'Pay' : 'Loading...'}
|
|
215
|
+
</button>
|
|
216
|
+
|
|
217
|
+
{error && <div style={{ color: 'red' }}>{error.message}</div>}
|
|
218
|
+
{paymentResult?.status === 'PAYMENT_ERROR' && paymentResult.error && (
|
|
219
|
+
<div style={{ color: 'red' }}>{paymentResult.error.message}</div>
|
|
220
|
+
)}
|
|
221
|
+
</form>
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Vanilla JavaScript
|
|
227
|
+
```javascript
|
|
228
|
+
import { FlintNFields } from 'flintn-checkout';
|
|
229
|
+
|
|
230
|
+
const fields = new FlintNFields({
|
|
231
|
+
config: {
|
|
232
|
+
clientSessionId: 'your_client_session_id',
|
|
233
|
+
styles: {
|
|
234
|
+
inputBorderRadius: '8px',
|
|
235
|
+
inputBorderFocusColor: '#6366f1',
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
onReady: () => console.log('All fields ready'),
|
|
239
|
+
onPayment: (result) => console.log('Payment result:', result),
|
|
240
|
+
onChange: (event) => console.log(`${event.fieldType}:`, event),
|
|
241
|
+
debug: true,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
const cardNumber = fields.createField('card-number', { placeholder: '4111 1111 1111 1111' });
|
|
245
|
+
const expiry = fields.createField('expiry', { placeholder: 'MM/YY' });
|
|
246
|
+
const cvv = fields.createField('cvv', { placeholder: 'CVC' });
|
|
247
|
+
|
|
248
|
+
cardNumber.mount('#card-number');
|
|
249
|
+
expiry.mount('#expiry');
|
|
250
|
+
cvv.mount('#cvv');
|
|
251
|
+
|
|
252
|
+
// Validate
|
|
253
|
+
const validation = await fields.validate();
|
|
254
|
+
if (validation.isValid) {
|
|
255
|
+
const result = await fields.submit({ cardholderName: 'John Doe' });
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Cleanup
|
|
259
|
+
fields.unmount();
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Hosted Fields Options (Vanilla JS)
|
|
263
|
+
|
|
264
|
+
| Option | Type | Required | Default | Description |
|
|
265
|
+
|--------|------|----------|---------|-------------|
|
|
266
|
+
| `config` | `FlintNFieldsConfig` | Yes | — | Fields configuration |
|
|
267
|
+
| `onPayment` | `(result: PaymentResult) => void` | No | — | Payment result callback |
|
|
268
|
+
| `onReady` | `() => void` | No | — | All fields loaded and ready |
|
|
269
|
+
| `onChange` | `(event: FieldChangeEvent) => void` | No | — | Field value changed |
|
|
270
|
+
| `onFocus` | `(fieldType: TFieldType) => void` | No | — | Field gained focus |
|
|
271
|
+
| `onBlur` | `(fieldType: TFieldType, state: FieldState) => void` | No | — | Field lost focus |
|
|
272
|
+
| `onError` | `(error: PaymentError) => void` | No | — | SDK initialization error |
|
|
273
|
+
| `debug` | `boolean` | No | `false` | Enable console debug logs |
|
|
274
|
+
|
|
275
|
+
### FlintNFieldsConfig
|
|
276
|
+
|
|
277
|
+
| Property | Type | Required | Description |
|
|
278
|
+
|----------|------|----------|-------------|
|
|
279
|
+
| `clientSessionId` | `string` | Yes | Client session ID from backend |
|
|
280
|
+
| `styles` | `FormStyles` | No | Styles applied to all hosted field inputs |
|
|
281
|
+
|
|
282
|
+
### React Hook Options
|
|
283
|
+
|
|
284
|
+
The `useFlintNFields` hook accepts `config`, `onPayment`, and `debug` from the options above. It manages `onReady`, `onChange`, `onFocus`, `onBlur`, and `onError` internally and exposes them as return values instead.
|
|
285
|
+
|
|
286
|
+
Additional React-only options:
|
|
287
|
+
|
|
288
|
+
| Option | Type | Description |
|
|
289
|
+
|--------|------|-------------|
|
|
290
|
+
| `fields.cardNumber` | `FieldOptions \| false` | Card number field options, or `false` to skip |
|
|
291
|
+
| `fields.expiry` | `FieldOptions \| false` | Expiry field options, or `false` to skip |
|
|
292
|
+
| `fields.cvv` | `FieldOptions \| false` | CVV field options, or `false` to skip |
|
|
293
|
+
| `onChange` | `(event: FieldChangeEvent) => void` | Optional additional callback |
|
|
294
|
+
| `onFocus` | `(fieldType: TFieldType) => void` | Optional additional callback |
|
|
295
|
+
| `onBlur` | `(fieldType: TFieldType, state: FieldState) => void` | Optional additional callback |
|
|
296
|
+
|
|
297
|
+
### FieldOptions
|
|
298
|
+
|
|
299
|
+
| Property | Type | Default | Description |
|
|
300
|
+
|----------|------|---------|-------------|
|
|
301
|
+
| `placeholder` | `string` | Field-specific default | Input placeholder text |
|
|
302
|
+
| `disabled` | `boolean` | `false` | Disable the input |
|
|
303
|
+
|
|
304
|
+
### React Hook Return Values
|
|
305
|
+
|
|
306
|
+
| Value | Type | Description |
|
|
307
|
+
|-------|------|-------------|
|
|
308
|
+
| `cardNumberRef` | `RefObject<HTMLDivElement>` | Ref for card number container |
|
|
309
|
+
| `expiryRef` | `RefObject<HTMLDivElement>` | Ref for expiry container |
|
|
310
|
+
| `cvvRef` | `RefObject<HTMLDivElement>` | Ref for CVV container |
|
|
311
|
+
| `isReady` | `boolean` | All fields loaded and ready |
|
|
312
|
+
| `fieldErrors` | `Partial<Record<TFieldType, string \| null>>` | Per-field validation errors (populated after first submit) |
|
|
313
|
+
| `fieldStates` | `Partial<Record<TFieldType, FieldState>>` | Per-field state (always up to date) |
|
|
314
|
+
| `cardBrand` | `string \| null` | Detected card brand (e.g. `"visa"`, `"mastercard"`) |
|
|
315
|
+
| `paymentResult` | `PaymentResult \| null` | Result after payment attempt |
|
|
316
|
+
| `error` | `PaymentError \| null` | SDK error if any |
|
|
317
|
+
| `validate` | `() => Promise<FieldsValidationResult>` | Validate all fields |
|
|
318
|
+
| `submit` | `(options?: SubmitOptions) => Promise<PaymentResult>` | Validate and submit payment |
|
|
319
|
+
| `focusField` | `(fieldType: TFieldType) => void` | Focus a field programmatically |
|
|
320
|
+
| `clearField` | `(fieldType: TFieldType) => void` | Clear a field |
|
|
321
|
+
| `clearAll` | `() => void` | Clear all fields |
|
|
322
|
+
|
|
323
|
+
### Validation Behavior
|
|
324
|
+
|
|
325
|
+
Validation mirrors react-hook-form `mode: 'onSubmit'`:
|
|
326
|
+
|
|
327
|
+
- Before first submit: `fieldErrors` is always `{}`
|
|
328
|
+
- After first submit: errors update on every field change (revalidation)
|
|
329
|
+
- Card number changes trigger CVV revalidation (CVV length depends on card brand)
|
|
330
|
+
- All three fields (card number, expiry, CVV) are required — submitting with a missing field returns a `MISSING_FIELDS` error
|
|
331
|
+
|
|
332
|
+
### Field Types
|
|
333
|
+
|
|
334
|
+
| Value | Description |
|
|
335
|
+
|-------|-------------|
|
|
336
|
+
| `'card-number'` | Card number input with automatic formatting and brand detection |
|
|
337
|
+
| `'expiry'` | Expiry date input (MM/YY format) |
|
|
338
|
+
| `'cvv'` | CVV/CVC input (3 or 4 digits depending on card brand) |
|
|
339
|
+
|
|
340
|
+
### Individual Field Methods (Vanilla JS)
|
|
341
|
+
|
|
342
|
+
| Method | Description |
|
|
343
|
+
|--------|-------------|
|
|
344
|
+
| `field.mount(selector)` | Mount field into a DOM element |
|
|
345
|
+
| `field.unmount()` | Remove field from DOM |
|
|
346
|
+
| `field.focus()` | Focus the field |
|
|
347
|
+
| `field.clear()` | Clear the field value |
|
|
348
|
+
| `field.getState()` | Get current field state |
|
|
349
|
+
| `field.getFieldType()` | Get the field type |
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Shared Types
|
|
129
354
|
|
|
130
355
|
### PaymentResult
|
|
131
356
|
```typescript
|
|
@@ -147,12 +372,42 @@ interface PaymentError {
|
|
|
147
372
|
}
|
|
148
373
|
```
|
|
149
374
|
|
|
375
|
+
### FieldState
|
|
376
|
+
```typescript
|
|
377
|
+
interface FieldState {
|
|
378
|
+
isEmpty: boolean;
|
|
379
|
+
isValid: boolean;
|
|
380
|
+
isFocused: boolean;
|
|
381
|
+
error: string | null;
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### FieldChangeEvent
|
|
386
|
+
```typescript
|
|
387
|
+
interface FieldChangeEvent {
|
|
388
|
+
fieldType: 'card-number' | 'expiry' | 'cvv';
|
|
389
|
+
isEmpty: boolean;
|
|
390
|
+
isValid: boolean;
|
|
391
|
+
isFocused: boolean;
|
|
392
|
+
error: string | null;
|
|
393
|
+
cardBrand?: string; // Only for card-number
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### FieldsValidationResult
|
|
398
|
+
```typescript
|
|
399
|
+
interface FieldsValidationResult {
|
|
400
|
+
isValid: boolean;
|
|
401
|
+
errors: Partial<Record<'card-number' | 'expiry' | 'cvv', string | null>>;
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
150
405
|
### FormFields
|
|
151
406
|
```typescript
|
|
152
407
|
interface FormFields {
|
|
153
|
-
isEmailVisible?: boolean;
|
|
408
|
+
isEmailVisible?: boolean; // Primer only
|
|
154
409
|
isCardholderNameRequired?: boolean; // Primer only
|
|
155
|
-
formVariant?: 'DEFAULT' | 'LIST';
|
|
410
|
+
formVariant?: 'DEFAULT' | 'LIST' | 'RADIO';
|
|
156
411
|
}
|
|
157
412
|
```
|
|
158
413
|
|
|
@@ -181,52 +436,59 @@ interface FormStyles {
|
|
|
181
436
|
|
|
182
437
|
### FormStyles Reference
|
|
183
438
|
|
|
184
|
-
| Property | Description |
|
|
185
|
-
|
|
186
|
-
| `loaderColor` |
|
|
187
|
-
| `backgroundColor` |
|
|
188
|
-
| `expressButtonsSpacing` | Spacing between express payment buttons
|
|
189
|
-
| `inputBackgroundColor` |
|
|
190
|
-
| `inputBorderRadius` |
|
|
191
|
-
| `inputBorderColor` |
|
|
192
|
-
| `inputBorderHoverColor` |
|
|
193
|
-
| `inputBorderFocusColor` |
|
|
194
|
-
| `inputBorderErrorColor` |
|
|
195
|
-
| `errorMessageColor` |
|
|
196
|
-
| `buttonColor` |
|
|
197
|
-
| `buttonHoverColor` |
|
|
198
|
-
| `buttonBorderRadius` |
|
|
199
|
-
| `buttonText` |
|
|
200
|
-
| `cardButtonColor` |
|
|
201
|
-
| `cardButtonHoverColor` |
|
|
202
|
-
| `cardButtonText` |
|
|
439
|
+
| Property | Iframe Checkout | Hosted Fields | Description |
|
|
440
|
+
|----------|:-:|:-:|-------------|
|
|
441
|
+
| `loaderColor` | ✅ | — | Loading spinner color |
|
|
442
|
+
| `backgroundColor` | ✅ | — | Form background color |
|
|
443
|
+
| `expressButtonsSpacing` | ✅ | — | Spacing between express payment buttons |
|
|
444
|
+
| `inputBackgroundColor` | ✅ | ✅ | Input field background color |
|
|
445
|
+
| `inputBorderRadius` | ✅ | ✅ | Input field border radius |
|
|
446
|
+
| `inputBorderColor` | ✅ | ✅ | Default input border color |
|
|
447
|
+
| `inputBorderHoverColor` | ✅ | ✅ | Input border color on hover |
|
|
448
|
+
| `inputBorderFocusColor` | ✅ | ✅ | Input border color on focus |
|
|
449
|
+
| `inputBorderErrorColor` | ✅ | ✅ | Input border color in error state |
|
|
450
|
+
| `errorMessageColor` | ✅ | — | Error message text color |
|
|
451
|
+
| `buttonColor` | ✅ | — | Submit button background color |
|
|
452
|
+
| `buttonHoverColor` | ✅ | — | Submit button hover color |
|
|
453
|
+
| `buttonBorderRadius` | ✅ | — | Submit button border radius |
|
|
454
|
+
| `buttonText` | ✅ | — | Custom submit button text |
|
|
455
|
+
| `cardButtonColor` | ✅ | — | Card button color (LIST variant) |
|
|
456
|
+
| `cardButtonHoverColor` | ✅ | — | Card button hover color (LIST variant) |
|
|
457
|
+
| `cardButtonText` | ✅ | — | Custom card button text (LIST variant) |
|
|
203
458
|
|
|
204
459
|
## Form Variants
|
|
205
460
|
|
|
206
|
-
The checkout
|
|
461
|
+
The iframe checkout supports three layout variants via `formFields.formVariant`:
|
|
207
462
|
|
|
208
|
-
- **DEFAULT** — Express payment methods shown above the card form with dividers
|
|
209
|
-
- **LIST** — Express payment methods shown
|
|
463
|
+
- **DEFAULT** — Express payment methods shown above the card form with dividers.
|
|
464
|
+
- **LIST** — Express payment methods shown first; users tap a "Credit or Debit Card" button to navigate to the card form, with a back arrow to return to the express view.
|
|
465
|
+
- **RADIO** — Express payments and the card form are presented as two radio options ("Fast checkout" and "Card payment"). Selecting a radio expands its section and collapses the other. The card payment radio shows accepted card brand logos inline with its label.
|
|
466
|
+
|
|
467
|
+
LIST and RADIO automatically fall back to the DEFAULT layout when no express payment methods are available, since there's nothing to toggle between. The `cardButtonColor`, `cardButtonHoverColor`, and `cardButtonText` style overrides apply only to the LIST variant's "Credit or Debit Card" button.
|
|
210
468
|
|
|
211
469
|
## Supported Payment Methods
|
|
212
470
|
|
|
213
|
-
|
|
214
|
-
-
|
|
215
|
-
-
|
|
216
|
-
-
|
|
471
|
+
### Iframe Checkout
|
|
472
|
+
- Credit/Debit Cards (Visa, Mastercard, Amex, Discover)
|
|
473
|
+
- Apple Pay
|
|
474
|
+
- Google Pay
|
|
475
|
+
- PayPal
|
|
476
|
+
|
|
477
|
+
### Hosted Fields
|
|
478
|
+
- Credit/Debit Cards (Visa, Mastercard, Amex, Discover)
|
|
217
479
|
|
|
218
480
|
## Debug Mode
|
|
219
481
|
|
|
220
482
|
Enable debug logs in console:
|
|
221
483
|
```typescript
|
|
222
|
-
//
|
|
484
|
+
// Iframe Checkout
|
|
223
485
|
useFlintNPayment({
|
|
224
486
|
config: { clientSessionId: '...' },
|
|
225
487
|
debug: true,
|
|
226
488
|
});
|
|
227
489
|
|
|
228
|
-
//
|
|
229
|
-
|
|
490
|
+
// Hosted Fields
|
|
491
|
+
useFlintNFields({
|
|
230
492
|
config: { clientSessionId: '...' },
|
|
231
493
|
debug: true,
|
|
232
494
|
});
|
package/dist/index.d.mts
CHANGED
|
@@ -7,11 +7,13 @@ declare const EventType: {
|
|
|
7
7
|
readonly PAYMENT_ERROR: "PAYMENT_ERROR";
|
|
8
8
|
readonly PAYMENT_CANCELLED: "PAYMENT_CANCELLED";
|
|
9
9
|
readonly REDIRECT: "REDIRECT";
|
|
10
|
+
readonly RESIZE: "RESIZE";
|
|
10
11
|
};
|
|
11
12
|
type TEventType = (typeof EventType)[keyof typeof EventType];
|
|
12
13
|
declare const CheckoutFormVariant: {
|
|
13
14
|
readonly DEFAULT: "DEFAULT";
|
|
14
15
|
readonly LIST: "LIST";
|
|
16
|
+
readonly RADIO: "RADIO";
|
|
15
17
|
};
|
|
16
18
|
type TCheckoutFormVariant = (typeof CheckoutFormVariant)[keyof typeof CheckoutFormVariant];
|
|
17
19
|
interface FormFields {
|
|
@@ -65,24 +67,109 @@ interface FlintNPaymentOptions {
|
|
|
65
67
|
onError?: (error: PaymentError) => void;
|
|
66
68
|
debug?: boolean;
|
|
67
69
|
}
|
|
70
|
+
declare const FieldType: {
|
|
71
|
+
readonly CARD_NUMBER: "card-number";
|
|
72
|
+
readonly EXPIRY: "expiry";
|
|
73
|
+
readonly CVV: "cvv";
|
|
74
|
+
};
|
|
75
|
+
type TFieldType = (typeof FieldType)[keyof typeof FieldType];
|
|
76
|
+
declare const FieldEventType: {
|
|
77
|
+
readonly FIELD_CONFIG: "FIELD_CONFIG";
|
|
78
|
+
readonly FIELD_VALIDATE: "FIELD_VALIDATE";
|
|
79
|
+
readonly FIELD_SUBMIT: "FIELD_SUBMIT";
|
|
80
|
+
readonly FIELD_FOCUS_REQUEST: "FIELD_FOCUS_REQUEST";
|
|
81
|
+
readonly FIELD_CLEAR: "FIELD_CLEAR";
|
|
82
|
+
readonly FIELD_READY: "FIELD_READY";
|
|
83
|
+
readonly FIELD_CHANGE: "FIELD_CHANGE";
|
|
84
|
+
readonly FIELD_FOCUS: "FIELD_FOCUS";
|
|
85
|
+
readonly FIELD_BLUR: "FIELD_BLUR";
|
|
86
|
+
readonly FIELD_VALIDATION: "FIELD_VALIDATION";
|
|
87
|
+
readonly FIELD_SUBMIT_RESULT: "FIELD_SUBMIT_RESULT";
|
|
88
|
+
readonly FIELD_HEIGHT: "FIELD_HEIGHT";
|
|
89
|
+
};
|
|
90
|
+
type TFieldEventType = (typeof FieldEventType)[keyof typeof FieldEventType];
|
|
91
|
+
interface FieldOptions {
|
|
92
|
+
placeholder?: string;
|
|
93
|
+
disabled?: boolean;
|
|
94
|
+
}
|
|
95
|
+
interface FieldState {
|
|
96
|
+
isEmpty: boolean;
|
|
97
|
+
isValid: boolean;
|
|
98
|
+
isFocused: boolean;
|
|
99
|
+
error: string | null;
|
|
100
|
+
}
|
|
101
|
+
interface FieldChangeEvent {
|
|
102
|
+
fieldType: TFieldType;
|
|
103
|
+
isEmpty: boolean;
|
|
104
|
+
isValid: boolean;
|
|
105
|
+
isFocused: boolean;
|
|
106
|
+
error: string | null;
|
|
107
|
+
cardBrand?: string;
|
|
108
|
+
}
|
|
109
|
+
interface FieldValidationResult {
|
|
110
|
+
fieldType: TFieldType;
|
|
111
|
+
isValid: boolean;
|
|
112
|
+
error: string | null;
|
|
113
|
+
}
|
|
114
|
+
interface FieldsValidationResult {
|
|
115
|
+
isValid: boolean;
|
|
116
|
+
errors: Partial<Record<TFieldType, string | null>>;
|
|
117
|
+
}
|
|
118
|
+
interface SubmitOptions {
|
|
119
|
+
cardholderName?: string;
|
|
120
|
+
}
|
|
121
|
+
interface FlintNFieldsConfig {
|
|
122
|
+
clientSessionId: string;
|
|
123
|
+
styles?: FormStyles;
|
|
124
|
+
}
|
|
125
|
+
interface FlintNFieldsOptions {
|
|
126
|
+
origin?: string;
|
|
127
|
+
config: FlintNFieldsConfig;
|
|
128
|
+
onPayment?: (result: PaymentResult) => void;
|
|
129
|
+
onReady?: () => void;
|
|
130
|
+
onChange?: (event: FieldChangeEvent) => void;
|
|
131
|
+
onFocus?: (fieldType: TFieldType) => void;
|
|
132
|
+
onBlur?: (fieldType: TFieldType, state: FieldState) => void;
|
|
133
|
+
onError?: (error: PaymentError) => void;
|
|
134
|
+
debug?: boolean;
|
|
135
|
+
}
|
|
68
136
|
|
|
69
|
-
|
|
70
|
-
private options;
|
|
71
|
-
private origin;
|
|
72
|
-
private iframe;
|
|
73
|
-
private container;
|
|
74
|
-
private isReady;
|
|
75
|
-
private messageHandler;
|
|
76
|
-
constructor(options: FlintNPaymentOptions);
|
|
137
|
+
interface FlintNPayment {
|
|
77
138
|
mount(selector: string | HTMLElement): void;
|
|
78
139
|
unmount(): void;
|
|
79
140
|
getIsReady(): boolean;
|
|
80
|
-
private handleMessage;
|
|
81
|
-
private isValidRedirectUrl;
|
|
82
|
-
private handlePaymentResult;
|
|
83
|
-
private sendConfig;
|
|
84
|
-
private log;
|
|
85
141
|
}
|
|
142
|
+
declare function createFlintNPayment(options: FlintNPaymentOptions): FlintNPayment;
|
|
143
|
+
|
|
144
|
+
interface FlintNFieldInternalCallbacks {
|
|
145
|
+
onReady: (fieldType: TFieldType) => void;
|
|
146
|
+
onChange: (event: FieldChangeEvent) => void;
|
|
147
|
+
onFocus: (fieldType: TFieldType) => void;
|
|
148
|
+
onBlur: (fieldType: TFieldType, state: FieldState) => void;
|
|
149
|
+
onHeight: (fieldType: TFieldType, height: number) => void;
|
|
150
|
+
}
|
|
151
|
+
interface FlintNField {
|
|
152
|
+
mount(selector: string | HTMLElement): void;
|
|
153
|
+
unmount(): void;
|
|
154
|
+
focus(): void;
|
|
155
|
+
clear(): void;
|
|
156
|
+
getState(): FieldState;
|
|
157
|
+
getFieldType(): TFieldType;
|
|
158
|
+
_sendMessage(type: string, payload: unknown): void;
|
|
159
|
+
_getIframe(): HTMLIFrameElement | null;
|
|
160
|
+
_handleMessage(type: string, payload: Record<string, unknown>): void;
|
|
161
|
+
}
|
|
162
|
+
declare function createFlintNField(fieldType: TFieldType, origin: string, clientSessionId: string, options: FieldOptions, callbacks: FlintNFieldInternalCallbacks, debug?: boolean, formStyles?: FormStyles): FlintNField;
|
|
163
|
+
|
|
164
|
+
interface FlintNFields {
|
|
165
|
+
createField(fieldType: TFieldType, options?: FieldOptions): FlintNField;
|
|
166
|
+
getField(fieldType: TFieldType): FlintNField | undefined;
|
|
167
|
+
validate(): Promise<FieldsValidationResult>;
|
|
168
|
+
submit(options?: SubmitOptions, skipValidation?: boolean): Promise<PaymentResult>;
|
|
169
|
+
unmount(): void;
|
|
170
|
+
getIsReady(): boolean;
|
|
171
|
+
}
|
|
172
|
+
declare function createFlintNFields(options: FlintNFieldsOptions): FlintNFields;
|
|
86
173
|
|
|
87
174
|
declare const parseOrigin: (origin: string) => string;
|
|
88
175
|
declare const buildIframeSrc: (origin: string) => string;
|
|
@@ -92,4 +179,4 @@ declare const validateConfig: (config: {
|
|
|
92
179
|
}) => void;
|
|
93
180
|
declare const sanitizeToken: (token: string) => string;
|
|
94
181
|
|
|
95
|
-
export { CheckoutFormVariant, EventType, type FlintNConfig, FlintNPayment, type FlintNPaymentOptions, type FormFields, type FormStyles, type PaymentError, type PaymentResult, type TCheckoutFormVariant, type TEventType, buildIframeSrc, createIframeElement, parseOrigin, sanitizeToken, validateConfig };
|
|
182
|
+
export { CheckoutFormVariant, EventType, type FieldChangeEvent, FieldEventType, type FieldOptions, type FieldState, FieldType, type FieldValidationResult, type FieldsValidationResult, type FlintNConfig, type FlintNField, type FlintNFieldInternalCallbacks, type FlintNFields, type FlintNFieldsConfig, type FlintNFieldsOptions, type FlintNPayment, type FlintNPaymentOptions, type FormFields, type FormStyles, type PaymentError, type PaymentResult, type SubmitOptions, type TCheckoutFormVariant, type TEventType, type TFieldEventType, type TFieldType, buildIframeSrc, createFlintNField, createFlintNFields, createFlintNPayment, createIframeElement, parseOrigin, sanitizeToken, validateConfig };
|