@blocklet/payment-react 1.16.0 → 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 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 { CheckoutForm, CheckoutTable, PaymentProvider } from '@blocklet/payment-react';
5
- import { Paper, Typography } from '@mui/material';
6
- import React from 'react';
7
- import { useSearchParams } from 'react-router-dom';
8
-
9
- import { useSessionContext } from '../contexts/session';
10
-
11
- export default function CheckoutPage() {
12
- const [params] = useSearchParams();
13
- const { session, connectApi } = useSessionContext();
14
-
15
- if (params.get('type') === 'session') {
16
- return (
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
- ## I18n
75
+ ### Form Components
60
76
 
61
77
  ```tsx
62
- import { createTranslator, translations as extraTranslations } from '@blocklet/payment-react';
63
- import merge from 'lodash/merge';
78
+ import {
79
+ FormInput,
80
+ PhoneInput,
81
+ AddressForm,
82
+ CurrencySelector,
83
+ CountrySelect
84
+ } from '@blocklet/payment-react';
64
85
 
65
- import en from './en';
66
- import zh from './zh';
86
+ // Phone input with validation
87
+ <PhoneInput
88
+ name="phone"
89
+ countryFieldName="billing_address.country"
90
+ />
67
91
 
68
- // eslint-disable-next-line import/prefer-default-export
69
- export const translations = merge({ zh, en }, extraTranslations);
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
- ## Updates
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
- ```js
322
+
323
+ ```tsx
90
324
  // 1. use themeOptions
91
- <CheckoutForm
92
- id="plink_oB1I6FNeHKSkuq81fhJy0vIZ"
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="plink_oB1I6FNeHKSkuq81fhJy0vIZ"
114
- mode="inline-minimal"
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
- #### showCheckoutSummary
364
+ ## I18n Support
131
365
 
132
- Since version 1.14.23, if you need to hide the product column, we recommend using `showCheckoutSummary=false` instead of `mode=inline-minimal`. We aim for better semantics.
133
- ```js
134
- // bad
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="plink_oB1I6FNeHKSkuq81fhJy0vIZ"
137
- mode="inline-minimal"
384
+ id="plink_xxx"
385
+ showCheckoutSummary={false}
138
386
  onChange={console.info}
139
387
  />
140
388
 
141
- // good
389
+ // Not recommended
142
390
  <CheckoutForm
143
- id="plink_oB1I6FNeHKSkuq81fhJy0vIZ"
144
- showCheckoutSummary={false}
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
+ ```
@@ -368,7 +368,8 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
368
368
  display: "flex",
369
369
  alignItems: "baseline",
370
370
  gap: "4px",
371
- flexWrap: "wrap"
371
+ flexWrap: "wrap",
372
+ lineHeight: "normal"
372
373
  },
373
374
  children: [
374
375
  amount,
package/es/libs/util.js CHANGED
@@ -881,7 +881,8 @@ export function getInvoiceDescriptionAndReason(invoice, locale = "en") {
881
881
  "Stake for subscription payment change": t("payment.invoice.reason.stakeForChangePayment", locale),
882
882
  "Stake for subscription": t("payment.invoice.reason.staking", locale),
883
883
  "Return Subscription staking": t("payment.invoice.reason.returnStake", locale),
884
- "Recharge for subscription": t("payment.invoice.reason.rechargeForSubscription", locale)
884
+ "Recharge for subscription": t("payment.invoice.reason.rechargeForSubscription", locale),
885
+ "Add funds for subscription": t("payment.invoice.reason.rechargeForSubscription", locale)
885
886
  };
886
887
  return {
887
888
  description: descMap[description] || description,
package/es/locales/en.js CHANGED
@@ -313,8 +313,8 @@ export default flat({
313
313
  returnStake: "Return stake",
314
314
  stakeForChangePlan: "Subscription plan update",
315
315
  stakeForChangePayment: "Subscription payment method update",
316
- recharge: "Recharge",
317
- rechargeForSubscription: "Subscription recharge"
316
+ recharge: "Add funds",
317
+ rechargeForSubscription: "Add funds for subscription"
318
318
  }
319
319
  }
320
320
  },
@@ -385,7 +385,8 @@ function PricingTable({
385
385
  display: "flex",
386
386
  alignItems: "baseline",
387
387
  gap: "4px",
388
- flexWrap: "wrap"
388
+ flexWrap: "wrap",
389
+ lineHeight: "normal"
389
390
  },
390
391
  children: [amount, unit ? /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
391
392
  sx: {
package/lib/libs/util.js CHANGED
@@ -1064,7 +1064,8 @@ function getInvoiceDescriptionAndReason(invoice, locale = "en") {
1064
1064
  "Stake for subscription payment change": (0, _locales.t)("payment.invoice.reason.stakeForChangePayment", locale),
1065
1065
  "Stake for subscription": (0, _locales.t)("payment.invoice.reason.staking", locale),
1066
1066
  "Return Subscription staking": (0, _locales.t)("payment.invoice.reason.returnStake", locale),
1067
- "Recharge for subscription": (0, _locales.t)("payment.invoice.reason.rechargeForSubscription", locale)
1067
+ "Recharge for subscription": (0, _locales.t)("payment.invoice.reason.rechargeForSubscription", locale),
1068
+ "Add funds for subscription": (0, _locales.t)("payment.invoice.reason.rechargeForSubscription", locale)
1068
1069
  };
1069
1070
  return {
1070
1071
  description: descMap[description] || description,
package/lib/locales/en.js CHANGED
@@ -320,8 +320,8 @@ module.exports = (0, _flat.default)({
320
320
  returnStake: "Return stake",
321
321
  stakeForChangePlan: "Subscription plan update",
322
322
  stakeForChangePayment: "Subscription payment method update",
323
- recharge: "Recharge",
324
- rechargeForSubscription: "Subscription recharge"
323
+ recharge: "Add funds",
324
+ rechargeForSubscription: "Add funds for subscription"
325
325
  }
326
326
  }
327
327
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/payment-react",
3
- "version": "1.16.0",
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.65",
57
- "@arcblock/ux": "^2.10.65",
58
- "@arcblock/ws": "^1.18.139",
59
- "@blocklet/ui-react": "^2.10.65",
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.139",
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.0",
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": "8d3dd981076bd6ace838f221a2171228456cb1f9"
125
+ "gitHead": "63c0ef382409afb79f595f82ea5e9bb9f264b844"
126
126
  }
@@ -401,6 +401,7 @@ export default function PricingTable({ table, alignItems, interval, mode, onSele
401
401
  alignItems: 'baseline',
402
402
  gap: '4px',
403
403
  flexWrap: 'wrap',
404
+ lineHeight: 'normal',
404
405
  }}>
405
406
  {amount}
406
407
  {unit ? (
package/src/libs/util.ts CHANGED
@@ -1140,6 +1140,7 @@ export function getInvoiceDescriptionAndReason(invoice: TInvoiceExpanded, locale
1140
1140
  'Stake for subscription': t('payment.invoice.reason.staking', locale),
1141
1141
  'Return Subscription staking': t('payment.invoice.reason.returnStake', locale),
1142
1142
  'Recharge for subscription': t('payment.invoice.reason.rechargeForSubscription', locale),
1143
+ 'Add funds for subscription': t('payment.invoice.reason.rechargeForSubscription', locale),
1143
1144
  };
1144
1145
 
1145
1146
  return {
@@ -326,8 +326,8 @@ export default flat({
326
326
  returnStake: 'Return stake',
327
327
  stakeForChangePlan: 'Subscription plan update',
328
328
  stakeForChangePayment: 'Subscription payment method update',
329
- recharge: 'Recharge',
330
- rechargeForSubscription: 'Subscription recharge',
329
+ recharge: 'Add funds',
330
+ rechargeForSubscription: 'Add funds for subscription',
331
331
  },
332
332
  },
333
333
  },