@paypercut/checkout-js 1.0.10 → 1.0.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 +244 -112
- package/dist/index.cjs +28 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.mjs +28 -6
- package/dist/index.mjs.map +1 -1
- package/dist/paypercut-checkout.iife.min.js +1 -1
- package/dist/paypercut-checkout.iife.min.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,12 +54,12 @@ pnpm add @paypercut/checkout-js
|
|
|
54
54
|
|
|
55
55
|
```html
|
|
56
56
|
<!-- jsDelivr (recommended with SRI) -->
|
|
57
|
-
<script src="https://cdn.jsdelivr.net/npm/@paypercut/checkout-js@1.0.
|
|
57
|
+
<script src="https://cdn.jsdelivr.net/npm/@paypercut/checkout-js@1.0.12/dist/paypercut-checkout.iife.min.js"
|
|
58
58
|
integrity="sha384-..."
|
|
59
59
|
crossorigin="anonymous"></script>
|
|
60
60
|
|
|
61
61
|
<!-- or UNPKG -->
|
|
62
|
-
<script src="https://unpkg.com/@paypercut/checkout-js@1.0.
|
|
62
|
+
<script src="https://unpkg.com/@paypercut/checkout-js@1.0.12/dist/paypercut-checkout.iife.min.js"></script>
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
---
|
|
@@ -118,12 +118,18 @@ Creates a new checkout instance.
|
|
|
118
118
|
|
|
119
119
|
#### Options
|
|
120
120
|
|
|
121
|
-
| Option | Type | Required | Description |
|
|
122
|
-
|
|
123
|
-
| `id` | `string` | Yes
|
|
124
|
-
| `containerId` | `string \| HTMLElement` | Yes
|
|
121
|
+
| Option | Type | Required | Default | Description |
|
|
122
|
+
|--------|------|----------|---------|-------------|
|
|
123
|
+
| `id` | `string` | Yes | — | Checkout session identifier (e.g., `CHK_12345`) |
|
|
124
|
+
| `containerId` | `string \| HTMLElement` | Yes | — | CSS selector or element where iframe mounts |
|
|
125
|
+
| `locale` | `string` | No | `'auto'` | Locale for checkout UI. Options: `'auto'`, `'en'`, `'en-GB'`, `'bg'`, `'bg-BG'` |
|
|
126
|
+
| `ui_mode` | `'hosted' \| 'embedded'` | No | `'embedded'` | UI mode for checkout display |
|
|
127
|
+
| `wallet_options` | `string[]` | No | `['apple_pay', 'google_pay']` | Digital wallet options. Pass `[]` to disable all wallets |
|
|
128
|
+
| `form_only` | `boolean` | No | `false` | Show only payment form (no Pay Now button - use external button with `submit()`) |
|
|
125
129
|
|
|
126
|
-
####
|
|
130
|
+
#### Examples
|
|
131
|
+
|
|
132
|
+
**Basic initialization:**
|
|
127
133
|
|
|
128
134
|
```typescript
|
|
129
135
|
const checkout = PaypercutCheckout({
|
|
@@ -132,6 +138,54 @@ const checkout = PaypercutCheckout({
|
|
|
132
138
|
});
|
|
133
139
|
```
|
|
134
140
|
|
|
141
|
+
**With all options:**
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
const checkout = PaypercutCheckout({
|
|
145
|
+
id: 'CHK_12345',
|
|
146
|
+
containerId: '#checkout-container',
|
|
147
|
+
locale: 'en', // 'auto' | 'en' | 'en-GB' | 'bg' | 'bg-BG'
|
|
148
|
+
ui_mode: 'embedded', // 'hosted' | 'embedded'
|
|
149
|
+
wallet_options: ['apple_pay', 'google_pay'], // Can be empty array [] or contain one/both options
|
|
150
|
+
form_only: false // Set true to hide Pay Now button (use external button)
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Disable wallet payments:**
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
const checkout = PaypercutCheckout({
|
|
158
|
+
id: 'CHK_12345',
|
|
159
|
+
containerId: '#checkout-container',
|
|
160
|
+
wallet_options: [] // No Apple Pay or Google Pay buttons
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Only Apple Pay:**
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
const checkout = PaypercutCheckout({
|
|
168
|
+
id: 'CHK_12345',
|
|
169
|
+
containerId: '#checkout-container',
|
|
170
|
+
wallet_options: ['apple_pay'] // Only Apple Pay, no Google Pay
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Form-only mode (external submit button):**
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
const checkout = PaypercutCheckout({
|
|
178
|
+
id: 'CHK_12345',
|
|
179
|
+
containerId: '#checkout-container',
|
|
180
|
+
form_only: true // No Pay Now button inside checkout
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Use your own button to trigger payment
|
|
184
|
+
document.getElementById('my-pay-button').addEventListener('click', () => {
|
|
185
|
+
checkout.submit();
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
135
189
|
### Instance Methods
|
|
136
190
|
|
|
137
191
|
#### `render()`
|
|
@@ -197,97 +251,50 @@ if (checkout.isMounted()) {
|
|
|
197
251
|
|
|
198
252
|
## Events
|
|
199
253
|
|
|
200
|
-
Subscribe to events using the `on()` method
|
|
201
|
-
|
|
202
|
-
| Event | Description | Payload |
|
|
203
|
-
|-------|-------------|---------|
|
|
204
|
-
| `loaded` | Checkout iframe has finished loading | `void` |
|
|
205
|
-
| `success` | Payment completed successfully | `PaymentSuccessPayload` |
|
|
206
|
-
| `error` | Terminal failure (tokenize, confirm, or 3DS) | `ApiErrorPayload` (see details below) |
|
|
207
|
-
| `expired` | Checkout session expired | `void` |
|
|
208
|
-
| `threeds_started` | 3DS challenge flow started; SDK modal opened | `object` (flow context) |
|
|
209
|
-
| `threeds_complete` | 3DS challenge completed | `object` (auth result context) |
|
|
210
|
-
| `threeds_canceled` | 3DS challenge canceled by user | `object` (flow context) |
|
|
211
|
-
| `threeds_error` | 3DS challenge error | `ApiErrorPayload` (if provided) or `object` |
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
#### Success payload example
|
|
215
|
-
|
|
216
|
-
```ts
|
|
217
|
-
checkout.on('success', (payload) => {
|
|
218
|
-
// payload: PaymentSuccessPayload
|
|
219
|
-
// Example:
|
|
220
|
-
// {
|
|
221
|
-
// payment_method: {
|
|
222
|
-
// brand: 'visa',
|
|
223
|
-
// last4: '4242',
|
|
224
|
-
// exp_month: 12,
|
|
225
|
-
// exp_year: 2030,
|
|
226
|
-
// }
|
|
227
|
-
// }
|
|
228
|
-
console.log('PM last4', payload.payment_method.last4);
|
|
229
|
-
});
|
|
230
|
-
```
|
|
254
|
+
Subscribe to events using the `on()` method. You can use string event names or the `SdkEvent` enum.
|
|
231
255
|
|
|
232
|
-
|
|
256
|
+
### Event Reference
|
|
233
257
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
case 'threeds_authentication_failed':
|
|
245
|
-
case 'threeds_canceled':
|
|
246
|
-
// 3DS issue. Some servers use status_code 424 with a detailed message.
|
|
247
|
-
break;
|
|
248
|
-
default:
|
|
249
|
-
// Other terminal errors (e.g., authentication_failed, session_expired)
|
|
250
|
-
break;
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
```
|
|
258
|
+
| Event | Enum | Description | Payload |
|
|
259
|
+
|-------|------|-------------|---------|
|
|
260
|
+
| `loaded` | `SdkEvent.Loaded` | Checkout iframe has finished loading | `void` |
|
|
261
|
+
| `success` | `SdkEvent.Success` | Payment completed successfully | `PaymentSuccessPayload` |
|
|
262
|
+
| `error` | `SdkEvent.Error` | Terminal failure (tokenize, confirm, or 3DS) | `ApiErrorPayload` |
|
|
263
|
+
| `expired` | `SdkEvent.Expired` | Checkout session expired | `void` |
|
|
264
|
+
| `threeds_started` | `SdkEvent.ThreeDSStarted` | 3DS challenge flow started | `object` |
|
|
265
|
+
| `threeds_complete` | `SdkEvent.ThreeDSComplete` | 3DS challenge completed | `object` |
|
|
266
|
+
| `threeds_canceled` | `SdkEvent.ThreeDSCanceled` | 3DS challenge canceled by user | `object` |
|
|
267
|
+
| `threeds_error` | `SdkEvent.ThreeDSError` | 3DS challenge error | `ApiErrorPayload` or `object` |
|
|
254
268
|
|
|
255
|
-
###
|
|
269
|
+
### Usage Examples
|
|
256
270
|
|
|
257
|
-
|
|
271
|
+
**Using string event names:**
|
|
258
272
|
|
|
259
273
|
```ts
|
|
260
|
-
import { PaypercutCheckout, SdkEvent } from '@paypercut/checkout-js';
|
|
261
|
-
|
|
262
274
|
const checkout = PaypercutCheckout({ id: 'CHK_12345', containerId: '#checkout' });
|
|
263
275
|
|
|
264
|
-
checkout.on(
|
|
265
|
-
|
|
276
|
+
checkout.on('loaded', () => {
|
|
277
|
+
console.log('Checkout loaded');
|
|
266
278
|
});
|
|
267
279
|
|
|
268
|
-
checkout.on(
|
|
269
|
-
//
|
|
280
|
+
checkout.on('success', (payload) => {
|
|
281
|
+
// PaymentSuccessPayload
|
|
282
|
+
console.log('Payment successful');
|
|
283
|
+
console.log('Card brand:', payload.payment_method.brand);
|
|
284
|
+
console.log('Last 4:', payload.payment_method.last4);
|
|
285
|
+
console.log('Expiry:', payload.payment_method.exp_month + '/' + payload.payment_method.exp_year);
|
|
270
286
|
});
|
|
271
287
|
|
|
272
|
-
checkout.on(
|
|
273
|
-
|
|
288
|
+
checkout.on('error', (err) => {
|
|
289
|
+
console.error('Payment error:', err.code, err.message);
|
|
274
290
|
});
|
|
275
291
|
|
|
276
|
-
checkout.on(
|
|
277
|
-
|
|
278
|
-
console.error('3DS error:', err);
|
|
292
|
+
checkout.on('expired', () => {
|
|
293
|
+
console.warn('Checkout session expired');
|
|
279
294
|
});
|
|
280
295
|
```
|
|
281
296
|
|
|
282
|
-
|
|
283
|
-
- `error`: the SDK forwards a normalized `ApiErrorPayload` when provided by Hosted Checkout.
|
|
284
|
-
- `threeds_error`: forwards `payload.error` when available; otherwise the raw message data.
|
|
285
|
-
- `threeds_*` non-error events: payload is forwarded as-is from Hosted Checkout (shape may evolve).
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
### Core events (loaded, success, error, expired)
|
|
289
|
-
|
|
290
|
-
Using enums:
|
|
297
|
+
**Using SdkEvent enum (recommended for TypeScript):**
|
|
291
298
|
|
|
292
299
|
```ts
|
|
293
300
|
import { PaypercutCheckout, SdkEvent } from '@paypercut/checkout-js';
|
|
@@ -303,48 +310,98 @@ checkout.on(SdkEvent.Success, (payload) => {
|
|
|
303
310
|
});
|
|
304
311
|
|
|
305
312
|
checkout.on(SdkEvent.Error, (err) => {
|
|
306
|
-
// err: ApiErrorPayload
|
|
307
313
|
console.error('Payment error:', err.code, err.message);
|
|
308
314
|
});
|
|
309
315
|
|
|
310
316
|
checkout.on(SdkEvent.Expired, () => {
|
|
311
317
|
console.warn('Checkout session expired');
|
|
312
318
|
});
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
Or with string event names:
|
|
316
319
|
|
|
317
|
-
|
|
318
|
-
checkout.on(
|
|
319
|
-
|
|
320
|
-
console.log('Payment successful', payload.payment_method);
|
|
320
|
+
// 3DS events
|
|
321
|
+
checkout.on(SdkEvent.ThreeDSStarted, (ctx) => {
|
|
322
|
+
console.log('3DS challenge started');
|
|
321
323
|
});
|
|
322
|
-
|
|
323
|
-
|
|
324
|
+
|
|
325
|
+
checkout.on(SdkEvent.ThreeDSComplete, (payload) => {
|
|
326
|
+
console.log('3DS completed');
|
|
324
327
|
});
|
|
325
|
-
checkout.on('expired', () => {});
|
|
326
|
-
```
|
|
327
328
|
|
|
329
|
+
checkout.on(SdkEvent.ThreeDSCanceled, (payload) => {
|
|
330
|
+
console.log('3DS canceled by user');
|
|
331
|
+
});
|
|
328
332
|
|
|
329
|
-
|
|
333
|
+
checkout.on(SdkEvent.ThreeDSError, (err) => {
|
|
334
|
+
console.error('3DS error:', err);
|
|
335
|
+
});
|
|
336
|
+
```
|
|
330
337
|
|
|
331
|
-
### Payload
|
|
338
|
+
### Success Payload
|
|
332
339
|
|
|
333
|
-
|
|
340
|
+
The `success` event returns a `PaymentSuccessPayload` with the payment method details:
|
|
334
341
|
|
|
335
342
|
```ts
|
|
336
|
-
// Payload for `checkout.on('success', (payload))`
|
|
337
343
|
type PaymentSuccessPayload = {
|
|
338
344
|
payment_method: {
|
|
339
|
-
brand: string;
|
|
340
|
-
last4: string;
|
|
341
|
-
exp_month: number;
|
|
342
|
-
exp_year: number;
|
|
345
|
+
brand: string; // e.g., 'visa', 'mastercard', 'amex'
|
|
346
|
+
last4: string; // Last 4 digits of card number
|
|
347
|
+
exp_month: number; // Expiration month (1-12)
|
|
348
|
+
exp_year: number; // Expiration year (e.g., 2030)
|
|
343
349
|
};
|
|
344
350
|
};
|
|
345
351
|
```
|
|
346
352
|
|
|
347
|
-
|
|
353
|
+
**Example:**
|
|
354
|
+
|
|
355
|
+
```ts
|
|
356
|
+
checkout.on('success', (payload) => {
|
|
357
|
+
// payload:
|
|
358
|
+
// {
|
|
359
|
+
// payment_method: {
|
|
360
|
+
// brand: 'visa',
|
|
361
|
+
// last4: '4242',
|
|
362
|
+
// exp_month: 12,
|
|
363
|
+
// exp_year: 2030
|
|
364
|
+
// }
|
|
365
|
+
// }
|
|
366
|
+
|
|
367
|
+
console.log(`Paid with ${payload.payment_method.brand} ending in ${payload.payment_method.last4}`);
|
|
368
|
+
// Output: "Paid with visa ending in 4242"
|
|
369
|
+
});
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Error Handling
|
|
373
|
+
|
|
374
|
+
```ts
|
|
375
|
+
checkout.on('error', (err) => {
|
|
376
|
+
switch (err.code) {
|
|
377
|
+
case 'card_validation_error':
|
|
378
|
+
// err.errors[] has field-level issues. Messages are localized.
|
|
379
|
+
break;
|
|
380
|
+
case 'card_declined':
|
|
381
|
+
// Optional err.decline_code and user-friendly err.message
|
|
382
|
+
break;
|
|
383
|
+
case 'threeds_error':
|
|
384
|
+
case 'threeds_authentication_failed':
|
|
385
|
+
case 'threeds_canceled':
|
|
386
|
+
// 3DS issue. Some servers use status_code 424 with a detailed message.
|
|
387
|
+
break;
|
|
388
|
+
default:
|
|
389
|
+
// Other terminal errors (e.g., authentication_failed, session_expired)
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Notes
|
|
396
|
+
|
|
397
|
+
- `error`: the SDK forwards a normalized `ApiErrorPayload` when provided by Hosted Checkout.
|
|
398
|
+
- `threeds_error`: forwards `payload.error` when available; otherwise the raw message data.
|
|
399
|
+
- `threeds_*` non-error events: payload is forwarded as-is from Hosted Checkout (shape may evolve).
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
## Types
|
|
403
|
+
|
|
404
|
+
### ApiErrorPayload
|
|
348
405
|
|
|
349
406
|
The SDK forwards the error payload provided by Hosted Checkout. Common shapes include:
|
|
350
407
|
|
|
@@ -505,15 +562,19 @@ Tip: Prefer subscribing with the SdkEvent enum for stronger typing.
|
|
|
505
562
|
<body>
|
|
506
563
|
<div id="checkout"></div>
|
|
507
564
|
|
|
508
|
-
<script src="https://cdn.jsdelivr.net/npm/@paypercut/checkout-js@1.0.
|
|
565
|
+
<script src="https://cdn.jsdelivr.net/npm/@paypercut/checkout-js@1.0.12/dist/paypercut-checkout.iife.min.js"></script>
|
|
509
566
|
<script>
|
|
510
567
|
const checkout = PaypercutCheckout({
|
|
511
568
|
id: 'CHK_12345',
|
|
512
|
-
containerId: '#checkout'
|
|
569
|
+
containerId: '#checkout',
|
|
570
|
+
locale: 'en',
|
|
571
|
+
ui_mode: 'embedded',
|
|
572
|
+
wallet_options: ['apple_pay', 'google_pay']
|
|
513
573
|
});
|
|
514
574
|
|
|
515
|
-
checkout.on('success', function() {
|
|
516
|
-
|
|
575
|
+
checkout.on('success', function(payload) {
|
|
576
|
+
// payload.payment_method: { brand, last4, exp_month, exp_year }
|
|
577
|
+
alert('Payment successful with ' + payload.payment_method.brand + ' ending in ' + payload.payment_method.last4);
|
|
517
578
|
});
|
|
518
579
|
|
|
519
580
|
checkout.on('error', function(error) {
|
|
@@ -533,11 +594,17 @@ import { PaypercutCheckout } from '@paypercut/checkout-js';
|
|
|
533
594
|
|
|
534
595
|
const checkout = PaypercutCheckout({
|
|
535
596
|
id: 'CHK_12345',
|
|
536
|
-
containerId: '#checkout'
|
|
597
|
+
containerId: '#checkout',
|
|
598
|
+
locale: 'auto',
|
|
599
|
+
ui_mode: 'embedded',
|
|
600
|
+
wallet_options: ['apple_pay', 'google_pay'],
|
|
601
|
+
form_only: false
|
|
537
602
|
});
|
|
538
603
|
|
|
539
|
-
checkout.on('success', () => {
|
|
604
|
+
checkout.on('success', (payload) => {
|
|
605
|
+
// payload.payment_method: { brand, last4, exp_month, exp_year }
|
|
540
606
|
console.log('Payment successful');
|
|
607
|
+
console.log(`Paid with ${payload.payment_method.brand} **** ${payload.payment_method.last4}`);
|
|
541
608
|
// Redirect to success page
|
|
542
609
|
window.location.href = '/success';
|
|
543
610
|
});
|
|
@@ -557,17 +624,29 @@ checkout.render();
|
|
|
557
624
|
import { useEffect, useRef, useState } from 'react';
|
|
558
625
|
import { PaypercutCheckout, CheckoutInstance } from '@paypercut/checkout-js';
|
|
559
626
|
|
|
627
|
+
interface PaymentMethod {
|
|
628
|
+
brand: string;
|
|
629
|
+
last4: string;
|
|
630
|
+
exp_month: number;
|
|
631
|
+
exp_year: number;
|
|
632
|
+
}
|
|
633
|
+
|
|
560
634
|
export function CheckoutComponent({ checkoutId }: { checkoutId: string }) {
|
|
561
635
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
562
636
|
const checkoutRef = useRef<CheckoutInstance | null>(null);
|
|
563
637
|
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
|
|
638
|
+
const [paymentMethod, setPaymentMethod] = useState<PaymentMethod | null>(null);
|
|
564
639
|
|
|
565
640
|
useEffect(() => {
|
|
566
641
|
if (!containerRef.current) return;
|
|
567
642
|
|
|
568
643
|
const checkout = PaypercutCheckout({
|
|
569
644
|
id: checkoutId,
|
|
570
|
-
containerId: containerRef.current
|
|
645
|
+
containerId: containerRef.current,
|
|
646
|
+
locale: 'auto',
|
|
647
|
+
ui_mode: 'embedded',
|
|
648
|
+
wallet_options: ['apple_pay', 'google_pay'],
|
|
649
|
+
form_only: false
|
|
571
650
|
});
|
|
572
651
|
|
|
573
652
|
checkout.on('loaded', () => {
|
|
@@ -575,9 +654,10 @@ export function CheckoutComponent({ checkoutId }: { checkoutId: string }) {
|
|
|
575
654
|
console.log('Checkout loaded');
|
|
576
655
|
});
|
|
577
656
|
|
|
578
|
-
checkout.on('success', () => {
|
|
657
|
+
checkout.on('success', (payload) => {
|
|
579
658
|
setStatus('success');
|
|
580
|
-
|
|
659
|
+
setPaymentMethod(payload.payment_method);
|
|
660
|
+
console.log('Payment successful:', payload.payment_method);
|
|
581
661
|
});
|
|
582
662
|
|
|
583
663
|
checkout.on('error', (error) => {
|
|
@@ -597,7 +677,9 @@ export function CheckoutComponent({ checkoutId }: { checkoutId: string }) {
|
|
|
597
677
|
<div>
|
|
598
678
|
<div ref={containerRef} style={{ width: '100%', height: '600px' }} />
|
|
599
679
|
{status === 'loading' && <p>Processing payment...</p>}
|
|
600
|
-
{status === 'success' &&
|
|
680
|
+
{status === 'success' && paymentMethod && (
|
|
681
|
+
<p>✅ Payment successful with {paymentMethod.brand} ending in {paymentMethod.last4}!</p>
|
|
682
|
+
)}
|
|
601
683
|
{status === 'error' && <p>❌ Payment failed. Please try again.</p>}
|
|
602
684
|
</div>
|
|
603
685
|
);
|
|
@@ -701,6 +783,56 @@ export function ModalCheckout({ checkoutId, onClose }: { checkoutId: string; onC
|
|
|
701
783
|
}
|
|
702
784
|
```
|
|
703
785
|
|
|
786
|
+
## Container Styling
|
|
787
|
+
|
|
788
|
+
The SDK automatically resizes the iframe to match the checkout content height. To ensure proper display, style your container with `max-width` and `max-height` constraints rather than fixed dimensions.
|
|
789
|
+
|
|
790
|
+
### Recommended Container Styles
|
|
791
|
+
|
|
792
|
+
```css
|
|
793
|
+
.checkout-container {
|
|
794
|
+
/* Use max-width/max-height to constrain the container */
|
|
795
|
+
max-width: 450px;
|
|
796
|
+
max-height: 600px;
|
|
797
|
+
overflow: hidden;
|
|
798
|
+
overflow-y: auto;
|
|
799
|
+
scroll-behavior: smooth;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/* The mount point should be full width with no fixed height */
|
|
803
|
+
#checkout-mount {
|
|
804
|
+
width: 100%;
|
|
805
|
+
/* Height is set dynamically by SDK via resize messages */
|
|
806
|
+
overflow: hidden;
|
|
807
|
+
position: relative;
|
|
808
|
+
}
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
### Key Points
|
|
812
|
+
|
|
813
|
+
1. **Avoid fixed `height` or `min-height`** on the container - the SDK will resize the iframe to fit the checkout content
|
|
814
|
+
2. **Use `max-height`** if you want to limit the container size and enable scrolling for longer content
|
|
815
|
+
3. **Use `max-width`** to constrain the container width (recommended: 375px–450px for optimal checkout display)
|
|
816
|
+
4. **Set `overflow-y: auto`** on the container if using `max-height` to enable scrolling
|
|
817
|
+
|
|
818
|
+
### Example HTML
|
|
819
|
+
|
|
820
|
+
```html
|
|
821
|
+
<div class="checkout-container">
|
|
822
|
+
<div id="checkout-mount"></div>
|
|
823
|
+
</div>
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
```javascript
|
|
827
|
+
const checkout = PaypercutCheckout({
|
|
828
|
+
id: 'CHK_12345',
|
|
829
|
+
containerId: '#checkout-mount'
|
|
830
|
+
});
|
|
831
|
+
checkout.render();
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
---
|
|
835
|
+
|
|
704
836
|
## Security
|
|
705
837
|
|
|
706
838
|
### Origin Validation
|
package/dist/index.cjs
CHANGED
|
@@ -84,7 +84,7 @@ class Emitter {
|
|
|
84
84
|
* Production configuration (for merchants)
|
|
85
85
|
*/
|
|
86
86
|
const productionConfig = {
|
|
87
|
-
version: "1.0.
|
|
87
|
+
version: "1.0.12",
|
|
88
88
|
defaultCheckoutOrigin: 'https://buy.paypercut.io',
|
|
89
89
|
allowedOrigins: [
|
|
90
90
|
'https://buy.paypercut.io',
|
|
@@ -274,6 +274,7 @@ exports.SdkEvent = void 0;
|
|
|
274
274
|
SdkEvent["Success"] = "success";
|
|
275
275
|
SdkEvent["Error"] = "error";
|
|
276
276
|
SdkEvent["Expired"] = "expired";
|
|
277
|
+
SdkEvent["Resize"] = "resize";
|
|
277
278
|
SdkEvent["ThreeDSComplete"] = "threeds_complete";
|
|
278
279
|
SdkEvent["ThreeDSError"] = "threeds_error";
|
|
279
280
|
SdkEvent["ThreeDSCanceled"] = "threeds_canceled";
|
|
@@ -323,11 +324,18 @@ class CheckoutImpl {
|
|
|
323
324
|
});
|
|
324
325
|
}
|
|
325
326
|
// Add wallet_options parameters (repeated for each wallet)
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
327
|
+
// If wallet_options is explicitly set (even as empty array), we need to pass it
|
|
328
|
+
if (this.options.wallet_options !== undefined) {
|
|
329
|
+
if (this.options.wallet_options.length === 0) {
|
|
330
|
+
// Explicit empty array means "no wallets" - pass null (coerced to "null" string)
|
|
331
|
+
url.searchParams.set('wallet_options', null);
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
const validatedWallets = validateWalletOptions(this.options.wallet_options);
|
|
335
|
+
validatedWallets.forEach((wallet) => {
|
|
336
|
+
url.searchParams.append('wallet_options', wallet);
|
|
337
|
+
});
|
|
338
|
+
}
|
|
331
339
|
}
|
|
332
340
|
if (this.options.appearance?.preset) {
|
|
333
341
|
url.searchParams.set('preset', this.options.appearance.preset);
|
|
@@ -383,6 +391,10 @@ class CheckoutImpl {
|
|
|
383
391
|
case 'CHECKOUT_EXPIRED':
|
|
384
392
|
this.emitter.emit(exports.SdkEvent.Expired);
|
|
385
393
|
break;
|
|
394
|
+
case 'CHECKOUT_RESIZE':
|
|
395
|
+
this.emitter.emit(exports.SdkEvent.Resize, data.height);
|
|
396
|
+
this.handleResize(data.height);
|
|
397
|
+
break;
|
|
386
398
|
case 'THREEDS_START_FLOW':
|
|
387
399
|
this.show3DSModal(data);
|
|
388
400
|
this.emitter.emit(exports.SdkEvent.ThreeDSStarted);
|
|
@@ -475,6 +487,16 @@ class CheckoutImpl {
|
|
|
475
487
|
const checkoutOrigin = getCheckoutOrigin(this.options.hostedCheckoutUrl);
|
|
476
488
|
this.iframe.contentWindow.postMessage(message, checkoutOrigin);
|
|
477
489
|
}
|
|
490
|
+
/**
|
|
491
|
+
* Handle CHECKOUT_RESIZE message - resize iframe to match content height
|
|
492
|
+
*/
|
|
493
|
+
handleResize(height) {
|
|
494
|
+
if (!this.iframe || typeof height !== 'number' || height <= 0) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
// Set iframe height to match content
|
|
498
|
+
this.iframe.style.height = `${height}px`;
|
|
499
|
+
}
|
|
478
500
|
/**
|
|
479
501
|
* Show 3DS modal with challenge/decoupled flow
|
|
480
502
|
*/
|