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