@blocklet/payment-react 1.16.1 → 1.16.2
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 +374 -77
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -1,80 +1,314 @@
|
|
|
1
1
|
# Payment Kit Components
|
|
2
2
|
|
|
3
|
+
## Quick Start
|
|
4
|
+
|
|
5
|
+
### 1. Installation
|
|
6
|
+
```bash
|
|
7
|
+
npm install @blocklet/payment-react @mui/material @emotion/react @emotion/styled
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
### 2. Basic Setup
|
|
3
11
|
```tsx
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<PaymentProvider session={session} connect={connectApi}>
|
|
18
|
-
<Typography variant="h4" gutterBottom>
|
|
19
|
-
Checkout with session
|
|
20
|
-
</Typography>
|
|
21
|
-
<Paper sx={{ p: 3, display: 'inline-block' }} elevation={3}>
|
|
22
|
-
<CheckoutForm id="cs_9zeD2yCgPXT9Vit9bab2vVC3V7DFjHiKvyoLzVTVzAf4XSU2oLWY67vKy7" mode="inline" />
|
|
23
|
-
</Paper>
|
|
24
|
-
</PaymentProvider>
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (params.get('type') === 'link') {
|
|
29
|
-
return (
|
|
30
|
-
<PaymentProvider session={session} connect={connectApi}>
|
|
31
|
-
<Typography variant="h4" gutterBottom>
|
|
32
|
-
Checkout with payment link
|
|
33
|
-
</Typography>
|
|
34
|
-
<Paper sx={{ p: 3, display: 'inline-block' }} elevation={3}>
|
|
35
|
-
<CheckoutForm id="plink_oB1I6FNeHKSkuq81fhJy0vIZ" mode="inline" />
|
|
36
|
-
</Paper>
|
|
37
|
-
</PaymentProvider>
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (params.get('type') === 'table') {
|
|
42
|
-
return (
|
|
43
|
-
<PaymentProvider session={session} connect={connectApi}>
|
|
44
|
-
<Typography variant="h4" gutterBottom>
|
|
45
|
-
Checkout with pricing table
|
|
46
|
-
</Typography>
|
|
47
|
-
<Paper sx={{ p: 3, display: 'inline-block' }} elevation={3}>
|
|
48
|
-
<CheckoutTable id="prctbl_kOsaIiPrsHAwwALaKgy17mIl" mode="inline" />
|
|
49
|
-
</Paper>
|
|
50
|
-
</PaymentProvider>
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return null;
|
|
12
|
+
import { PaymentProvider, CheckoutForm } from '@blocklet/payment-react';
|
|
13
|
+
|
|
14
|
+
function App() {
|
|
15
|
+
return (
|
|
16
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
17
|
+
<CheckoutForm
|
|
18
|
+
id="plink_xxx"
|
|
19
|
+
mode="inline"
|
|
20
|
+
showCheckoutSummary={true}
|
|
21
|
+
onChange={(state) => console.log(state)}
|
|
22
|
+
/>
|
|
23
|
+
</PaymentProvider>
|
|
24
|
+
);
|
|
55
25
|
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Component Usage
|
|
29
|
+
|
|
30
|
+
### Core Components
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { CheckoutForm, CheckoutTable, CheckoutDonate, PaymentProvider } from '@blocklet/payment-react';
|
|
34
|
+
|
|
35
|
+
// Checkout with session
|
|
36
|
+
<CheckoutForm
|
|
37
|
+
id="cs_xxx"
|
|
38
|
+
mode="inline"
|
|
39
|
+
showCheckoutSummary={true}
|
|
40
|
+
onChange={(state) => console.log(state)}
|
|
41
|
+
/>
|
|
42
|
+
|
|
43
|
+
// Checkout with payment link
|
|
44
|
+
<CheckoutForm
|
|
45
|
+
id="plink_xxx"
|
|
46
|
+
mode="inline"
|
|
47
|
+
/>
|
|
56
48
|
|
|
49
|
+
// Pricing table
|
|
50
|
+
<CheckoutTable
|
|
51
|
+
id="prctbl_xxx"
|
|
52
|
+
mode="inline"
|
|
53
|
+
/>
|
|
54
|
+
|
|
55
|
+
// Donation form
|
|
56
|
+
<CheckoutDonate
|
|
57
|
+
mode="inline"
|
|
58
|
+
settings={{
|
|
59
|
+
target: 'donation-target',
|
|
60
|
+
title: 'Support Us',
|
|
61
|
+
description: 'Help us continue our work',
|
|
62
|
+
beneficiaries: [{
|
|
63
|
+
address: 'wallet_address',
|
|
64
|
+
share: '100'
|
|
65
|
+
}],
|
|
66
|
+
amount: {
|
|
67
|
+
minimum: '0.01',
|
|
68
|
+
maximum: '1',
|
|
69
|
+
custom: true
|
|
70
|
+
}
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
57
73
|
```
|
|
58
74
|
|
|
59
|
-
|
|
75
|
+
### Form Components
|
|
60
76
|
|
|
61
77
|
```tsx
|
|
62
|
-
import {
|
|
63
|
-
|
|
78
|
+
import {
|
|
79
|
+
FormInput,
|
|
80
|
+
PhoneInput,
|
|
81
|
+
AddressForm,
|
|
82
|
+
CurrencySelector,
|
|
83
|
+
CountrySelect
|
|
84
|
+
} from '@blocklet/payment-react';
|
|
64
85
|
|
|
65
|
-
|
|
66
|
-
|
|
86
|
+
// Phone input with validation
|
|
87
|
+
<PhoneInput
|
|
88
|
+
name="phone"
|
|
89
|
+
countryFieldName="billing_address.country"
|
|
90
|
+
/>
|
|
67
91
|
|
|
68
|
-
//
|
|
69
|
-
|
|
92
|
+
// Address form
|
|
93
|
+
<AddressForm
|
|
94
|
+
mode="required"
|
|
95
|
+
stripe={false}
|
|
96
|
+
sx={{}}
|
|
97
|
+
/>
|
|
98
|
+
|
|
99
|
+
// Currency selector
|
|
100
|
+
<CurrencySelector
|
|
101
|
+
value={0}
|
|
102
|
+
onChange={(index) => {}}
|
|
103
|
+
currencies={[
|
|
104
|
+
{
|
|
105
|
+
id: 'currency_id',
|
|
106
|
+
symbol: '$',
|
|
107
|
+
logo: 'currency_logo_url',
|
|
108
|
+
name: 'USD',
|
|
109
|
+
method: { name: 'Payment Method' }
|
|
110
|
+
}
|
|
111
|
+
]}
|
|
112
|
+
/>
|
|
113
|
+
|
|
114
|
+
// Country select
|
|
115
|
+
<CountrySelect
|
|
116
|
+
value="us"
|
|
117
|
+
onChange={(value: CountryIso2) => {}}
|
|
118
|
+
name="country"
|
|
119
|
+
sx={{}}
|
|
120
|
+
/>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Display Components
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import {
|
|
127
|
+
PricingItem,
|
|
128
|
+
TruncatedText,
|
|
129
|
+
TxGas,
|
|
130
|
+
TxLink,
|
|
131
|
+
ProductSkeleton,
|
|
132
|
+
} from '@blocklet/payment-react';
|
|
133
|
+
|
|
134
|
+
// Display pricing information
|
|
135
|
+
<PricingItem
|
|
136
|
+
productId="prod_xxx"
|
|
137
|
+
quantity={1}
|
|
138
|
+
priceId="price_xxx"
|
|
139
|
+
>
|
|
140
|
+
{(pricing, product) => (
|
|
141
|
+
<div>
|
|
142
|
+
<div>Total: {pricing.totalPrice}</div>
|
|
143
|
+
<div>Product: {product?.name}</div>
|
|
144
|
+
</div>
|
|
145
|
+
)}
|
|
146
|
+
</PricingItem>
|
|
147
|
+
|
|
148
|
+
// Display transaction gas fee
|
|
149
|
+
<TxGas
|
|
150
|
+
details={paymentDetails}
|
|
151
|
+
method={paymentMethod}
|
|
152
|
+
/>
|
|
153
|
+
|
|
154
|
+
// Display transaction link
|
|
155
|
+
<TxLink
|
|
156
|
+
details={paymentDetails}
|
|
157
|
+
method={paymentMethod}
|
|
158
|
+
mode="dashboard"
|
|
159
|
+
align="left"
|
|
160
|
+
/>
|
|
161
|
+
|
|
162
|
+
// Loading skeleton
|
|
163
|
+
<ProductSkeleton />
|
|
164
|
+
|
|
165
|
+
// Truncate long text
|
|
166
|
+
<TruncatedText
|
|
167
|
+
text="Very long text..."
|
|
168
|
+
maxLength={20}
|
|
169
|
+
/>
|
|
70
170
|
```
|
|
71
171
|
|
|
72
|
-
|
|
172
|
+
### Donation Components
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
import { CheckoutDonate } from '@blocklet/payment-react';
|
|
176
|
+
|
|
177
|
+
// Basic usage
|
|
178
|
+
<CheckoutDonate
|
|
179
|
+
mode="default" // 'default' | 'inline' | 'custom'
|
|
180
|
+
settings={{
|
|
181
|
+
target: 'donation-target',
|
|
182
|
+
title: 'Support Us',
|
|
183
|
+
description: 'Help us continue our work',
|
|
184
|
+
beneficiaries: [{
|
|
185
|
+
address: 'wallet_address',
|
|
186
|
+
share: '100'
|
|
187
|
+
}],
|
|
188
|
+
amount: {
|
|
189
|
+
minimum: '0.01',
|
|
190
|
+
maximum: '100',
|
|
191
|
+
custom: true
|
|
192
|
+
},
|
|
193
|
+
appearance: {
|
|
194
|
+
button: {
|
|
195
|
+
text: 'Donate Now',
|
|
196
|
+
icon: <FavoriteIcon />,
|
|
197
|
+
size: 'large',
|
|
198
|
+
color: 'primary',
|
|
199
|
+
variant: 'contained'
|
|
200
|
+
},
|
|
201
|
+
history: {
|
|
202
|
+
variant: 'avatar' // 'avatar' | 'table'
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}}
|
|
206
|
+
/>
|
|
207
|
+
|
|
208
|
+
// Custom render mode
|
|
209
|
+
<CheckoutDonate
|
|
210
|
+
mode="custom"
|
|
211
|
+
settings={{
|
|
212
|
+
target: 'custom-donation',
|
|
213
|
+
// ... other settings
|
|
214
|
+
}}
|
|
215
|
+
>
|
|
216
|
+
{(openDonate, totalAmount, supporters) => (
|
|
217
|
+
<div>
|
|
218
|
+
<button onClick={openDonate}>
|
|
219
|
+
Support Us
|
|
220
|
+
</button>
|
|
221
|
+
<div>Total Donations: {totalAmount}</div>
|
|
222
|
+
<div>Supporters: {supporters.supporters.length}</div>
|
|
223
|
+
{supporters.supporters.map(supporter => (
|
|
224
|
+
<div key={supporter.id}>
|
|
225
|
+
<img src={supporter.customer?.avatar} alt={supporter.customer?.name} />
|
|
226
|
+
<span>{supporter.customer?.name}</span>
|
|
227
|
+
<span>{formatAmount(supporter.amount_total, supporters.currency.decimal)} {supporters.currency.symbol}</span>
|
|
228
|
+
</div>
|
|
229
|
+
))}
|
|
230
|
+
</div>
|
|
231
|
+
)}
|
|
232
|
+
</CheckoutDonate>
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Lazy Loading Components
|
|
236
|
+
|
|
237
|
+
The SDK provides `createLazyComponent` for optimizing bundle size by loading components and their dependencies on demand:
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
import { createLazyComponent } from '@blocklet/payment-react';
|
|
241
|
+
|
|
242
|
+
// 1. Create lazy component with dependencies
|
|
243
|
+
const LazyComponent = createLazyComponent(async () => {
|
|
244
|
+
// Load dependencies in parallel
|
|
245
|
+
const [dep1, dep2] = await Promise.all([
|
|
246
|
+
import('heavy-dependency-1'),
|
|
247
|
+
import('heavy-dependency-2')
|
|
248
|
+
]);
|
|
249
|
+
|
|
250
|
+
// Store dependencies for reuse
|
|
251
|
+
const dependencies = {
|
|
252
|
+
Component1: dep1.Component1,
|
|
253
|
+
Component2: dep1.Component2,
|
|
254
|
+
useHook1: dep2.useHook1,
|
|
255
|
+
useHook2: dep2.useHook2,
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// Make dependencies available to child components
|
|
259
|
+
globalThis.__DEPENDENCIES__ = dependencies;
|
|
260
|
+
|
|
261
|
+
// Load and return the actual component that uses these dependencies
|
|
262
|
+
const { default: Component } = await import('./MyComponent');
|
|
263
|
+
return Component;
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// 2. Use dependencies in your component
|
|
267
|
+
// Access loaded dependencies
|
|
268
|
+
const {
|
|
269
|
+
Component1,
|
|
270
|
+
Component2,
|
|
271
|
+
useHook1,
|
|
272
|
+
useHook2
|
|
273
|
+
} = globalThis.__DEPENDENCIES__;
|
|
274
|
+
function MyComponent(props) {
|
|
275
|
+
// Use hooks from dependencies
|
|
276
|
+
const hook1Result = useHook1();
|
|
277
|
+
const hook2Result = useHook2();
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<div>
|
|
281
|
+
<Component1 {...hook1Result} />
|
|
282
|
+
<Component2 {...hook2Result} />
|
|
283
|
+
</div>
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// 3. Use the lazy component
|
|
288
|
+
function App() {
|
|
289
|
+
return (
|
|
290
|
+
<LazyComponent
|
|
291
|
+
prop1="value1"
|
|
292
|
+
prop2="value2"
|
|
293
|
+
onEvent={() => {}}
|
|
294
|
+
/>
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Key features:
|
|
300
|
+
- 🚀 Loads dependencies on demand
|
|
301
|
+
- 📦 Reduces initial bundle size
|
|
302
|
+
- 🌐 Provides global access to loaded dependencies
|
|
303
|
+
- ⚡️ Supports parallel loading
|
|
304
|
+
- 🔄 Handles async initialization
|
|
305
|
+
- ❌ Built-in error handling
|
|
306
|
+
|
|
307
|
+
## Theme Customization
|
|
73
308
|
|
|
74
|
-
#### theme
|
|
75
309
|
Since version 1.14.22, the component includes a built-in theme provider. If you need to modify the styles of internal components, you need to pass the `theme` property to override or inherit the external theme.
|
|
76
310
|
|
|
77
|
-
| option |description |
|
|
311
|
+
| option | description |
|
|
78
312
|
| --- | --- |
|
|
79
313
|
| default [default value] | wrapped with built-in PaymentThemeProvider |
|
|
80
314
|
| inherit | use the parent component's themeProvider |
|
|
@@ -84,12 +318,12 @@ Since version 1.14.22, the component includes a built-in theme provider. If you
|
|
|
84
318
|
export type PaymentThemeOptions = ThemeOptions & {
|
|
85
319
|
sx?: SxProps;
|
|
86
320
|
};
|
|
87
|
-
|
|
88
321
|
```
|
|
89
|
-
|
|
322
|
+
|
|
323
|
+
```tsx
|
|
90
324
|
// 1. use themeOptions
|
|
91
|
-
|
|
92
|
-
id="
|
|
325
|
+
<CheckoutForm
|
|
326
|
+
id="plink_xxx"
|
|
93
327
|
onChange={console.info}
|
|
94
328
|
theme={{
|
|
95
329
|
components: {
|
|
@@ -110,8 +344,8 @@ export type PaymentThemeOptions = ThemeOptions & {
|
|
|
110
344
|
|
|
111
345
|
// 2. use theme sx
|
|
112
346
|
<CheckoutForm
|
|
113
|
-
id="
|
|
114
|
-
|
|
347
|
+
id="plink_xxx"
|
|
348
|
+
showCheckoutSummary={false}
|
|
115
349
|
onChange={console.info}
|
|
116
350
|
theme={{
|
|
117
351
|
sx: {
|
|
@@ -127,21 +361,84 @@ export type PaymentThemeOptions = ThemeOptions & {
|
|
|
127
361
|
/>
|
|
128
362
|
```
|
|
129
363
|
|
|
130
|
-
|
|
364
|
+
## I18n Support
|
|
131
365
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
366
|
+
```tsx
|
|
367
|
+
import { createTranslator, translations as extraTranslations } from '@blocklet/payment-react';
|
|
368
|
+
import merge from 'lodash/merge';
|
|
369
|
+
|
|
370
|
+
import en from './en';
|
|
371
|
+
import zh from './zh';
|
|
372
|
+
|
|
373
|
+
export const translations = merge({ zh, en }, extraTranslations);
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Recent Updates
|
|
377
|
+
|
|
378
|
+
### v1.14.23
|
|
379
|
+
We recommend using `showCheckoutSummary={false}` instead of `mode=inline-minimal` for better semantics:
|
|
380
|
+
|
|
381
|
+
```tsx
|
|
382
|
+
// Recommended
|
|
135
383
|
<CheckoutForm
|
|
136
|
-
id="
|
|
137
|
-
|
|
384
|
+
id="plink_xxx"
|
|
385
|
+
showCheckoutSummary={false}
|
|
138
386
|
onChange={console.info}
|
|
139
387
|
/>
|
|
140
388
|
|
|
141
|
-
//
|
|
389
|
+
// Not recommended
|
|
142
390
|
<CheckoutForm
|
|
143
|
-
id="
|
|
144
|
-
|
|
391
|
+
id="plink_xxx"
|
|
392
|
+
mode="inline-minimal"
|
|
145
393
|
onChange={console.info}
|
|
146
394
|
/>
|
|
147
|
-
```
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Status & Utility Components
|
|
398
|
+
```tsx
|
|
399
|
+
import {
|
|
400
|
+
Status,
|
|
401
|
+
Livemode,
|
|
402
|
+
Switch,
|
|
403
|
+
Link,
|
|
404
|
+
Amount
|
|
405
|
+
} from '@blocklet/payment-react';
|
|
406
|
+
|
|
407
|
+
// Status indicator for payment states
|
|
408
|
+
<Status
|
|
409
|
+
label="active"
|
|
410
|
+
color="success"
|
|
411
|
+
size="small"
|
|
412
|
+
sx={{ margin: 1 }}
|
|
413
|
+
/>
|
|
414
|
+
|
|
415
|
+
// Live/Test mode indicator
|
|
416
|
+
<Livemode livemode={false} />
|
|
417
|
+
|
|
418
|
+
// Custom switch button
|
|
419
|
+
<Switch
|
|
420
|
+
checked={true}
|
|
421
|
+
onChange={(checked) => console.log('Switched:', checked)}
|
|
422
|
+
size="small"
|
|
423
|
+
color="primary"
|
|
424
|
+
/>
|
|
425
|
+
|
|
426
|
+
// Safe navigation link
|
|
427
|
+
<Link
|
|
428
|
+
href="https://example.com"
|
|
429
|
+
confirmBeforeNavigate={true}
|
|
430
|
+
confirmMessage="Are you sure to leave?"
|
|
431
|
+
target="_blank"
|
|
432
|
+
/>
|
|
433
|
+
|
|
434
|
+
// Amount display with formatting
|
|
435
|
+
<Amount
|
|
436
|
+
value={1000}
|
|
437
|
+
currency={{
|
|
438
|
+
symbol: '$',
|
|
439
|
+
decimal: 2
|
|
440
|
+
}}
|
|
441
|
+
variant="body1"
|
|
442
|
+
color="primary"
|
|
443
|
+
/>
|
|
444
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/payment-react",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.2",
|
|
4
4
|
"description": "Reusable react components for payment kit v2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -53,15 +53,15 @@
|
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@arcblock/did-connect": "^2.10.
|
|
57
|
-
"@arcblock/ux": "^2.10.
|
|
58
|
-
"@arcblock/ws": "^1.18.
|
|
59
|
-
"@blocklet/ui-react": "^2.10.
|
|
56
|
+
"@arcblock/did-connect": "^2.10.67",
|
|
57
|
+
"@arcblock/ux": "^2.10.67",
|
|
58
|
+
"@arcblock/ws": "^1.18.147",
|
|
59
|
+
"@blocklet/ui-react": "^2.10.67",
|
|
60
60
|
"@mui/icons-material": "^5.16.6",
|
|
61
61
|
"@mui/lab": "^5.0.0-alpha.173",
|
|
62
62
|
"@mui/material": "^5.16.6",
|
|
63
63
|
"@mui/system": "^5.16.6",
|
|
64
|
-
"@ocap/util": "^1.18.
|
|
64
|
+
"@ocap/util": "^1.18.147",
|
|
65
65
|
"@stripe/react-stripe-js": "^2.7.3",
|
|
66
66
|
"@stripe/stripe-js": "^2.4.0",
|
|
67
67
|
"@vitejs/plugin-legacy": "^5.4.1",
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"@babel/core": "^7.25.2",
|
|
93
93
|
"@babel/preset-env": "^7.25.2",
|
|
94
94
|
"@babel/preset-react": "^7.24.7",
|
|
95
|
-
"@blocklet/payment-types": "1.16.
|
|
95
|
+
"@blocklet/payment-types": "1.16.2",
|
|
96
96
|
"@storybook/addon-essentials": "^7.6.20",
|
|
97
97
|
"@storybook/addon-interactions": "^7.6.20",
|
|
98
98
|
"@storybook/addon-links": "^7.6.20",
|
|
@@ -122,5 +122,5 @@
|
|
|
122
122
|
"vite-plugin-babel": "^1.2.0",
|
|
123
123
|
"vite-plugin-node-polyfills": "^0.21.0"
|
|
124
124
|
},
|
|
125
|
-
"gitHead": "
|
|
125
|
+
"gitHead": "63c0ef382409afb79f595f82ea5e9bb9f264b844"
|
|
126
126
|
}
|