@windrun-huaiin/third-ui 7.3.8 → 7.3.10

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/dist/main/faq.js CHANGED
@@ -14,6 +14,7 @@ var faqInteractive = require('./faq-interactive.js');
14
14
  require('next/navigation');
15
15
  require('@clerk/nextjs');
16
16
  require('../clerk/fingerprint/fingerprint-provider.js');
17
+ require('react-dom');
17
18
  require('next-themes');
18
19
  require('fumadocs-core/framework');
19
20
  require('next/link');
package/dist/main/faq.mjs CHANGED
@@ -12,6 +12,7 @@ import { FAQInteractive } from './faq-interactive.mjs';
12
12
  import 'next/navigation';
13
13
  import '@clerk/nextjs';
14
14
  import '../clerk/fingerprint/fingerprint-provider.mjs';
15
+ import 'react-dom';
15
16
  import 'next-themes';
16
17
  import 'fumadocs-core/framework';
17
18
  import 'next/link';
@@ -14,6 +14,7 @@ require('next/navigation');
14
14
  var galleryInteractive = require('./gallery-interactive.js');
15
15
  require('@clerk/nextjs');
16
16
  require('../clerk/fingerprint/fingerprint-provider.js');
17
+ require('react-dom');
17
18
  require('next-themes');
18
19
  require('fumadocs-core/framework');
19
20
  require('next/link');
@@ -12,6 +12,7 @@ import 'next/navigation';
12
12
  import { GalleryInteractive } from './gallery-interactive.mjs';
13
13
  import '@clerk/nextjs';
14
14
  import '../clerk/fingerprint/fingerprint-provider.mjs';
15
+ import 'react-dom';
15
16
  import 'next-themes';
16
17
  import 'fumadocs-core/framework';
17
18
  import 'next/link';
@@ -8,6 +8,7 @@ var React = require('react');
8
8
  var fingerprintProvider = require('../../clerk/fingerprint/fingerprint-provider.js');
9
9
  var utils = require('@windrun-huaiin/lib/utils');
10
10
  var navigation = require('next/navigation');
11
+ var ReactDOM = require('react-dom');
11
12
  var moneyPriceButton = require('./money-price-button.js');
12
13
  var moneyPriceConfigUtil = require('./money-price-config-util.js');
13
14
  var moneyPriceTypes = require('./money-price-types.js');
@@ -131,55 +132,47 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
131
132
  if (priceDiscountElement)
132
133
  priceDiscountElement.style.display = 'none';
133
134
  }
134
- const priceSubtitleElement = document.querySelector(`[data-price-subtitle="${plan.key}"]`);
135
- if (priceSubtitleElement && plan.showBillingSubTitle !== false) {
136
- const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
137
- priceSubtitleElement.textContent = (billingOption === null || billingOption === void 0 ? void 0 : billingOption.subTitle) || '';
138
- }
139
135
  });
140
136
  }, [config, data]);
141
- // 更新按钮样式
142
- const updateButtonStyles = React.useCallback((newBillingType) => {
143
- const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
144
- const yearlyButton = document.querySelector('[data-billing-button="yearly"]');
145
- const activeClasses = 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm';
146
- const inactiveClasses = 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full';
147
- if (monthlyButton && yearlyButton) {
148
- if (newBillingType === 'monthly') {
149
- monthlyButton.className = utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', activeClasses);
150
- yearlyButton.className = utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', inactiveClasses);
151
- }
152
- else {
153
- monthlyButton.className = utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', inactiveClasses);
154
- yearlyButton.className = utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', activeClasses);
155
- }
156
- }
157
- }, []);
158
137
  // 更新折扣信息
159
138
  const updateDiscountInfo = React.useCallback((newBillingType) => {
160
139
  const discountInfoElement = document.querySelector('[data-discount-info]');
161
- if (!discountInfoElement)
162
- return;
163
- const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
164
- const providerConfig = moneyPriceConfigUtil.getActiveProviderConfig(config);
165
- let hasDiscount = false;
166
- let discountPercent = 0;
167
- ['pro', 'ultra'].forEach(planKey => {
168
- const product = providerConfig.products[planKey];
169
- const pricing = product.plans[newBillingType];
170
- if (pricing.discountPercent) {
171
- hasDiscount = true;
172
- discountPercent = pricing.discountPercent;
140
+ if (discountInfoElement) {
141
+ const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
142
+ let hasDiscount = false;
143
+ let discountPercent = 0;
144
+ const providerConfig = moneyPriceConfigUtil.getActiveProviderConfig(config);
145
+ ['pro', 'ultra'].forEach(planKey => {
146
+ const pricing = providerConfig.products[planKey].plans[newBillingType];
147
+ if (pricing.discountPercent) {
148
+ hasDiscount = true;
149
+ discountPercent = pricing.discountPercent;
150
+ }
151
+ });
152
+ discountInfoElement.innerHTML = '';
153
+ if (hasDiscount && (billingOption === null || billingOption === void 0 ? void 0 : billingOption.discountText)) {
154
+ const discountBadge = document.createElement('span');
155
+ discountBadge.className = 'px-2 py-1 text-xs rounded bg-yellow-100 text-yellow-800 font-semibold align-middle text-center inline-flex items-center justify-center whitespace-nowrap';
156
+ discountBadge.textContent = billingOption.discountText.replace('{percent}', String(discountPercent));
157
+ discountInfoElement.appendChild(discountBadge);
173
158
  }
174
- });
175
- discountInfoElement.innerHTML = '';
176
- if (hasDiscount && (billingOption === null || billingOption === void 0 ? void 0 : billingOption.discountText)) {
177
- const discountBadge = document.createElement('span');
178
- discountBadge.className = 'px-2 py-1 text-xs rounded bg-yellow-100 text-yellow-800 font-semibold align-middle text-center inline-flex items-center justify-center whitespace-nowrap';
179
- discountBadge.textContent = billingOption.discountText.replace('{percent}', String(discountPercent));
180
- discountInfoElement.appendChild(discountBadge);
181
159
  }
182
160
  }, [config, data]);
161
+ // 更新按钮样式
162
+ const updateButtonStyles = React.useCallback((newBillingType) => {
163
+ const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
164
+ const yearlyButton = document.querySelector('[data-billing-button="yearly"]');
165
+ if (monthlyButton) {
166
+ monthlyButton.className = newBillingType === 'monthly'
167
+ ? utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm')
168
+ : utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full');
169
+ }
170
+ if (yearlyButton) {
171
+ yearlyButton.className = newBillingType === 'yearly'
172
+ ? utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm')
173
+ : utils.cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full');
174
+ }
175
+ }, []);
183
176
  // 处理月付/年付切换和 tooltip 功能
184
177
  React.useEffect(() => {
185
178
  const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
@@ -233,8 +226,17 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
233
226
  }
234
227
  });
235
228
  });
229
+ // Inject buttons into placeholders using createPortal
230
+ data.plans.forEach((plan) => {
231
+ const placeholder = document.querySelector(`[data-button-placeholder="${plan.key}"]`);
232
+ if (placeholder) {
233
+ ReactDOM.createPortal(jsxRuntime.jsx(moneyPriceButton.MoneyPriceButton, { planKey: plan.key, userContext: userContext, billingType: billingType, onLogin: handleLogin, onUpgrade: handleUpgrade, texts: data.buttonTexts, isProcessing: isProcessing }), placeholder);
234
+ }
235
+ });
236
+ // Initial updates
236
237
  updatePriceDisplay(billingType);
237
238
  updateDiscountInfo(billingType);
239
+ updateButtonStyles(billingType);
238
240
  return () => {
239
241
  if (monthlyButton) {
240
242
  monthlyButton.removeEventListener('click', handleMonthlyClick);
@@ -248,7 +250,7 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
248
250
  element.removeEventListener('mouseleave', handlers.mouseleave);
249
251
  });
250
252
  };
251
- }, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo]);
253
+ }, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
252
254
  // Tooltip 组件
253
255
  const Tooltip = ({ show, content, x, y }) => {
254
256
  if (!show)
@@ -265,8 +267,7 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
265
267
  };
266
268
  return (jsxRuntime.jsx("div", { style: style, className: "bg-gray-700 dark:bg-gray-200 text-gray-100 dark:text-gray-800 text-xs leading-relaxed px-3 py-2 rounded-lg shadow-lg border border-gray-300 dark:border-gray-600 backdrop-blur-sm", children: content }));
267
269
  };
268
- // 直接渲染按钮
269
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [data.plans.map((plan) => (jsxRuntime.jsx("div", { "data-button-placeholder": plan.key, children: jsxRuntime.jsx(moneyPriceButton.MoneyPriceButton, { planKey: plan.key, userContext: userContext, billingType: billingType, onLogin: handleLogin, onUpgrade: handleUpgrade, texts: data.buttonTexts, isProcessing: isProcessing }) }, plan.key))), jsxRuntime.jsx(Tooltip, Object.assign({}, tooltip))] }));
270
+ return jsxRuntime.jsx(Tooltip, Object.assign({}, tooltip));
270
271
  }
271
272
 
272
273
  exports.MoneyPriceInteractive = MoneyPriceInteractive;
@@ -1,11 +1,12 @@
1
1
  "use client";
2
2
  import { __awaiter } from '../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.2/node_modules/tslib/tslib.es6.mjs';
3
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
+ import { jsx } from 'react/jsx-runtime';
4
4
  import { useClerk } from '@clerk/nextjs';
5
5
  import { useState, useCallback, useMemo, useEffect } from 'react';
6
6
  import { useFingerprintContextSafe } from '../../clerk/fingerprint/fingerprint-provider.mjs';
7
7
  import { cn } from '@windrun-huaiin/lib/utils';
8
8
  import { useRouter } from 'next/navigation';
9
+ import { createPortal } from 'react-dom';
9
10
  import { MoneyPriceButton } from './money-price-button.mjs';
10
11
  import { getActiveProviderConfig, getProductPricing } from './money-price-config-util.mjs';
11
12
  import { UserState } from './money-price-types.mjs';
@@ -129,55 +130,47 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
129
130
  if (priceDiscountElement)
130
131
  priceDiscountElement.style.display = 'none';
131
132
  }
132
- const priceSubtitleElement = document.querySelector(`[data-price-subtitle="${plan.key}"]`);
133
- if (priceSubtitleElement && plan.showBillingSubTitle !== false) {
134
- const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
135
- priceSubtitleElement.textContent = (billingOption === null || billingOption === void 0 ? void 0 : billingOption.subTitle) || '';
136
- }
137
133
  });
138
134
  }, [config, data]);
139
- // 更新按钮样式
140
- const updateButtonStyles = useCallback((newBillingType) => {
141
- const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
142
- const yearlyButton = document.querySelector('[data-billing-button="yearly"]');
143
- const activeClasses = 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm';
144
- const inactiveClasses = 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full';
145
- if (monthlyButton && yearlyButton) {
146
- if (newBillingType === 'monthly') {
147
- monthlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', activeClasses);
148
- yearlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', inactiveClasses);
149
- }
150
- else {
151
- monthlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', inactiveClasses);
152
- yearlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', activeClasses);
153
- }
154
- }
155
- }, []);
156
135
  // 更新折扣信息
157
136
  const updateDiscountInfo = useCallback((newBillingType) => {
158
137
  const discountInfoElement = document.querySelector('[data-discount-info]');
159
- if (!discountInfoElement)
160
- return;
161
- const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
162
- const providerConfig = getActiveProviderConfig(config);
163
- let hasDiscount = false;
164
- let discountPercent = 0;
165
- ['pro', 'ultra'].forEach(planKey => {
166
- const product = providerConfig.products[planKey];
167
- const pricing = product.plans[newBillingType];
168
- if (pricing.discountPercent) {
169
- hasDiscount = true;
170
- discountPercent = pricing.discountPercent;
138
+ if (discountInfoElement) {
139
+ const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
140
+ let hasDiscount = false;
141
+ let discountPercent = 0;
142
+ const providerConfig = getActiveProviderConfig(config);
143
+ ['pro', 'ultra'].forEach(planKey => {
144
+ const pricing = providerConfig.products[planKey].plans[newBillingType];
145
+ if (pricing.discountPercent) {
146
+ hasDiscount = true;
147
+ discountPercent = pricing.discountPercent;
148
+ }
149
+ });
150
+ discountInfoElement.innerHTML = '';
151
+ if (hasDiscount && (billingOption === null || billingOption === void 0 ? void 0 : billingOption.discountText)) {
152
+ const discountBadge = document.createElement('span');
153
+ discountBadge.className = 'px-2 py-1 text-xs rounded bg-yellow-100 text-yellow-800 font-semibold align-middle text-center inline-flex items-center justify-center whitespace-nowrap';
154
+ discountBadge.textContent = billingOption.discountText.replace('{percent}', String(discountPercent));
155
+ discountInfoElement.appendChild(discountBadge);
171
156
  }
172
- });
173
- discountInfoElement.innerHTML = '';
174
- if (hasDiscount && (billingOption === null || billingOption === void 0 ? void 0 : billingOption.discountText)) {
175
- const discountBadge = document.createElement('span');
176
- discountBadge.className = 'px-2 py-1 text-xs rounded bg-yellow-100 text-yellow-800 font-semibold align-middle text-center inline-flex items-center justify-center whitespace-nowrap';
177
- discountBadge.textContent = billingOption.discountText.replace('{percent}', String(discountPercent));
178
- discountInfoElement.appendChild(discountBadge);
179
157
  }
180
158
  }, [config, data]);
159
+ // 更新按钮样式
160
+ const updateButtonStyles = useCallback((newBillingType) => {
161
+ const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
162
+ const yearlyButton = document.querySelector('[data-billing-button="yearly"]');
163
+ if (monthlyButton) {
164
+ monthlyButton.className = newBillingType === 'monthly'
165
+ ? cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm')
166
+ : cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full');
167
+ }
168
+ if (yearlyButton) {
169
+ yearlyButton.className = newBillingType === 'yearly'
170
+ ? cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm')
171
+ : cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full');
172
+ }
173
+ }, []);
181
174
  // 处理月付/年付切换和 tooltip 功能
182
175
  useEffect(() => {
183
176
  const monthlyButton = document.querySelector('[data-billing-button="monthly"]');
@@ -231,8 +224,17 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
231
224
  }
232
225
  });
233
226
  });
227
+ // Inject buttons into placeholders using createPortal
228
+ data.plans.forEach((plan) => {
229
+ const placeholder = document.querySelector(`[data-button-placeholder="${plan.key}"]`);
230
+ if (placeholder) {
231
+ createPortal(jsx(MoneyPriceButton, { planKey: plan.key, userContext: userContext, billingType: billingType, onLogin: handleLogin, onUpgrade: handleUpgrade, texts: data.buttonTexts, isProcessing: isProcessing }), placeholder);
232
+ }
233
+ });
234
+ // Initial updates
234
235
  updatePriceDisplay(billingType);
235
236
  updateDiscountInfo(billingType);
237
+ updateButtonStyles(billingType);
236
238
  return () => {
237
239
  if (monthlyButton) {
238
240
  monthlyButton.removeEventListener('click', handleMonthlyClick);
@@ -246,7 +248,7 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
246
248
  element.removeEventListener('mouseleave', handlers.mouseleave);
247
249
  });
248
250
  };
249
- }, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo]);
251
+ }, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
250
252
  // Tooltip 组件
251
253
  const Tooltip = ({ show, content, x, y }) => {
252
254
  if (!show)
@@ -263,8 +265,7 @@ function MoneyPriceInteractive({ data, config, upgradeApiEndpoint, signInPath })
263
265
  };
264
266
  return (jsx("div", { style: style, className: "bg-gray-700 dark:bg-gray-200 text-gray-100 dark:text-gray-800 text-xs leading-relaxed px-3 py-2 rounded-lg shadow-lg border border-gray-300 dark:border-gray-600 backdrop-blur-sm", children: content }));
265
267
  };
266
- // 直接渲染按钮
267
- return (jsxs(Fragment, { children: [data.plans.map((plan) => (jsx("div", { "data-button-placeholder": plan.key, children: jsx(MoneyPriceButton, { planKey: plan.key, userContext: userContext, billingType: billingType, onLogin: handleLogin, onUpgrade: handleUpgrade, texts: data.buttonTexts, isProcessing: isProcessing }) }, plan.key))), jsx(Tooltip, Object.assign({}, tooltip))] }));
268
+ return jsx(Tooltip, Object.assign({}, tooltip));
268
269
  }
269
270
 
270
271
  export { MoneyPriceInteractive };
@@ -14,6 +14,7 @@ var pricePlanInteractive = require('./price-plan-interactive.js');
14
14
  require('@clerk/nextjs');
15
15
  require('../clerk/fingerprint/fingerprint-provider.js');
16
16
  require('next/navigation');
17
+ require('react-dom');
17
18
  require('next-themes');
18
19
  require('fumadocs-core/framework');
19
20
  require('next/link');
@@ -12,6 +12,7 @@ import { PricePlanInteractive } from './price-plan-interactive.mjs';
12
12
  import '@clerk/nextjs';
13
13
  import '../clerk/fingerprint/fingerprint-provider.mjs';
14
14
  import 'next/navigation';
15
+ import 'react-dom';
15
16
  import 'next-themes';
16
17
  import 'fumadocs-core/framework';
17
18
  import 'next/link';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var coseBase$1 = require('../../../../../_virtual/cose-base2.js');
3
+ var coseBase$1 = require('../../../../../_virtual/cose-base.js');
4
4
  var layoutBase = require('../../../layout-base@1.0.2/node_modules/layout-base/layout-base.js');
5
5
 
6
6
  var coseBase = coseBase$1.__module.exports;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var coseBase$1 = require('../../../../../_virtual/cose-base.js');
3
+ var coseBase$1 = require('../../../../../_virtual/cose-base2.js');
4
4
  var layoutBase = require('../../../layout-base@2.0.1/node_modules/layout-base/layout-base.js');
5
5
 
6
6
  var coseBase = coseBase$1.__module.exports;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var layoutBase$1 = require('../../../../../_virtual/layout-base2.js');
3
+ var layoutBase$1 = require('../../../../../_virtual/layout-base.js');
4
4
 
5
5
  var layoutBase = layoutBase$1.__module.exports;
6
6
 
@@ -1,4 +1,4 @@
1
- import { __module as layoutBase$1 } from '../../../../../_virtual/layout-base2.mjs';
1
+ import { __module as layoutBase$1 } from '../../../../../_virtual/layout-base.mjs';
2
2
 
3
3
  var layoutBase = layoutBase$1.exports;
4
4
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var layoutBase$1 = require('../../../../../_virtual/layout-base.js');
3
+ var layoutBase$1 = require('../../../../../_virtual/layout-base2.js');
4
4
 
5
5
  var layoutBase = layoutBase$1.__module.exports;
6
6
 
@@ -1,4 +1,4 @@
1
- import { __module as layoutBase$1 } from '../../../../../_virtual/layout-base.mjs';
1
+ import { __module as layoutBase$1 } from '../../../../../_virtual/layout-base2.mjs';
2
2
 
3
3
  var layoutBase = layoutBase$1.exports;
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/third-ui",
3
- "version": "7.3.8",
3
+ "version": "7.3.10",
4
4
  "description": "Third-party integrated UI components for windrun-huaiin projects",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -5,6 +5,7 @@ import { useFingerprintContextSafe } from '@third-ui/clerk/fingerprint';
5
5
  import { cn } from '@windrun-huaiin/lib/utils';
6
6
  import { useRouter } from 'next/navigation';
7
7
  import React, { useEffect, useState, useMemo, useCallback } from 'react';
8
+ import { createPortal } from 'react-dom';
8
9
  import { MoneyPriceButton } from './money-price-button';
9
10
  import { getActiveProviderConfig, getProductPricing } from './money-price-config-util';
10
11
  import {
@@ -130,7 +131,6 @@ export function MoneyPriceInteractive({
130
131
 
131
132
  const priceOriginalElement = document.querySelector(`[data-price-original="${plan.key}"]`) as HTMLElement;
132
133
  const priceDiscountElement = document.querySelector(`[data-price-discount="${plan.key}"]`) as HTMLElement;
133
-
134
134
  if (pricing.originalAmount && pricing.discountPercent) {
135
135
  if (priceOriginalElement) {
136
136
  priceOriginalElement.style.display = 'inline';
@@ -140,74 +140,57 @@ export function MoneyPriceInteractive({
140
140
  priceDiscountElement.style.display = 'inline';
141
141
  const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
142
142
  if (billingOption?.discountText) {
143
- priceDiscountElement.textContent = billingOption.discountText.replace(
144
- '{percent}',
145
- String(pricing.discountPercent)
146
- );
143
+ priceDiscountElement.textContent = billingOption.discountText.replace('{percent}', String(pricing.discountPercent));
147
144
  }
148
145
  }
149
146
  } else {
150
147
  if (priceOriginalElement) priceOriginalElement.style.display = 'none';
151
148
  if (priceDiscountElement) priceDiscountElement.style.display = 'none';
152
149
  }
153
-
154
- const priceSubtitleElement = document.querySelector(`[data-price-subtitle="${plan.key}"]`) as HTMLElement;
155
- if (priceSubtitleElement && plan.showBillingSubTitle !== false) {
156
- const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
157
- priceSubtitleElement.textContent = billingOption?.subTitle || '';
158
- }
159
150
  });
160
151
  }, [config, data]);
161
152
 
162
- // 更新按钮样式
163
- const updateButtonStyles = useCallback((newBillingType: string) => {
164
- const monthlyButton = document.querySelector('[data-billing-button="monthly"]') as HTMLButtonElement;
165
- const yearlyButton = document.querySelector('[data-billing-button="yearly"]') as HTMLButtonElement;
166
-
167
- const activeClasses = 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm';
168
- const inactiveClasses = 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full';
169
-
170
- if (monthlyButton && yearlyButton) {
171
- if (newBillingType === 'monthly') {
172
- monthlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', activeClasses);
173
- yearlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', inactiveClasses);
174
- } else {
175
- monthlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', inactiveClasses);
176
- yearlyButton.className = cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', activeClasses);
177
- }
178
- }
179
- }, []);
180
-
181
153
  // 更新折扣信息
182
154
  const updateDiscountInfo = useCallback((newBillingType: string) => {
183
155
  const discountInfoElement = document.querySelector('[data-discount-info]') as HTMLElement;
184
- if (!discountInfoElement) return;
185
-
186
- const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
187
- const providerConfig = getActiveProviderConfig(config);
188
-
189
- let hasDiscount = false;
190
- let discountPercent = 0;
191
-
192
- ['pro', 'ultra'].forEach(planKey => {
193
- const product = providerConfig.products[planKey as 'pro' | 'ultra'];
194
- const pricing = product.plans[newBillingType as 'monthly' | 'yearly'];
195
- if (pricing.discountPercent) {
196
- hasDiscount = true;
197
- discountPercent = pricing.discountPercent;
156
+ if (discountInfoElement) {
157
+ const billingOption = data.billingSwitch.options.find(opt => opt.key === newBillingType);
158
+ let hasDiscount = false;
159
+ let discountPercent = 0;
160
+ const providerConfig = getActiveProviderConfig(config);
161
+ ['pro', 'ultra'].forEach(planKey => {
162
+ const pricing = providerConfig.products[planKey as 'pro' | 'ultra'].plans[newBillingType as 'monthly' | 'yearly'];
163
+ if (pricing.discountPercent) {
164
+ hasDiscount = true;
165
+ discountPercent = pricing.discountPercent;
166
+ }
167
+ });
168
+ discountInfoElement.innerHTML = '';
169
+ if (hasDiscount && billingOption?.discountText) {
170
+ const discountBadge = document.createElement('span');
171
+ discountBadge.className = 'px-2 py-1 text-xs rounded bg-yellow-100 text-yellow-800 font-semibold align-middle text-center inline-flex items-center justify-center whitespace-nowrap';
172
+ discountBadge.textContent = billingOption.discountText.replace('{percent}', String(discountPercent));
173
+ discountInfoElement.appendChild(discountBadge);
198
174
  }
199
- });
200
-
201
- discountInfoElement.innerHTML = '';
202
-
203
- if (hasDiscount && billingOption?.discountText) {
204
- const discountBadge = document.createElement('span');
205
- discountBadge.className = 'px-2 py-1 text-xs rounded bg-yellow-100 text-yellow-800 font-semibold align-middle text-center inline-flex items-center justify-center whitespace-nowrap';
206
- discountBadge.textContent = billingOption.discountText.replace('{percent}', String(discountPercent));
207
- discountInfoElement.appendChild(discountBadge);
208
175
  }
209
176
  }, [config, data]);
210
177
 
178
+ // 更新按钮样式
179
+ const updateButtonStyles = useCallback((newBillingType: string) => {
180
+ const monthlyButton = document.querySelector('[data-billing-button="monthly"]') as HTMLElement;
181
+ const yearlyButton = document.querySelector('[data-billing-button="yearly"]') as HTMLElement;
182
+ if (monthlyButton) {
183
+ monthlyButton.className = newBillingType === 'monthly'
184
+ ? cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm')
185
+ : cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full');
186
+ }
187
+ if (yearlyButton) {
188
+ yearlyButton.className = newBillingType === 'yearly'
189
+ ? cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-white bg-gradient-to-r from-purple-400 to-pink-500 hover:from-purple-500 hover:to-pink-600 dark:from-purple-500 dark:to-pink-600 dark:hover:from-purple-600 rounded-full shadow-sm')
190
+ : cn('min-w-[120px] px-6 py-2 font-medium transition text-lg relative', 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full');
191
+ }
192
+ }, []);
193
+
211
194
  // 处理月付/年付切换和 tooltip 功能
212
195
  useEffect(() => {
213
196
  const monthlyButton = document.querySelector('[data-billing-button="monthly"]') as HTMLButtonElement;
@@ -275,9 +258,30 @@ export function MoneyPriceInteractive({
275
258
  });
276
259
  });
277
260
 
261
+ // Inject buttons into placeholders using createPortal
262
+ data.plans.forEach((plan: any) => {
263
+ const placeholder = document.querySelector(`[data-button-placeholder="${plan.key}"]`) as HTMLElement;
264
+ if (placeholder) {
265
+ createPortal(
266
+ <MoneyPriceButton
267
+ planKey={plan.key}
268
+ userContext={userContext}
269
+ billingType={billingType}
270
+ onLogin={handleLogin}
271
+ onUpgrade={handleUpgrade}
272
+ texts={data.buttonTexts}
273
+ isProcessing={isProcessing}
274
+ />,
275
+ placeholder
276
+ );
277
+ }
278
+ });
279
+
280
+ // Initial updates
278
281
  updatePriceDisplay(billingType);
279
282
  updateDiscountInfo(billingType);
280
-
283
+ updateButtonStyles(billingType);
284
+
281
285
  return () => {
282
286
  if (monthlyButton) {
283
287
  monthlyButton.removeEventListener('click', handleMonthlyClick);
@@ -292,7 +296,7 @@ export function MoneyPriceInteractive({
292
296
  element.removeEventListener('mouseleave', handlers.mouseleave);
293
297
  });
294
298
  };
295
- }, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo]);
299
+ }, [data, billingType, updatePriceDisplay, updateButtonStyles, updateDiscountInfo, userContext, handleLogin, handleUpgrade, isProcessing]);
296
300
 
297
301
  // Tooltip 组件
298
302
  const Tooltip = ({ show, content, x, y }: typeof tooltip) => {
@@ -317,23 +321,5 @@ export function MoneyPriceInteractive({
317
321
  );
318
322
  };
319
323
 
320
- // 直接渲染按钮
321
- return (
322
- <>
323
- {data.plans.map((plan: any) => (
324
- <div key={plan.key} data-button-placeholder={plan.key}>
325
- <MoneyPriceButton
326
- planKey={plan.key}
327
- userContext={userContext}
328
- billingType={billingType}
329
- onLogin={handleLogin}
330
- onUpgrade={handleUpgrade}
331
- texts={data.buttonTexts}
332
- isProcessing={isProcessing}
333
- />
334
- </div>
335
- ))}
336
- <Tooltip {...tooltip} />
337
- </>
338
- );
324
+ return <Tooltip {...tooltip} />;
339
325
  }