@windrun-huaiin/third-ui 30.1.0 → 31.0.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.
Files changed (103) hide show
  1. package/README.md +109 -143
  2. package/dist/ai/ai-prompt-textarea.js +5 -5
  3. package/dist/ai/ai-prompt-textarea.mjs +5 -5
  4. package/dist/clerk/clerk-auth-appearance.d.ts +13 -0
  5. package/dist/clerk/clerk-auth-appearance.js +19 -0
  6. package/dist/clerk/clerk-auth-appearance.mjs +15 -0
  7. package/dist/clerk/clerk-auth-modal-appearance.d.ts +12 -0
  8. package/dist/clerk/clerk-auth-modal-appearance.js +17 -0
  9. package/dist/clerk/clerk-auth-modal-appearance.mjs +14 -0
  10. package/dist/clerk/clerk-page-context-generator.js +3 -3
  11. package/dist/clerk/clerk-page-context-generator.mjs +3 -3
  12. package/dist/clerk/clerk-page-generator.js +4 -4
  13. package/dist/clerk/clerk-page-generator.mjs +4 -4
  14. package/dist/clerk/clerk-user-client.js +2 -1
  15. package/dist/clerk/clerk-user-client.mjs +2 -1
  16. package/dist/clerk/fingerprint/fingerprint-client.d.ts +10 -10
  17. package/dist/clerk/fingerprint/fingerprint-client.js +20 -20
  18. package/dist/clerk/fingerprint/fingerprint-client.mjs +20 -20
  19. package/dist/clerk/fingerprint/fingerprint-provider.d.ts +3 -3
  20. package/dist/clerk/fingerprint/fingerprint-provider.js +8 -8
  21. package/dist/clerk/fingerprint/fingerprint-provider.mjs +8 -8
  22. package/dist/clerk/fingerprint/fingerprint-server.d.ts +12 -12
  23. package/dist/clerk/fingerprint/fingerprint-server.js +17 -17
  24. package/dist/clerk/fingerprint/fingerprint-server.mjs +17 -17
  25. package/dist/clerk/fingerprint/fingerprint-shared.d.ts +3 -3
  26. package/dist/clerk/fingerprint/fingerprint-shared.js +10 -10
  27. package/dist/clerk/fingerprint/fingerprint-shared.mjs +10 -10
  28. package/dist/clerk/fingerprint/types.d.ts +0 -1
  29. package/dist/clerk/fingerprint/use-fingerprint.js +7 -7
  30. package/dist/clerk/fingerprint/use-fingerprint.mjs +7 -7
  31. package/dist/clerk/signin-with-fingerprint-client.d.ts +2 -2
  32. package/dist/clerk/signin-with-fingerprint-client.js +7 -6
  33. package/dist/clerk/signin-with-fingerprint-client.mjs +7 -6
  34. package/dist/clerk/signup-button-with-fingerprint-client.js +6 -4
  35. package/dist/clerk/signup-button-with-fingerprint-client.mjs +6 -4
  36. package/dist/clerk/signup-with-fingerprint-client.d.ts +2 -2
  37. package/dist/clerk/signup-with-fingerprint-client.js +7 -6
  38. package/dist/clerk/signup-with-fingerprint-client.mjs +7 -6
  39. package/dist/fuma/heavy/mermaid.js +1 -1
  40. package/dist/fuma/heavy/mermaid.mjs +1 -1
  41. package/dist/fuma/mdx/fuma-github-info.d.ts +1 -2
  42. package/dist/fuma/mdx/fuma-github-info.js +3 -6
  43. package/dist/fuma/mdx/fuma-github-info.mjs +3 -6
  44. package/dist/fuma/site-x.js +0 -1
  45. package/dist/fuma/site-x.mjs +0 -1
  46. package/dist/main/calendar/calendar-date-range-input.js +1 -1
  47. package/dist/main/calendar/calendar-date-range-input.mjs +1 -1
  48. package/dist/main/credit/credit-overview-nav-client.d.ts +12 -0
  49. package/dist/main/credit/credit-overview-nav-client.js +65 -0
  50. package/dist/main/credit/credit-overview-nav-client.mjs +63 -0
  51. package/dist/main/credit/index.d.ts +2 -0
  52. package/dist/main/credit/index.js +2 -0
  53. package/dist/main/credit/index.mjs +1 -0
  54. package/dist/main/credit/types.d.ts +8 -8
  55. package/dist/main/money-price/index.d.ts +1 -1
  56. package/dist/main/money-price/money-price-button.js +10 -10
  57. package/dist/main/money-price/money-price-button.mjs +10 -10
  58. package/dist/main/money-price/money-price-config-util.d.ts +30 -30
  59. package/dist/main/money-price/money-price-config-util.js +48 -48
  60. package/dist/main/money-price/money-price-config-util.mjs +48 -48
  61. package/dist/main/money-price/money-price-interactive.js +30 -18
  62. package/dist/main/money-price/money-price-interactive.mjs +30 -18
  63. package/dist/main/money-price/money-price-types.d.ts +7 -1
  64. package/dist/main/money-price/money-price-types.js +2 -2
  65. package/dist/main/money-price/money-price-types.mjs +2 -2
  66. package/dist/main/money-price/server.d.ts +1 -1
  67. package/dist/main/pill-select/x-pill-select.js +2 -2
  68. package/dist/main/pill-select/x-pill-select.mjs +2 -2
  69. package/dist/main/server.d.ts +1 -1
  70. package/package.json +13 -7
  71. package/src/ai/ai-prompt-textarea.tsx +6 -6
  72. package/src/clerk/clerk-auth-appearance.ts +16 -0
  73. package/src/clerk/clerk-page-context-generator.tsx +3 -5
  74. package/src/clerk/clerk-page-generator.tsx +9 -8
  75. package/src/clerk/clerk-user-client.tsx +14 -5
  76. package/src/clerk/fingerprint/fingerprint-client.ts +20 -20
  77. package/src/clerk/fingerprint/fingerprint-provider.tsx +11 -11
  78. package/src/clerk/fingerprint/fingerprint-server.ts +17 -17
  79. package/src/clerk/fingerprint/fingerprint-shared.ts +10 -10
  80. package/src/clerk/fingerprint/types.ts +0 -1
  81. package/src/clerk/fingerprint/use-fingerprint.ts +7 -7
  82. package/src/clerk/signin-with-fingerprint-client.tsx +7 -7
  83. package/src/clerk/signup-button-with-fingerprint-client.tsx +7 -5
  84. package/src/clerk/signup-with-fingerprint-client.tsx +7 -7
  85. package/src/fuma/base/custom-home-layout.tsx +4 -4
  86. package/src/fuma/heavy/mermaid.tsx +1 -1
  87. package/src/fuma/mdx/fuma-github-info.tsx +3 -8
  88. package/src/fuma/site-x.tsx +0 -1
  89. package/src/main/calendar/calendar-date-range-input.tsx +1 -1
  90. package/src/main/credit/credit-overview-nav-client.tsx +95 -0
  91. package/src/main/credit/index.ts +5 -0
  92. package/src/main/credit/types.ts +8 -8
  93. package/src/main/gallery/gallery-mobile-swiper.tsx +0 -1
  94. package/src/main/gallery/gallery-server.tsx +2 -2
  95. package/src/main/money-price/index.ts +2 -0
  96. package/src/main/money-price/money-price-button.tsx +10 -10
  97. package/src/main/money-price/money-price-config-util.ts +49 -49
  98. package/src/main/money-price/money-price-interactive.tsx +40 -20
  99. package/src/main/money-price/money-price-types.ts +21 -14
  100. package/src/main/money-price/server.ts +2 -0
  101. package/src/main/pill-select/x-pill-select.tsx +2 -2
  102. package/src/main/server.ts +3 -1
  103. package/src/styles/third-ui.css +8 -0
@@ -47,21 +47,21 @@ export interface CreditCTAConfig {
47
47
  export type CreditBucketStatus = 'active' | 'expiringSoon' | 'expired';
48
48
 
49
49
  export interface CreditBucket {
50
- /** 业务方自定义的积分类型标识,用于映射翻译或埋点 */
50
+ /** Business-defined credit type identifier for translation mapping or analytics. */
51
51
  kind: string;
52
- /** 若提供则使用该名称,否则由组件根据 kind 使用默认翻译 */
52
+ /** Display name override; otherwise the component uses the default translation for kind. */
53
53
  label?: string;
54
- /** 当前积分余额 */
54
+ /** Current credit balance. */
55
55
  balance: number;
56
- /** 该类型积分的额度上限 */
56
+ /** Credit limit for this credit type. */
57
57
  limit: number;
58
- /** 可选状态标签,用于强调过期等状态 */
58
+ /** Optional status label for highlighting states such as expiration. */
59
59
  status?: CreditBucketStatus;
60
- /** 积分过期时间(本地时区字符串),用于组件内部推导状态 */
60
+ /** Credit expiration time as a local time string, used to derive component state. */
61
61
  expiresAt?: string;
62
- /** 进度百分比(0-100);未提供时组件按 balance/limit 计算 */
62
+ /** Progress percentage from 0 to 100; computed from balance/limit when omitted. */
63
63
  progressPercent?: number;
64
- /** 任何额外说明,如剩余天数、使用限制等 */
64
+ /** Additional details, such as remaining days or usage limits. */
65
65
  description?: string;
66
66
  }
67
67
 
@@ -19,7 +19,6 @@ const swiperThemeStyle = {
19
19
  export function GalleryMobileSwiper({ items }: Props) {
20
20
  return (
21
21
  <div className="block sm:hidden px-4">
22
- {/* 外层容器:强制 maxWidth,防止任何溢出 */}
23
22
  <div
24
23
  className="w-full overflow-hidden"
25
24
  style={{ maxWidth: "min(calc(100vw - 48px), 350px)", margin: "0 auto" }}
@@ -33,10 +33,10 @@ export async function Gallery({ locale, sectionClassName, button }: GalleryProps
33
33
  </h2>
34
34
  <p className="text-center max-w-2xl mx-auto mb-16">{data.description}</p>
35
35
 
36
- {/* 移动端轮播 */}
36
+ {/* Mobile swiper */}
37
37
  <GalleryMobileSwiper items={data.items} />
38
38
 
39
- {/* 桌面端网格 */}
39
+ {/* Desktop grid */}
40
40
  <GalleryDesktopGrid items={data.items} />
41
41
 
42
42
  {button && <div className="text-center mx-auto mt-12 max-w-[85vw]">{button}</div>}
@@ -5,6 +5,8 @@ export { MoneyPriceButton } from './money-price-button';
5
5
  export type {
6
6
  MoneyPriceConfig,
7
7
  MoneyPriceData,
8
+ MoneyPriceAnimeTone,
9
+ MoneyPriceStrictDiffAnime,
8
10
  InitUserContext,
9
11
  MoneyPriceInteractiveProps,
10
12
  MoneyPriceButtonProps,
@@ -44,9 +44,9 @@ export function MoneyPriceButton({
44
44
  return 0;
45
45
  };
46
46
 
47
- // OneTime 模式的按钮配置
47
+ // Button configuration for one-time mode.
48
48
  const getOnetimeButtonConfig = () => {
49
- // 匿名用户:所有卡片都显示登录按钮
49
+ // Anonymous users: show the sign-in button on every card.
50
50
  if (!isAuthenticated) {
51
51
  return {
52
52
  text: texts.getStarted,
@@ -57,12 +57,12 @@ export function MoneyPriceButton({
57
57
  }
58
58
 
59
59
  if (subscriptionStatus === UserState.Anonymous) {
60
- // 已登录但状态未知 视为 FreeUser
60
+ // Signed in but status unknown: treat as FreeUser.
61
61
  console.warn('Clerk is authed OK but user is anonymous!');
62
62
  return { text: '', disabled: true, hidden: true };
63
63
  }
64
64
 
65
- // 登录用户:OneTime 模式下所有卡片都显示购买积分按钮
65
+ // Signed-in users: show the buy-credits button on every card in one-time mode.
66
66
  return {
67
67
  text: texts.buyCredits || texts.upgrade,
68
68
  onClick: () => onAction(planKey, billingType),
@@ -71,9 +71,9 @@ export function MoneyPriceButton({
71
71
  };
72
72
  };
73
73
 
74
- // 订阅模式的按钮配置
74
+ // Button configuration for subscription mode.
75
75
  const getSubscriptionButtonConfig = () => {
76
- // 匿名用户
76
+ // Anonymous users.
77
77
  if (!isAuthenticated) {
78
78
  const getButtonText = () => {
79
79
  switch (planKey) {
@@ -96,7 +96,7 @@ export function MoneyPriceButton({
96
96
  };
97
97
  }
98
98
 
99
- // 已登录用户
99
+ // Signed-in users.
100
100
  switch (subscriptionStatus) {
101
101
  case UserState.FreeUser: {
102
102
  if (planTier === 'F1') {
@@ -115,7 +115,7 @@ export function MoneyPriceButton({
115
115
  }
116
116
 
117
117
  case UserState.ProUser: {
118
- // 不允许降级到 Free
118
+ // Do not allow downgrades to Free.
119
119
  if (planTier === 'F1') {
120
120
  return { hidden: true };
121
121
  }
@@ -209,13 +209,13 @@ export function MoneyPriceButton({
209
209
  }
210
210
 
211
211
  default:
212
- // 已登录但状态未知 视为 FreeUser
212
+ // Signed in but status unknown: treat as FreeUser.
213
213
  console.warn('Clerk is authed OK but user is anonymous!');
214
214
  return { text: '', disabled: true, hidden: true };
215
215
  }
216
216
  };
217
217
 
218
- // 主要的按钮配置函数
218
+ // Main button configuration function.
219
219
  const getButtonConfig = () => {
220
220
  if (billingType === 'onetime') {
221
221
  return getOnetimeButtonConfig();
@@ -1,27 +1,27 @@
1
1
  /**
2
2
  * Money Price Configuration
3
- * 价格组件配置文件
3
+ * Pricing component configuration.
4
4
  */
5
5
 
6
6
  import type { MoneyPriceConfig, PaymentProviderConfig, EnhancePricePlan } from './money-price-types';
7
7
 
8
8
  /**
9
- * 获取当前激活的支付供应商配置
9
+ * Get the currently active payment provider configuration.
10
10
  *
11
- * 🔒 安全设计:
12
- * - util层负责从config中提取激活的provider配置
13
- * - 只返回提取的结果,不暴露任何config结构
14
- * - 调用方(应用层)通过wrapper隐藏config对象
11
+ * Security design:
12
+ * - The utility layer extracts the active provider configuration from the config.
13
+ * - Only the extracted result is returned; the full config structure is not exposed.
14
+ * - Application-level wrappers hide the config object from callers.
15
15
  *
16
- * @param config - MoneyPriceConfig对象(由应用层提供)
17
- * @returns 当前激活的支付供应商配置
16
+ * @param config - MoneyPriceConfig object provided by the application layer.
17
+ * @returns The currently active payment provider configuration.
18
18
  */
19
19
  export function getActiveProviderConfigUtil(config: MoneyPriceConfig): PaymentProviderConfig {
20
20
  const provider = config.activeProvider;
21
21
  return config.paymentProviders[provider];
22
22
  }
23
23
 
24
- // 辅助函数:获取特定产品的价格信息
24
+ // Helper: get pricing information for a specific product.
25
25
  export function getProductPricing(
26
26
  productKey: 'F1' | 'P2' | 'U3',
27
27
  billingType: string,
@@ -30,10 +30,10 @@ export function getProductPricing(
30
30
  ): EnhancePricePlan {
31
31
  const providerConfig = config.paymentProviders[provider];
32
32
 
33
- // 如果是 onetime 类型,尝试从积分包中获取
33
+ // For one-time billing, try to resolve pricing from credit packs.
34
34
  if (billingType === 'onetime') {
35
35
  const creditPacks = providerConfig.creditPackProducts;
36
- // 直接使用相同的 keyF1->F1, P2->P2, U3->U3
36
+ // Use the same product key directly: F1 -> F1, P2 -> P2, U3 -> U3.
37
37
  if (creditPacks && creditPacks[productKey]) {
38
38
  const pack = creditPacks[productKey];
39
39
  return {
@@ -45,7 +45,7 @@ export function getProductPricing(
45
45
  }
46
46
  }
47
47
 
48
- // 否则从订阅产品中获取
48
+ // Otherwise resolve pricing from subscription products.
49
49
  const products = providerConfig.subscriptionProducts || providerConfig.products;
50
50
  if (products && products[productKey] && products[productKey].plans[billingType]) {
51
51
  return products[productKey].plans[billingType];
@@ -54,19 +54,19 @@ export function getProductPricing(
54
54
  throw new Error(`Product pricing not found for ${productKey} ${billingType}`);
55
55
  }
56
56
 
57
- // ============ 安全的util函数 - 只接收简单的映射表参数,不暴露任何config细节 ============
57
+ // ============ Safe utility functions: accept only simple mapping inputs and do not expose config internals ============
58
58
 
59
59
  /**
60
- * 根据 priceId 获取对应的积分数量
60
+ * Get the credit amount for a price ID.
61
61
  *
62
- * 🔒 安全设计:
63
- * - util层负责解析config,提取所需数据
64
- * - 只返回查询结果,不暴露任何config结构
65
- * - 调用方(应用层)通过wrapper隐藏config对象
62
+ * Security design:
63
+ * - The utility layer parses the config and extracts only the required data.
64
+ * - Only the query result is returned; the full config structure is not exposed.
65
+ * - Application-level wrappers hide the config object from callers.
66
66
  *
67
- * @param priceId - 查询的价格ID
68
- * @param config - MoneyPriceConfig对象(由应用层提供)
69
- * @returns 对应的积分数量,或null
67
+ * @param priceId - Price ID to query.
68
+ * @param config - MoneyPriceConfig object provided by the application layer.
69
+ * @returns The matching credit amount, or null.
70
70
  */
71
71
  export function getCreditsFromPriceIdUtil(
72
72
  priceId: string | undefined,
@@ -76,9 +76,9 @@ export function getCreditsFromPriceIdUtil(
76
76
  return null;
77
77
  }
78
78
 
79
- // 遍历所有支付提供商
79
+ // Iterate through all payment providers.
80
80
  for (const provider of Object.values(config.paymentProviders)) {
81
- // 遍历订阅产品
81
+ // Iterate through subscription products.
82
82
  const subscriptionProducts = (
83
83
  provider.subscriptionProducts || provider.products
84
84
  ) as Record<string, any>;
@@ -96,7 +96,7 @@ export function getCreditsFromPriceIdUtil(
96
96
  }
97
97
  }
98
98
 
99
- // 遍历积分包产品
99
+ // Iterate through credit pack products.
100
100
  const creditPacks = provider.creditPackProducts as Record<string, any>;
101
101
  if (creditPacks) {
102
102
  for (const pack of Object.values(creditPacks)) {
@@ -112,23 +112,23 @@ export function getCreditsFromPriceIdUtil(
112
112
  }
113
113
 
114
114
  /**
115
- * 根据查询参数获取价格配置
115
+ * Get price configuration by query parameters.
116
116
  *
117
- * 支持三种查询方式:
118
- * 1. priceId 直接查询
119
- * 2. plan + billingType 查询
120
- * 3. plan 查询
117
+ * Supported query modes:
118
+ * 1. Query directly by priceId.
119
+ * 2. Query by plan and billingType.
120
+ * 3. Query by plan.
121
121
  *
122
- * 🔒 安全设计:
123
- * - util层负责解析config,提取和匹配数据
124
- * - 只返回查询结果,不暴露任何config结构
125
- * - 调用方(应用层)通过wrapper隐藏config对象
122
+ * Security design:
123
+ * - The utility layer parses the config and extracts only matching data.
124
+ * - Only the query result is returned; the full config structure is not exposed.
125
+ * - Application-level wrappers hide the config object from callers.
126
126
  *
127
- * @param priceId - 查询的价格ID(可选)
128
- * @param plan - 查询的套餐名称如'P2''U3'(可选)
129
- * @param billingType - 查询的计费类型如'monthly''yearly'(可选)
130
- * @param config - MoneyPriceConfig对象(由应用层提供)
131
- * @returns 匹配的价格配置,包含计算好的元数据(priceNamedescriptioninterval
127
+ * @param priceId - Optional price ID to query.
128
+ * @param plan - Optional plan name, such as 'P2' or 'U3'.
129
+ * @param billingType - Optional billing type, such as 'monthly' or 'yearly'.
130
+ * @param config - MoneyPriceConfig object provided by the application layer.
131
+ * @returns The matching price config with derived metadata: priceName, description, and interval.
132
132
  */
133
133
  export function getPriceConfigUtil(
134
134
  priceId: string | undefined,
@@ -136,9 +136,9 @@ export function getPriceConfigUtil(
136
136
  billingType: string | undefined,
137
137
  config: MoneyPriceConfig
138
138
  ): (EnhancePricePlan & { priceName: string; description: string; interval?: string }) | null {
139
- // 遍历所有支付提供商
139
+ // Iterate through all payment providers.
140
140
  for (const provider of Object.values(config.paymentProviders)) {
141
- // 遍历订阅产品
141
+ // Iterate through subscription products.
142
142
  const subscriptionProducts = (
143
143
  provider.subscriptionProducts || provider.products
144
144
  ) as Record<string, any>;
@@ -149,8 +149,8 @@ export function getPriceConfigUtil(
149
149
  for (const [billingKey, planConfig] of Object.entries(product.plans)) {
150
150
  const plan_config = planConfig as any;
151
151
 
152
- // 匹配逻辑:按优先级尝试
153
- // 1. priceId精确匹配(优先级最高)
152
+ // Matching order by priority.
153
+ // 1. Exact priceId match with highest priority.
154
154
  if (priceId && plan_config.priceId === priceId) {
155
155
  return {
156
156
  ...plan_config,
@@ -160,7 +160,7 @@ export function getPriceConfigUtil(
160
160
  };
161
161
  }
162
162
 
163
- // 2. planbillingType同时匹配
163
+ // 2. Match by both plan and billingType.
164
164
  if (!priceId && plan && billingType) {
165
165
  if (productKey === plan && billingKey === billingType) {
166
166
  return {
@@ -172,7 +172,7 @@ export function getPriceConfigUtil(
172
172
  }
173
173
  }
174
174
 
175
- // 3. plan匹配(billingType为空时)
175
+ // 3. Match by plan when billingType is empty.
176
176
  if (!priceId && !billingType && plan && productKey === plan) {
177
177
  return {
178
178
  ...plan_config,
@@ -186,13 +186,13 @@ export function getPriceConfigUtil(
186
186
  }
187
187
  }
188
188
 
189
- // 遍历积分包产品
189
+ // Iterate through credit pack products.
190
190
  const creditPacks = provider.creditPackProducts as Record<string, any>;
191
191
  if (creditPacks) {
192
192
  for (const [packKey, pack] of Object.entries(creditPacks)) {
193
193
  const pack_typed = pack as any;
194
194
 
195
- // 积分包匹配
195
+ // Credit pack match.
196
196
  if (priceId && pack_typed.priceId === priceId) {
197
197
  return {
198
198
  priceId: pack_typed.priceId,
@@ -205,7 +205,7 @@ export function getPriceConfigUtil(
205
205
  };
206
206
  }
207
207
 
208
- // plan和onetime匹配
208
+ // Match by plan and one-time billing.
209
209
  if (!priceId && plan && billingType === 'onetime') {
210
210
  if (packKey === plan) {
211
211
  return {
@@ -220,7 +220,7 @@ export function getPriceConfigUtil(
220
220
  }
221
221
  }
222
222
 
223
- // plan匹配(billingType为空时也能找到first积分包)
223
+ // Match by plan; also resolves the first credit pack when billingType is empty.
224
224
  if (!priceId && !billingType && plan && packKey === plan) {
225
225
  return {
226
226
  priceId: pack_typed.priceId,
@@ -237,4 +237,4 @@ export function getPriceConfigUtil(
237
237
  }
238
238
 
239
239
  return null;
240
- }
240
+ }
@@ -19,6 +19,7 @@ import {
19
19
  } from './money-price-types';
20
20
  import { redirectToCustomerPortal } from './customer-portal';
21
21
  import { themeButtonGradientClass, themeButtonGradientHoverClass, themeIconColor } from '@windrun-huaiin/base-ui/lib';
22
+ import { AnimeBeamFrame } from '../anime';
22
23
 
23
24
  type BillingType = string;
24
25
  type ProcessingTarget = {
@@ -56,12 +57,12 @@ export function MoneyPriceInteractive({
56
57
  const billingOptions = useMemo(() => {
57
58
  const options = data.billingSwitch.options as BillingOption[];
58
59
 
59
- // 如果配置了 enabledBillingTypes,只显示配置的类型
60
+ // If enabledBillingTypes is configured, show only those billing types.
60
61
  if (enabledBillingTypes?.length) {
61
62
  return options.filter(option => enabledBillingTypes.includes(option.key));
62
63
  }
63
64
 
64
- // 否则显示所有配置的选项
65
+ // Otherwise show all configured options.
65
66
  return options;
66
67
  }, [data.billingSwitch.options, enabledBillingTypes]);
67
68
  const billingOptionMap = useMemo(() => {
@@ -73,12 +74,12 @@ export function MoneyPriceInteractive({
73
74
  const defaultBilling = useMemo<BillingType>(() => {
74
75
  const defaultKey = data.billingSwitch.defaultKey;
75
76
 
76
- // 如果默认值在可用选项中,使用默认值
77
+ // Use the default value when it is available.
77
78
  if (billingOptions.some(opt => opt.key === defaultKey)) {
78
79
  return defaultKey;
79
80
  }
80
81
 
81
- // 否则使用第一个可用选项
82
+ // Otherwise use the first available option.
82
83
  return billingOptions[0]?.key || 'monthly';
83
84
  }, [data.billingSwitch.defaultKey, billingOptions]);
84
85
 
@@ -95,18 +96,18 @@ export function MoneyPriceInteractive({
95
96
  const priceIdsByCycle = useMemo(() => {
96
97
  const priceIds: Record<string, string[]> = {};
97
98
 
98
- // 为每个可用的计费类型创建价格ID数组
99
+ // Build a price ID list for each available billing type.
99
100
  billingOptions.forEach(option => {
100
101
  priceIds[option.key] = [];
101
102
 
102
103
  if (option.key === 'onetime') {
103
- // 处理积分包产品
104
+ // Handle credit pack products.
104
105
  const creditPacks = providerConfig.creditPackProducts || {};
105
106
  Object.values(creditPacks).forEach((pack: any) => {
106
107
  priceIds[option.key].push(pack.priceId);
107
108
  });
108
109
  } else {
109
- // 处理订阅产品
110
+ // Handle subscription products.
110
111
  const products = providerConfig.subscriptionProducts || providerConfig.products || {};
111
112
  PLAN_KEYS.forEach(planKey => {
112
113
  const product = (products as any)[planKey];
@@ -341,7 +342,7 @@ export function MoneyPriceInteractive({
341
342
  enableSubscriptionUpgrade
342
343
  ]);
343
344
 
344
- // 根据当前计费类型动态选择要显示的 plans
345
+ // Select visible plans dynamically based on the current billing type.
345
346
  const currentPlans = useMemo(() => {
346
347
  if (billingType === 'onetime') {
347
348
  return data.creditsPlans || [];
@@ -374,12 +375,12 @@ export function MoneyPriceInteractive({
374
375
  const discountBadgeText = useMemo(() => {
375
376
  if (!selectedBillingOption?.discountText) return null;
376
377
 
377
- // 对于 onetime 模式,直接显示 discountText,不依赖 discountPercent
378
+ // In one-time mode, show discountText directly without relying on discountPercent.
378
379
  if (billingType === 'onetime') {
379
380
  return selectedBillingOption.discountText;
380
381
  }
381
382
 
382
- // 对于订阅模式,查找 discountPercent 并替换
383
+ // In subscription mode, find discountPercent and interpolate it.
383
384
  let discountPercent: number | null = null;
384
385
  const products = providerConfig.subscriptionProducts || providerConfig.products || {};
385
386
 
@@ -394,7 +395,7 @@ export function MoneyPriceInteractive({
394
395
  return selectedBillingOption.discountText.replace('{percent}', String(discountPercent));
395
396
  }, [selectedBillingOption, providerConfig, billingType]);
396
397
 
397
- // 配置移动端BillingTypeButton悬浮样式
398
+ // Configure the mobile floating style for BillingTypeButton.
398
399
  return (
399
400
  <>
400
401
  <div className="flex justify-center mb-6 max-md:sticky max-md:top-30 max-md:z-30 max-md:py-2 max-md:bg-transparent">
@@ -442,18 +443,36 @@ export function MoneyPriceInteractive({
442
443
 
443
444
  const showBillingSubtitle = plan.showBillingSubTitle !== false;
444
445
  const hasDiscount = !!pricing.discountPercent && !!pricing.originalAmount;
446
+ const hasStrictDiffAnime = Object.prototype.hasOwnProperty.call(
447
+ plan.strictDiffAnime ?? {},
448
+ billingType
449
+ );
450
+ const animeTone = hasStrictDiffAnime
451
+ ? plan.strictDiffAnime?.[billingType]
452
+ : plan.animeTone;
453
+ const hasAnimeTone = !!animeTone;
445
454
 
446
- // 移动端宽度样式
447
455
  return (
456
+ <AnimeBeamFrame
457
+ key={`${billingType}-${plan.key}-${animeTone ?? 'none'}`}
458
+ active={false}
459
+ interactive={hasAnimeTone}
460
+ tone={animeTone ?? 'theme'}
461
+ radius={16}
462
+ className={cn(
463
+ 'h-full w-[85vw] max-w-[360px]',
464
+ 'md:w-[clamp(280px,32vw,360px)] md:max-w-[360px] md:shrink-0',
465
+ )}
466
+ >
448
467
  <div
449
- key={plan.key}
450
468
  data-price-plan={planKey}
451
469
  className={cn(
452
- 'flex flex-col bg-white dark:bg-gray-800/60 rounded-2xl border border-gray-300 dark:border-[#7c3aed40] transition p-5 md:p-8 h-full shadow-sm dark:shadow-none w-[85vw] max-w-[360px]',
453
- 'md:w-[clamp(280px,32vw,360px)] md:max-w-[360px] md:shrink-0',
454
- 'hover:border-2 hover:border-current',
455
- 'focus-within:border-2 focus-within:border-current',
456
- themeIconColor
470
+ 'flex flex-col bg-white dark:bg-gray-800/60 rounded-2xl border border-gray-300 dark:border-[#7c3aed40] transition p-5 md:p-8 h-full shadow-sm dark:shadow-none',
471
+ !hasAnimeTone && [
472
+ 'hover:border-current',
473
+ 'focus-within:border-current',
474
+ themeIconColor,
475
+ ]
457
476
  )}
458
477
  style={{ minHeight: maxFeaturesCount * (isTouchDevice ? 86 : 100) }}
459
478
  >
@@ -498,7 +517,7 @@ export function MoneyPriceInteractive({
498
517
  data-price-subtitle={planKey}
499
518
  >
500
519
  {showBillingSubtitle && billingType === 'onetime' ? (
501
- // OneTime 模式下的特殊处理:普通文本 + 带样式的产品副标题
520
+ // Special one-time mode rendering: plain text plus styled product subtitle.
502
521
  <>
503
522
  {selectedBillingOption?.subTitle && (
504
523
  <span className="text-[11px] md:text-xs text-gray-700 dark:text-gray-300 font-medium">
@@ -512,7 +531,7 @@ export function MoneyPriceInteractive({
512
531
  )}
513
532
  </>
514
533
  ) : (
515
- // 其他模式下保持原逻辑
534
+ // Keep the original rendering for other modes.
516
535
  showBillingSubtitle && (
517
536
  <span className="text-[11px] md:text-xs text-gray-700 dark:text-gray-300 font-medium">
518
537
  {selectedBillingOption?.subTitle || ''}
@@ -570,6 +589,7 @@ export function MoneyPriceInteractive({
570
589
  enableSubscriptionUpgrade={enableSubscriptionUpgrade}
571
590
  />
572
591
  </div>
592
+ </AnimeBeamFrame>
573
593
  );
574
594
  })}
575
595
  </div>
@@ -2,10 +2,10 @@ import type { XCredit, XSubscription, XUser } from '../../clerk/fingerprint/type
2
2
 
3
3
  /**
4
4
  * Money Price Component Types
5
- * 价格组件类型定义
5
+ * Pricing component type definitions.
6
6
  */
7
7
 
8
- // 用户状态枚举
8
+ // User status enum.
9
9
  export enum UserState {
10
10
  Anonymous = 'anonymous',
11
11
  FreeUser = 'free',
@@ -13,7 +13,7 @@ export enum UserState {
13
13
  UltraUser = 'ultra'
14
14
  }
15
15
 
16
- // 用户上下文
16
+ // User context.
17
17
  export interface UserContext {
18
18
  isAuthenticated: boolean;
19
19
  subscriptionStatus: UserState;
@@ -29,10 +29,10 @@ export interface InitUserContext {
29
29
  isClerkAuthenticated?: boolean;
30
30
  }
31
31
 
32
- // 支付供应商类型
32
+ // Payment provider type.
33
33
  export type PaymentProvider = 'stripe' | 'apple' | 'paypal' | 'wechat' | 'alipay' ;
34
34
 
35
- // 价格计划
35
+ // Price plan.
36
36
  export interface EnhancePricePlan {
37
37
  priceId: string;
38
38
  amount: number;
@@ -42,13 +42,13 @@ export interface EnhancePricePlan {
42
42
  credits?: number;
43
43
  }
44
44
 
45
- // 订阅产品配置
45
+ // Subscription product configuration.
46
46
  export interface SubscriptionProductConfig {
47
47
  key: string;
48
48
  plans: Record<string, EnhancePricePlan>;
49
49
  }
50
50
 
51
- // 积分包产品配置
51
+ // Credit pack product configuration.
52
52
  export interface CreditPackProductConfig {
53
53
  key: string;
54
54
  priceId: string;
@@ -57,7 +57,7 @@ export interface CreditPackProductConfig {
57
57
  credits: number;
58
58
  }
59
59
 
60
- // 支付供应商配置
60
+ // Payment provider configuration.
61
61
  export interface PaymentProviderConfig {
62
62
  provider: PaymentProvider;
63
63
  enabled: boolean;
@@ -71,7 +71,7 @@ export interface PaymentProviderConfig {
71
71
  P2: CreditPackProductConfig;
72
72
  U3: CreditPackProductConfig;
73
73
  };
74
- // 兼容旧结构
74
+ // Backward-compatible legacy shape.
75
75
  products?: {
76
76
  F1: SubscriptionProductConfig;
77
77
  P2: SubscriptionProductConfig;
@@ -79,7 +79,7 @@ export interface PaymentProviderConfig {
79
79
  };
80
80
  }
81
81
 
82
- // 主配置
82
+ // Main configuration.
83
83
  export interface MoneyPriceConfig {
84
84
  paymentProviders: {
85
85
  [provider: string]: PaymentProviderConfig;
@@ -92,7 +92,7 @@ export interface MoneyPriceConfig {
92
92
  };
93
93
  }
94
94
 
95
- // 组件属性
95
+ // Component props.
96
96
  export interface MoneyPriceProps {
97
97
  locale: string;
98
98
  config: MoneyPriceConfig;
@@ -107,7 +107,7 @@ export interface MoneyPriceProps {
107
107
  initialBillingType?: string;
108
108
  }
109
109
 
110
- // 交互组件属性
110
+ // Interactive component props.
111
111
  export interface MoneyPriceInteractiveProps {
112
112
  data: MoneyPriceData;
113
113
  config: MoneyPriceConfig;
@@ -122,7 +122,7 @@ export interface MoneyPriceInteractiveProps {
122
122
  isInitLoading?: boolean;
123
123
  }
124
124
 
125
- // 按钮组件属性
125
+ // Button component props.
126
126
  export interface MoneyPriceButtonProps {
127
127
  planKey: 'F1' | 'P2' | 'U3';
128
128
  userContext: UserContext;
@@ -143,7 +143,10 @@ export interface MoneyPriceButtonProps {
143
143
  enableSubscriptionUpgrade?: boolean;
144
144
  }
145
145
 
146
- // 数据结构
146
+ export type MoneyPriceAnimeTone = 'theme' | 'rainbow' | 'mono' | 'warm' | 'cool';
147
+ export type MoneyPriceStrictDiffAnime = Record<string, MoneyPriceAnimeTone | null | undefined>;
148
+
149
+ // Data structures.
147
150
  export interface MoneyPriceData {
148
151
  title: string;
149
152
  subtitle: string;
@@ -160,6 +163,8 @@ export interface MoneyPriceData {
160
163
  subscriptionPlans: Array<{
161
164
  key: string;
162
165
  title: string;
166
+ animeTone?: MoneyPriceAnimeTone;
167
+ strictDiffAnime?: MoneyPriceStrictDiffAnime;
163
168
  showBillingSubTitle?: boolean;
164
169
  titleTags?: string[];
165
170
  features?: Array<{
@@ -173,6 +178,8 @@ export interface MoneyPriceData {
173
178
  key: string;
174
179
  title: string;
175
180
  subtitle?: string;
181
+ animeTone?: MoneyPriceAnimeTone;
182
+ strictDiffAnime?: MoneyPriceStrictDiffAnime;
176
183
  showBillingSubTitle?: boolean;
177
184
  titleTags?: string[];
178
185
  features?: Array<{
@@ -11,6 +11,8 @@ export type {
11
11
  MoneyPriceInteractiveProps,
12
12
  MoneyPriceButtonProps,
13
13
  MoneyPriceData,
14
+ MoneyPriceAnimeTone,
15
+ MoneyPriceStrictDiffAnime,
14
16
  InitUserContext,
15
17
  PaymentProvider,
16
18
  PaymentProviderConfig,