suioutkit 1.0.4 → 1.1.1
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 +15 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +28 -5
- package/dist/types/index.d.ts +7 -0
- package/package.json +1 -1
- package/src/components/modal.ts +35 -5
- package/src/components/style.css +42 -0
- package/src/index.ts +2 -1
- package/src/types/index.ts +8 -0
package/README.md
CHANGED
|
@@ -123,17 +123,29 @@ Throws if the backend returns a non-OK response.
|
|
|
123
123
|
|
|
124
124
|
---
|
|
125
125
|
|
|
126
|
-
### `openModal(session,
|
|
126
|
+
### `openModal(session, options?)`
|
|
127
127
|
Opens the built-in checkout modal (bank transfer, OPay, Stripe, Sui wallet, outPay).
|
|
128
128
|
|
|
129
129
|
```ts
|
|
130
|
-
const modal = sdk.openModal(session,
|
|
131
|
-
|
|
130
|
+
const modal = sdk.openModal(session, {
|
|
131
|
+
onClose: () => console.log("closed"),
|
|
132
|
+
onPaymentComplete: (result) => console.log(result.txDigest, result.walrusBlobId),
|
|
133
|
+
redirectUrl: "/thank-you",
|
|
134
|
+
autoCloseOnSuccess: true,
|
|
132
135
|
});
|
|
133
136
|
```
|
|
134
137
|
|
|
135
138
|
**Returns** `SuiOutKitModal` (internal handle). The modal loads styles from `{backendUrl}/style.css` automatically.
|
|
136
139
|
|
|
140
|
+
Options (`SuiOutKitModalOptions`):
|
|
141
|
+
|
|
142
|
+
| Option | Type | Description |
|
|
143
|
+
|--------|------|-------------|
|
|
144
|
+
| `onClose` | `() => void` | Called when the user dismisses the overlay |
|
|
145
|
+
| `onPaymentComplete` | `(result: PaymentResult) => void` | Called after on-chain settlement with `{ nonce, txDigest, walrusBlobId }` |
|
|
146
|
+
| `redirectUrl` | `string` | Redirect browser here after successful payment |
|
|
147
|
+
| `autoCloseOnSuccess` | `boolean` | Auto-close the modal after settlement instead of showing success panel |
|
|
148
|
+
|
|
137
149
|
> **Note:** Theme, logo, and `allowedMethods` customization are not exposed on `openModal` today. Use [custom UI](#custom-ui-no-modal) or extend the modal in source if you need that.
|
|
138
150
|
|
|
139
151
|
---
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -52401,13 +52401,20 @@ var SuiOutKitModal = class {
|
|
|
52401
52401
|
async handleCryptoPaymentPanel() {
|
|
52402
52402
|
const container = this.overlay?.querySelector("#sok-content-panel");
|
|
52403
52403
|
if (!container) return;
|
|
52404
|
+
const coins = this.session.supportedCoins || [];
|
|
52405
|
+
const currentCoin = this.session.coinType || "0x2::sui::SUI";
|
|
52406
|
+
const currentSymbol = coins.find((c4) => c4.type === currentCoin)?.symbol || "SUI";
|
|
52407
|
+
const coinChips = coins.length > 1 ? `<div class="sok-coin-selector">${coins.map(
|
|
52408
|
+
(c4) => `<button class="sok-coin-chip${c4.type === currentCoin ? " active" : ""}" data-coin-type="${c4.type}">${c4.symbol}</button>`
|
|
52409
|
+
).join("")}</div>` : `<div class="sok-coin-badge">${currentSymbol}</div>`;
|
|
52404
52410
|
container.innerHTML = `
|
|
52405
52411
|
<button class="suioutkit-back" id="sok-back-btn">\u2190 Back to methods</button>
|
|
52406
52412
|
<div class="suioutkit-header">
|
|
52407
52413
|
<h2 class="suioutkit-title">Pay with Sui Wallet</h2>
|
|
52408
|
-
<p class="suioutkit-subtitle">Choose
|
|
52414
|
+
<p class="suioutkit-subtitle">Choose settlement token and payment channel</p>
|
|
52409
52415
|
</div>
|
|
52410
52416
|
<div class="suioutkit-panel">
|
|
52417
|
+
${coinChips}
|
|
52411
52418
|
<p class="sok-status-text" style="margin-bottom: 12px;">
|
|
52412
52419
|
Choose whether to pay via a desktop extension wallet or scan a dynamic QR Code with your mobile wallet.
|
|
52413
52420
|
</p>
|
|
@@ -52419,6 +52426,17 @@ var SuiOutKitModal = class {
|
|
|
52419
52426
|
</button>
|
|
52420
52427
|
</div>
|
|
52421
52428
|
`;
|
|
52429
|
+
if (coins.length > 1) {
|
|
52430
|
+
container.querySelectorAll(".sok-coin-chip").forEach((chip) => {
|
|
52431
|
+
chip.addEventListener("click", () => {
|
|
52432
|
+
const coinType = chip.dataset.coinType || "";
|
|
52433
|
+
if (coinType && coinType !== this.session.coinType) {
|
|
52434
|
+
this.session.coinType = coinType;
|
|
52435
|
+
void this.handleCryptoPaymentPanel();
|
|
52436
|
+
}
|
|
52437
|
+
});
|
|
52438
|
+
});
|
|
52439
|
+
}
|
|
52422
52440
|
container.querySelector("#sok-back-btn")?.addEventListener("click", () => this.renderSelectionPanel());
|
|
52423
52441
|
container.querySelector("#sok-connect-extension-btn")?.addEventListener("click", async () => {
|
|
52424
52442
|
this.renderLoadingPanel("Preparing crypto payment...");
|
|
@@ -52766,13 +52784,17 @@ var SuiOutKitModal = class {
|
|
|
52766
52784
|
});
|
|
52767
52785
|
}
|
|
52768
52786
|
async loadCryptoIntent(method) {
|
|
52787
|
+
const body = {
|
|
52788
|
+
token: this.session.token,
|
|
52789
|
+
method
|
|
52790
|
+
};
|
|
52791
|
+
if (this.session.coinType) {
|
|
52792
|
+
body.coinType = this.session.coinType;
|
|
52793
|
+
}
|
|
52769
52794
|
const response = await fetch(joinApiPath(this.backendUrl, "checkout", "crypto", "intent"), {
|
|
52770
52795
|
method: "POST",
|
|
52771
52796
|
headers: { "Content-Type": "application/json" },
|
|
52772
|
-
body: JSON.stringify(
|
|
52773
|
-
token: this.session.token,
|
|
52774
|
-
method
|
|
52775
|
-
})
|
|
52797
|
+
body: JSON.stringify(body)
|
|
52776
52798
|
});
|
|
52777
52799
|
const result = await response.json();
|
|
52778
52800
|
if (!response.ok) {
|
|
@@ -53005,6 +53027,7 @@ var SuiOutKit = class {
|
|
|
53005
53027
|
amount: options.amount,
|
|
53006
53028
|
currency: options.currency,
|
|
53007
53029
|
merchantAddress: this.merchantAddress,
|
|
53030
|
+
coinType: options.coinType,
|
|
53008
53031
|
metadata: options.metadata || {}
|
|
53009
53032
|
})
|
|
53010
53033
|
});
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
export type SomeType = any;
|
|
2
|
+
export interface SupportedCoin {
|
|
3
|
+
symbol: string;
|
|
4
|
+
type: string;
|
|
5
|
+
decimals: number;
|
|
6
|
+
}
|
|
2
7
|
export interface CheckoutSessionOptions {
|
|
3
8
|
amount: number;
|
|
4
9
|
currency: "NGN" | "SUI" | string;
|
|
5
10
|
merchantAddress: string;
|
|
11
|
+
coinType?: string;
|
|
6
12
|
metadata?: Record<string, any>;
|
|
7
13
|
}
|
|
8
14
|
export interface CheckoutSession {
|
|
@@ -17,6 +23,7 @@ export interface CheckoutSession {
|
|
|
17
23
|
cryptoRegistryName?: string;
|
|
18
24
|
coinType?: string;
|
|
19
25
|
estimatedRate?: number;
|
|
26
|
+
supportedCoins?: SupportedCoin[];
|
|
20
27
|
}
|
|
21
28
|
export type ChargeMethod = "bank_transfer" | "opay" | "crypto" | "sui_wallet" | "outpay" | "stripe";
|
|
22
29
|
export interface VirtualAccount {
|
package/package.json
CHANGED
package/src/components/modal.ts
CHANGED
|
@@ -420,13 +420,27 @@ export class SuiOutKitModal {
|
|
|
420
420
|
const container = this.overlay?.querySelector("#sok-content-panel");
|
|
421
421
|
if (!container) return;
|
|
422
422
|
|
|
423
|
+
const coins = this.session.supportedCoins || [];
|
|
424
|
+
const currentCoin = this.session.coinType || "0x2::sui::SUI";
|
|
425
|
+
const currentSymbol = coins.find((c) => c.type === currentCoin)?.symbol || "SUI";
|
|
426
|
+
|
|
427
|
+
const coinChips = coins.length > 1
|
|
428
|
+
? `<div class="sok-coin-selector">${coins
|
|
429
|
+
.map(
|
|
430
|
+
(c) =>
|
|
431
|
+
`<button class="sok-coin-chip${c.type === currentCoin ? " active" : ""}" data-coin-type="${c.type}">${c.symbol}</button>`
|
|
432
|
+
)
|
|
433
|
+
.join("")}</div>`
|
|
434
|
+
: `<div class="sok-coin-badge">${currentSymbol}</div>`;
|
|
435
|
+
|
|
423
436
|
container.innerHTML = `
|
|
424
437
|
<button class="suioutkit-back" id="sok-back-btn">← Back to methods</button>
|
|
425
438
|
<div class="suioutkit-header">
|
|
426
439
|
<h2 class="suioutkit-title">Pay with Sui Wallet</h2>
|
|
427
|
-
<p class="suioutkit-subtitle">Choose
|
|
440
|
+
<p class="suioutkit-subtitle">Choose settlement token and payment channel</p>
|
|
428
441
|
</div>
|
|
429
442
|
<div class="suioutkit-panel">
|
|
443
|
+
${coinChips}
|
|
430
444
|
<p class="sok-status-text" style="margin-bottom: 12px;">
|
|
431
445
|
Choose whether to pay via a desktop extension wallet or scan a dynamic QR Code with your mobile wallet.
|
|
432
446
|
</p>
|
|
@@ -439,6 +453,18 @@ export class SuiOutKitModal {
|
|
|
439
453
|
</div>
|
|
440
454
|
`;
|
|
441
455
|
|
|
456
|
+
if (coins.length > 1) {
|
|
457
|
+
container.querySelectorAll(".sok-coin-chip").forEach((chip) => {
|
|
458
|
+
chip.addEventListener("click", () => {
|
|
459
|
+
const coinType = (chip as HTMLElement).dataset.coinType || "";
|
|
460
|
+
if (coinType && coinType !== this.session.coinType) {
|
|
461
|
+
this.session.coinType = coinType;
|
|
462
|
+
void this.handleCryptoPaymentPanel();
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
|
|
442
468
|
container.querySelector("#sok-back-btn")?.addEventListener("click", () => this.renderSelectionPanel());
|
|
443
469
|
|
|
444
470
|
container.querySelector("#sok-connect-extension-btn")?.addEventListener("click", async () => {
|
|
@@ -858,13 +884,17 @@ export class SuiOutKitModal {
|
|
|
858
884
|
}
|
|
859
885
|
|
|
860
886
|
private async loadCryptoIntent(method: "sui_wallet" | "outpay"): Promise<CryptoIntentResponse> {
|
|
887
|
+
const body: Record<string, any> = {
|
|
888
|
+
token: this.session.token,
|
|
889
|
+
method
|
|
890
|
+
};
|
|
891
|
+
if (this.session.coinType) {
|
|
892
|
+
body.coinType = this.session.coinType;
|
|
893
|
+
}
|
|
861
894
|
const response = await fetch(joinApiPath(this.backendUrl, "checkout", "crypto", "intent"), {
|
|
862
895
|
method: "POST",
|
|
863
896
|
headers: { "Content-Type": "application/json" },
|
|
864
|
-
body: JSON.stringify(
|
|
865
|
-
token: this.session.token,
|
|
866
|
-
method
|
|
867
|
-
})
|
|
897
|
+
body: JSON.stringify(body)
|
|
868
898
|
});
|
|
869
899
|
|
|
870
900
|
const result: any = await response.json();
|
package/src/components/style.css
CHANGED
|
@@ -478,6 +478,48 @@
|
|
|
478
478
|
100% { top: 0; }
|
|
479
479
|
}
|
|
480
480
|
|
|
481
|
+
.sok-coin-selector {
|
|
482
|
+
display: flex;
|
|
483
|
+
gap: 8px;
|
|
484
|
+
justify-content: center;
|
|
485
|
+
margin-bottom: 14px;
|
|
486
|
+
flex-wrap: wrap;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.sok-coin-chip {
|
|
490
|
+
background: var(--sok-card-bg);
|
|
491
|
+
border: 2px solid var(--sok-border);
|
|
492
|
+
border-radius: 20px;
|
|
493
|
+
padding: 6px 18px;
|
|
494
|
+
font-size: 13px;
|
|
495
|
+
font-weight: 600;
|
|
496
|
+
cursor: pointer;
|
|
497
|
+
transition: all 0.2s ease;
|
|
498
|
+
color: var(--sok-text);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.sok-coin-chip:hover {
|
|
502
|
+
border-color: var(--sok-accent);
|
|
503
|
+
color: var(--sok-accent);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.sok-coin-chip.active {
|
|
507
|
+
border-color: var(--sok-accent);
|
|
508
|
+
background: var(--sok-accent);
|
|
509
|
+
color: #ffffff;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
.sok-coin-badge {
|
|
513
|
+
display: inline-block;
|
|
514
|
+
background: var(--sok-accent);
|
|
515
|
+
color: #ffffff;
|
|
516
|
+
border-radius: 20px;
|
|
517
|
+
padding: 4px 16px;
|
|
518
|
+
font-size: 13px;
|
|
519
|
+
font-weight: 600;
|
|
520
|
+
margin-bottom: 14px;
|
|
521
|
+
}
|
|
522
|
+
|
|
481
523
|
.suioutkit-wallet-list {
|
|
482
524
|
display: flex;
|
|
483
525
|
flex-direction: column;
|
package/src/index.ts
CHANGED
|
@@ -33,6 +33,7 @@ export class SuiOutKit {
|
|
|
33
33
|
amount: options.amount,
|
|
34
34
|
currency: options.currency,
|
|
35
35
|
merchantAddress: this.merchantAddress,
|
|
36
|
+
coinType: options.coinType,
|
|
36
37
|
metadata: options.metadata || {}
|
|
37
38
|
})
|
|
38
39
|
});
|
|
@@ -86,7 +87,7 @@ export class SuiOutKit {
|
|
|
86
87
|
*/
|
|
87
88
|
public wrapButton(
|
|
88
89
|
selector: string,
|
|
89
|
-
options: { amount: number; currency: "NGN" | "SUI" | string; metadata?: Record<string, any> }
|
|
90
|
+
options: { amount: number; currency: "NGN" | "SUI" | string; coinType?: string; metadata?: Record<string, any> }
|
|
90
91
|
): void {
|
|
91
92
|
const btn = document.querySelector(selector) as HTMLButtonElement;
|
|
92
93
|
if (!btn) {
|
package/src/types/index.ts
CHANGED
|
@@ -4,10 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
export type SomeType = any;
|
|
6
6
|
|
|
7
|
+
export interface SupportedCoin {
|
|
8
|
+
symbol: string;
|
|
9
|
+
type: string;
|
|
10
|
+
decimals: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
7
13
|
export interface CheckoutSessionOptions {
|
|
8
14
|
amount: number;
|
|
9
15
|
currency: "NGN" | "SUI" | string;
|
|
10
16
|
merchantAddress: string;
|
|
17
|
+
coinType?: string;
|
|
11
18
|
metadata?: Record<string, any>;
|
|
12
19
|
}
|
|
13
20
|
|
|
@@ -23,6 +30,7 @@ export interface CheckoutSession {
|
|
|
23
30
|
cryptoRegistryName?: string;
|
|
24
31
|
coinType?: string;
|
|
25
32
|
estimatedRate?: number;
|
|
33
|
+
supportedCoins?: SupportedCoin[];
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
export type ChargeMethod = "bank_transfer" | "opay" | "crypto" | "sui_wallet" | "outpay" | "stripe";
|