@windrun-huaiin/third-ui 27.0.0 → 28.0.0

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 (58) hide show
  1. package/dist/fuma/base/custom-home-layout.d.ts +0 -5
  2. package/dist/fuma/base/docs-root-provider.d.ts +19 -0
  3. package/dist/fuma/base/docs-root-provider.js +17 -0
  4. package/dist/fuma/base/docs-root-provider.mjs +15 -0
  5. package/dist/fuma/base/index.d.ts +4 -0
  6. package/dist/fuma/base/index.js +12 -7
  7. package/dist/fuma/base/index.mjs +4 -1
  8. package/dist/fuma/base/site-docs-layout.d.ts +11 -0
  9. package/dist/fuma/base/site-docs-layout.js +15 -0
  10. package/dist/fuma/base/site-docs-layout.mjs +13 -0
  11. package/dist/fuma/base/site-home-layout.d.ts +24 -0
  12. package/dist/fuma/base/site-home-layout.js +16 -0
  13. package/dist/fuma/base/site-home-layout.mjs +14 -0
  14. package/dist/fuma/base/site-layout-shared.d.ts +89 -0
  15. package/dist/fuma/base/site-layout-shared.js +48 -0
  16. package/dist/fuma/base/site-layout-shared.mjs +42 -0
  17. package/dist/fuma/base/site-layout.d.ts +4 -120
  18. package/dist/fuma/fuma-page-genarator.js +5 -5
  19. package/dist/fuma/fuma-page-genarator.mjs +1 -1
  20. package/dist/fuma/server/llm-copy-handler.d.ts +2 -0
  21. package/dist/fuma/server/llm-copy-handler.js +7 -0
  22. package/dist/fuma/server/llm-copy-handler.mjs +1 -0
  23. package/dist/fuma/server/page-generator.d.ts +2 -0
  24. package/dist/fuma/server/page-generator.js +7 -0
  25. package/dist/fuma/server/page-generator.mjs +1 -0
  26. package/dist/lib/seo-metadata.js +3 -3
  27. package/dist/lib/seo-metadata.mjs +1 -1
  28. package/dist/lib/seo-util.js +4 -4
  29. package/dist/lib/seo-util.mjs +1 -1
  30. package/dist/main/credit/credit-nav-button.js +25 -1
  31. package/dist/main/credit/credit-nav-button.mjs +25 -1
  32. package/dist/main/footer.js +3 -3
  33. package/dist/main/footer.mjs +1 -1
  34. package/dist/main/money-price/money-price-button.js +2 -2
  35. package/dist/main/money-price/money-price-button.mjs +2 -2
  36. package/dist/main/money-price/money-price-interactive.d.ts +1 -1
  37. package/dist/main/money-price/money-price-interactive.js +14 -18
  38. package/dist/main/money-price/money-price-interactive.mjs +14 -18
  39. package/dist/main/money-price/money-price-types.d.ts +1 -0
  40. package/package.json +44 -4
  41. package/src/fuma/base/custom-header.tsx +1 -1
  42. package/src/fuma/base/custom-home-layout.tsx +0 -6
  43. package/src/fuma/base/docs-root-provider.tsx +58 -0
  44. package/src/fuma/base/index.ts +4 -0
  45. package/src/fuma/base/site-docs-layout.tsx +35 -0
  46. package/src/fuma/base/site-home-layout.tsx +78 -0
  47. package/src/fuma/base/site-layout-shared.tsx +190 -0
  48. package/src/fuma/base/site-layout.tsx +4 -295
  49. package/src/fuma/fuma-page-genarator.tsx +1 -1
  50. package/src/fuma/server/llm-copy-handler.ts +2 -0
  51. package/src/fuma/server/page-generator.ts +2 -0
  52. package/src/lib/seo-metadata.ts +1 -1
  53. package/src/lib/seo-util.ts +2 -2
  54. package/src/main/credit/credit-nav-button.tsx +36 -3
  55. package/src/main/footer.tsx +1 -2
  56. package/src/main/money-price/money-price-button.tsx +5 -3
  57. package/src/main/money-price/money-price-interactive.tsx +13 -15
  58. package/src/main/money-price/money-price-types.ts +1 -0
@@ -1,6 +1,6 @@
1
1
  import { __awaiter } from 'tslib';
2
2
  import { getTranslations } from 'next-intl/server';
3
- import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
3
+ import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib/utils';
4
4
 
5
5
  const DEFAULT_SITE_ICONS = [
6
6
  { rel: 'icon', type: 'image/png', sizes: '16x16', url: '/favicon-16x16.png' },
@@ -2,7 +2,7 @@
2
2
 
3
3
  var fs = require('fs');
4
4
  var path = require('path');
5
- var lib = require('@windrun-huaiin/lib');
5
+ var utils = require('@windrun-huaiin/lib/utils');
6
6
 
7
7
  /**
8
8
  * Generate robots.txt content
@@ -51,7 +51,7 @@ function generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = tru
51
51
  for (const locale of locales) {
52
52
  for (const f of blogFiles) {
53
53
  if (f === 'index.mdx') {
54
- const localizedPath = lib.getAsNeededLocalizedUrl(locale, '/blog', localePrefixAsNeeded, defaultLocale);
54
+ const localizedPath = utils.getAsNeededLocalizedUrl(locale, '/blog', localePrefixAsNeeded, defaultLocale);
55
55
  blogRoutes.push({
56
56
  url: `${baseUrl}${localizedPath}`,
57
57
  lastModified: new Date(),
@@ -61,7 +61,7 @@ function generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = tru
61
61
  }
62
62
  else {
63
63
  const slug = f.replace(/\.mdx$/, '');
64
- const localizedPath = lib.getAsNeededLocalizedUrl(locale, `/blog/${slug}`, localePrefixAsNeeded, defaultLocale);
64
+ const localizedPath = utils.getAsNeededLocalizedUrl(locale, `/blog/${slug}`, localePrefixAsNeeded, defaultLocale);
65
65
  blogRoutes.push({
66
66
  url: `${baseUrl}${localizedPath}`,
67
67
  lastModified: new Date(),
@@ -80,7 +80,7 @@ function generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = tru
80
80
  }
81
81
  // 3. main page (all language versions)
82
82
  const mainRoutes = locales.map(locale => {
83
- const localizedPath = lib.getAsNeededLocalizedUrl(locale, '/', localePrefixAsNeeded, defaultLocale);
83
+ const localizedPath = utils.getAsNeededLocalizedUrl(locale, '/', localePrefixAsNeeded, defaultLocale);
84
84
  return {
85
85
  url: `${baseUrl}${localizedPath}`,
86
86
  lastModified: new Date(),
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
3
+ import { getAsNeededLocalizedUrl } from '@windrun-huaiin/lib/utils';
4
4
 
5
5
  /**
6
6
  * Generate robots.txt content
@@ -4,9 +4,12 @@
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var utils = require('@windrun-huaiin/lib/utils');
6
6
  var icons = require('@windrun-huaiin/base-ui/icons');
7
+ var lib = require('@windrun-huaiin/base-ui/lib');
7
8
  var ui = require('@windrun-huaiin/base-ui/ui');
8
9
  var React = require('react');
9
10
  var moneyPriceInteractive = require('../money-price/money-price-interactive.js');
11
+ var moneyPriceConfigUtil = require('../money-price/money-price-config-util.js');
12
+ var dialogStyles = require('../alert-dialog/dialog-styles.js');
10
13
 
11
14
  function CreditNavButton({ locale, totalBalance, totalLabel, children, }) {
12
15
  const [open, setOpen] = React.useState(false);
@@ -106,7 +109,28 @@ function CreditNavButton({ locale, totalBalance, totalLabel, children, }) {
106
109
  closePricingModal,
107
110
  }), [closeMenu, isMobile, openPricingModal, closePricingModal]);
108
111
  const isOnetimeModal = pricingModal.mode === 'onetime';
109
- return (jsxRuntime.jsxs(CreditNavPopoverContext.Provider, { value: contextValue, children: [jsxRuntime.jsxs(ui.DropdownMenu, { modal: false, open: open, onOpenChange: setOpen, children: [jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: jsxRuntime.jsxs("button", { type: "button", "aria-label": `${formattedBalance} ${totalLabel}`, className: utils.cn('group relative mx-2 sm:mx-1 inline-flex items-center gap-2 overflow-hidden rounded-full border border-slate-200 bg-white pl-2 pr-4 py-1.5 text-sm font-semibold text-slate-700 shadow-sm transition-all duration-200 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100', 'hover:-translate-y-0.5 hover:scale-[1.02] hover:border-transparent hover:text-white hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-slate-400 dark:focus-visible:ring-slate-500'), ref: triggerRef, children: [jsxRuntime.jsx("span", { className: "pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-focus-visible:opacity-100 bg-linear-to-bl from-indigo-200/60 via-indigo-400/90 to-purple-200/50 dark:from-indigo-300/20 dark:via-slate-400 dark:to-slate-500/50", "aria-hidden": "true" }), jsxRuntime.jsx("span", { className: "relative z-10 flex h-6 w-6 items-center justify-center rounded-full bg-slate-100 text-slate-600 transition-transform duration-200 group-hover:scale-110 group-hover:bg-white/20 group-hover:text-white dark:bg-slate-800 dark:text-slate-200 dark:group-hover:bg-white/20 dark:group-hover:text-white", children: jsxRuntime.jsx(icons.GemIcon, { className: "h-3.5 w-3.5" }) }), jsxRuntime.jsxs("span", { className: "relative z-10 flex items-center", children: [jsxRuntime.jsx("span", { className: "text-base font-semibold leading-none", children: formattedBalance }), jsxRuntime.jsx("span", { className: "sr-only", children: ` ${totalLabel}` })] })] }) }), jsxRuntime.jsx(ui.DropdownMenuContent, { forceMount: true, sideOffset: 12, align: "end", className: "z-50 border-0 bg-transparent p-0 shadow-none mx-4 sm:mx-2 md:mx-1", children: jsxRuntime.jsx("div", { className: "w-[90vw] max-w-[90vw] max-h-[80vh] overflow-y-auto overflow-x-hidden rounded-3xl bg-transparent sm:w-[410px] sm:max-h-[90vh] sm:max-w-[95vw]", ref: contentRef, children: children }) })] }), pricingModal.modalMoneyPriceData && pricingModal.pricingContext ? (jsxRuntime.jsx(ui.AlertDialog, { open: pricingModal.open, onOpenChange: (open) => setPricingModal((prev) => (Object.assign(Object.assign({}, prev), { open }))), children: jsxRuntime.jsxs(ui.AlertDialogContent, { className: "mt-5 sm:mt-6 md:mt-10 lg:mt-15 w-[95vw] max-w-[1200px] overflow-hidden border border-slate-200 bg-white p-0 shadow-[0_32px_90px_rgba(15,23,42,0.25)] ring-1 ring-black/5 dark:border-white/12 dark:bg-[#0f1222] dark:shadow-[0_40px_120px_rgba(0,0,0,0.6)] dark:ring-white/10", children: [jsxRuntime.jsxs(ui.AlertDialogHeader, { className: "flex flex-row items-center justify-between border-b border-slate-200 px-6 pt-4 pb-1 dark:border-slate-800", children: [jsxRuntime.jsx(ui.AlertDialogTitle, { asChild: true, children: jsxRuntime.jsxs("div", { className: "flex flex-wrap items-baseline gap-3 text-slate-900 dark:text-white", children: [jsxRuntime.jsx("span", { className: "text-2xl font-semibold leading-tight", children: pricingModal.modalMoneyPriceData.title }), pricingModal.modalMoneyPriceData.subtitle ? (jsxRuntime.jsx("span", { className: "text-sm font-medium text-slate-500 dark:text-slate-300", children: pricingModal.modalMoneyPriceData.subtitle })) : null] }) }), jsxRuntime.jsx("button", { type: "button", className: "rounded-full p-2 text-gray-400 transition hover:bg-gray-400 hover:text-gray-400 dark:text-white/80 dark:hover:bg-white/80 dark:hover:text-white/80", onClick: closePricingModal, children: jsxRuntime.jsx(icons.XIcon, { className: "h-6 w-6" }) })] }), jsxRuntime.jsx("div", { className: "max-h-[60vh] sm:max-h-[80vh] overflow-y-auto px-4 pt-2 pb-6", children: jsxRuntime.jsx("div", { className: "mx-auto w-full", children: jsxRuntime.jsx(moneyPriceInteractive.MoneyPriceInteractive, { data: pricingModal.modalMoneyPriceData, config: pricingModal.pricingContext.moneyPriceConfig, checkoutApiEndpoint: pricingModal.pricingContext.checkoutApiEndpoint, customerPortalApiEndpoint: pricingModal.pricingContext.customerPortalApiEndpoint, enableSubscriptionUpgrade: pricingModal.pricingContext.enableSubscriptionUpgrade, initialBillingType: isOnetimeModal ? 'onetime' : undefined, disableAutoDetectBilling: isOnetimeModal, initUserContext: pricingModal.pricingContext.initUserContext }, pricingModal.mode) }) })] }) })) : null] }));
112
+ const modalInitialBillingType = React.useMemo(() => {
113
+ var _a, _b;
114
+ if (isOnetimeModal) {
115
+ return 'onetime';
116
+ }
117
+ const pricingContext = pricingModal.pricingContext;
118
+ const priceId = (_b = (_a = pricingContext === null || pricingContext === void 0 ? void 0 : pricingContext.initUserContext) === null || _a === void 0 ? void 0 : _a.xSubscription) === null || _b === void 0 ? void 0 : _b.priceId;
119
+ if (!pricingContext || !priceId) {
120
+ return undefined;
121
+ }
122
+ const providerConfig = moneyPriceConfigUtil.getActiveProviderConfigUtil(pricingContext.moneyPriceConfig);
123
+ const products = providerConfig.subscriptionProducts || providerConfig.products || {};
124
+ for (const product of Object.values(products)) {
125
+ for (const [billingType, plan] of Object.entries(product.plans)) {
126
+ if (plan.priceId === priceId) {
127
+ return billingType;
128
+ }
129
+ }
130
+ }
131
+ return undefined;
132
+ }, [isOnetimeModal, pricingModal.pricingContext]);
133
+ return (jsxRuntime.jsxs(CreditNavPopoverContext.Provider, { value: contextValue, children: [jsxRuntime.jsxs(ui.DropdownMenu, { modal: false, open: open, onOpenChange: setOpen, children: [jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: jsxRuntime.jsxs("button", { type: "button", "aria-label": `${formattedBalance} ${totalLabel}`, className: utils.cn('group relative mx-2 sm:mx-1 inline-flex items-center gap-2 overflow-hidden rounded-full border border-slate-200 bg-white pl-2 pr-4 py-1.5 text-sm font-semibold text-slate-700 shadow-sm transition-all duration-200 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100', 'hover:-translate-y-0.5 hover:scale-[1.02] hover:border-transparent hover:text-white hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-slate-400 dark:focus-visible:ring-slate-500'), ref: triggerRef, children: [jsxRuntime.jsx("span", { className: "pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-focus-visible:opacity-100 bg-linear-to-bl from-indigo-200/60 via-indigo-400/90 to-purple-200/50 dark:from-indigo-300/20 dark:via-slate-400 dark:to-slate-500/50", "aria-hidden": "true" }), jsxRuntime.jsx("span", { className: "relative z-10 flex h-6 w-6 items-center justify-center rounded-full bg-slate-100 text-slate-600 transition-transform duration-200 group-hover:scale-110 group-hover:bg-white/20 group-hover:text-white dark:bg-slate-800 dark:text-slate-200 dark:group-hover:bg-white/20 dark:group-hover:text-white", children: jsxRuntime.jsx(icons.GemIcon, { className: "h-3.5 w-3.5" }) }), jsxRuntime.jsxs("span", { className: "relative z-10 flex items-center", children: [jsxRuntime.jsx("span", { className: "text-base font-semibold leading-none", children: formattedBalance }), jsxRuntime.jsx("span", { className: "sr-only", children: ` ${totalLabel}` })] })] }) }), jsxRuntime.jsx(ui.DropdownMenuContent, { forceMount: true, sideOffset: 12, align: "end", className: "z-50 border-0 bg-transparent p-0 shadow-none mx-4 sm:mx-2 md:mx-1", children: jsxRuntime.jsx("div", { className: "w-[90vw] max-w-[90vw] max-h-[80vh] overflow-y-auto overflow-x-hidden rounded-3xl bg-transparent sm:w-[410px] sm:max-h-[90vh] sm:max-w-[95vw]", ref: contentRef, children: children }) })] }), pricingModal.modalMoneyPriceData && pricingModal.pricingContext ? (jsxRuntime.jsx(ui.AlertDialog, { open: pricingModal.open, onOpenChange: (open) => setPricingModal((prev) => (Object.assign(Object.assign({}, prev), { open }))), children: jsxRuntime.jsxs(ui.AlertDialogContent, { className: utils.cn('mt-5 sm:mt-6 md:mt-10 lg:mt-15 w-[95vw] max-w-[1200px] overflow-hidden border border-slate-200 p-0 shadow-[0_32px_90px_rgba(15,23,42,0.25)] ring-1 ring-black/5 dark:border-white/12 dark:shadow-[0_40px_120px_rgba(0,0,0,0.6)] dark:ring-white/10', lib.themeMainBgColor), overlayClassName: dialogStyles.dialogThemedOverlayClass, children: [jsxRuntime.jsxs(ui.AlertDialogHeader, { className: "flex flex-row items-center justify-between border-b border-slate-200 px-6 pt-4 pb-1 dark:border-slate-800", children: [jsxRuntime.jsx(ui.AlertDialogTitle, { asChild: true, children: jsxRuntime.jsxs("div", { className: "flex flex-wrap items-baseline gap-3 text-slate-900 dark:text-white", children: [jsxRuntime.jsx("span", { className: "text-2xl font-semibold leading-tight", children: pricingModal.modalMoneyPriceData.title }), pricingModal.modalMoneyPriceData.subtitle ? (jsxRuntime.jsx("span", { className: "text-sm font-medium text-slate-500 dark:text-slate-300", children: pricingModal.modalMoneyPriceData.subtitle })) : null] }) }), jsxRuntime.jsx("button", { type: "button", className: "rounded-full p-2 text-gray-400 transition hover:bg-gray-400 hover:text-gray-400 dark:text-white/80 dark:hover:bg-white/80 dark:hover:text-white/80", onClick: closePricingModal, children: jsxRuntime.jsx(icons.XIcon, { className: "h-6 w-6" }) })] }), jsxRuntime.jsx("div", { className: "max-h-[60vh] sm:max-h-[80vh] overflow-y-auto px-4 pt-2 pb-6", children: jsxRuntime.jsx("div", { className: "mx-auto w-full", children: jsxRuntime.jsx(moneyPriceInteractive.MoneyPriceInteractive, { data: pricingModal.modalMoneyPriceData, config: pricingModal.pricingContext.moneyPriceConfig, checkoutApiEndpoint: pricingModal.pricingContext.checkoutApiEndpoint, customerPortalApiEndpoint: pricingModal.pricingContext.customerPortalApiEndpoint, enableSubscriptionUpgrade: pricingModal.pricingContext.enableSubscriptionUpgrade, initialBillingType: modalInitialBillingType, disableAutoDetectBilling: isOnetimeModal, initUserContext: pricingModal.pricingContext.initUserContext }, pricingModal.mode) }) })] }) })) : null] }));
110
134
  }
111
135
  const CreditNavPopoverContext = React.createContext(null);
112
136
  function useCreditNavPopover() {
@@ -2,9 +2,12 @@
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import { cn } from '@windrun-huaiin/lib/utils';
4
4
  import { GemIcon, XIcon } from '@windrun-huaiin/base-ui/icons';
5
+ import { themeMainBgColor } from '@windrun-huaiin/base-ui/lib';
5
6
  import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle } from '@windrun-huaiin/base-ui/ui';
6
7
  import { createContext, useState, useRef, useCallback, useMemo, useEffect, useContext } from 'react';
7
8
  import { MoneyPriceInteractive } from '../money-price/money-price-interactive.mjs';
9
+ import { getActiveProviderConfigUtil } from '../money-price/money-price-config-util.mjs';
10
+ import { dialogThemedOverlayClass } from '../alert-dialog/dialog-styles.mjs';
8
11
 
9
12
  function CreditNavButton({ locale, totalBalance, totalLabel, children, }) {
10
13
  const [open, setOpen] = useState(false);
@@ -104,7 +107,28 @@ function CreditNavButton({ locale, totalBalance, totalLabel, children, }) {
104
107
  closePricingModal,
105
108
  }), [closeMenu, isMobile, openPricingModal, closePricingModal]);
106
109
  const isOnetimeModal = pricingModal.mode === 'onetime';
107
- return (jsxs(CreditNavPopoverContext.Provider, { value: contextValue, children: [jsxs(DropdownMenu, { modal: false, open: open, onOpenChange: setOpen, children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsxs("button", { type: "button", "aria-label": `${formattedBalance} ${totalLabel}`, className: cn('group relative mx-2 sm:mx-1 inline-flex items-center gap-2 overflow-hidden rounded-full border border-slate-200 bg-white pl-2 pr-4 py-1.5 text-sm font-semibold text-slate-700 shadow-sm transition-all duration-200 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100', 'hover:-translate-y-0.5 hover:scale-[1.02] hover:border-transparent hover:text-white hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-slate-400 dark:focus-visible:ring-slate-500'), ref: triggerRef, children: [jsx("span", { className: "pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-focus-visible:opacity-100 bg-linear-to-bl from-indigo-200/60 via-indigo-400/90 to-purple-200/50 dark:from-indigo-300/20 dark:via-slate-400 dark:to-slate-500/50", "aria-hidden": "true" }), jsx("span", { className: "relative z-10 flex h-6 w-6 items-center justify-center rounded-full bg-slate-100 text-slate-600 transition-transform duration-200 group-hover:scale-110 group-hover:bg-white/20 group-hover:text-white dark:bg-slate-800 dark:text-slate-200 dark:group-hover:bg-white/20 dark:group-hover:text-white", children: jsx(GemIcon, { className: "h-3.5 w-3.5" }) }), jsxs("span", { className: "relative z-10 flex items-center", children: [jsx("span", { className: "text-base font-semibold leading-none", children: formattedBalance }), jsx("span", { className: "sr-only", children: ` ${totalLabel}` })] })] }) }), jsx(DropdownMenuContent, { forceMount: true, sideOffset: 12, align: "end", className: "z-50 border-0 bg-transparent p-0 shadow-none mx-4 sm:mx-2 md:mx-1", children: jsx("div", { className: "w-[90vw] max-w-[90vw] max-h-[80vh] overflow-y-auto overflow-x-hidden rounded-3xl bg-transparent sm:w-[410px] sm:max-h-[90vh] sm:max-w-[95vw]", ref: contentRef, children: children }) })] }), pricingModal.modalMoneyPriceData && pricingModal.pricingContext ? (jsx(AlertDialog, { open: pricingModal.open, onOpenChange: (open) => setPricingModal((prev) => (Object.assign(Object.assign({}, prev), { open }))), children: jsxs(AlertDialogContent, { className: "mt-5 sm:mt-6 md:mt-10 lg:mt-15 w-[95vw] max-w-[1200px] overflow-hidden border border-slate-200 bg-white p-0 shadow-[0_32px_90px_rgba(15,23,42,0.25)] ring-1 ring-black/5 dark:border-white/12 dark:bg-[#0f1222] dark:shadow-[0_40px_120px_rgba(0,0,0,0.6)] dark:ring-white/10", children: [jsxs(AlertDialogHeader, { className: "flex flex-row items-center justify-between border-b border-slate-200 px-6 pt-4 pb-1 dark:border-slate-800", children: [jsx(AlertDialogTitle, { asChild: true, children: jsxs("div", { className: "flex flex-wrap items-baseline gap-3 text-slate-900 dark:text-white", children: [jsx("span", { className: "text-2xl font-semibold leading-tight", children: pricingModal.modalMoneyPriceData.title }), pricingModal.modalMoneyPriceData.subtitle ? (jsx("span", { className: "text-sm font-medium text-slate-500 dark:text-slate-300", children: pricingModal.modalMoneyPriceData.subtitle })) : null] }) }), jsx("button", { type: "button", className: "rounded-full p-2 text-gray-400 transition hover:bg-gray-400 hover:text-gray-400 dark:text-white/80 dark:hover:bg-white/80 dark:hover:text-white/80", onClick: closePricingModal, children: jsx(XIcon, { className: "h-6 w-6" }) })] }), jsx("div", { className: "max-h-[60vh] sm:max-h-[80vh] overflow-y-auto px-4 pt-2 pb-6", children: jsx("div", { className: "mx-auto w-full", children: jsx(MoneyPriceInteractive, { data: pricingModal.modalMoneyPriceData, config: pricingModal.pricingContext.moneyPriceConfig, checkoutApiEndpoint: pricingModal.pricingContext.checkoutApiEndpoint, customerPortalApiEndpoint: pricingModal.pricingContext.customerPortalApiEndpoint, enableSubscriptionUpgrade: pricingModal.pricingContext.enableSubscriptionUpgrade, initialBillingType: isOnetimeModal ? 'onetime' : undefined, disableAutoDetectBilling: isOnetimeModal, initUserContext: pricingModal.pricingContext.initUserContext }, pricingModal.mode) }) })] }) })) : null] }));
110
+ const modalInitialBillingType = useMemo(() => {
111
+ var _a, _b;
112
+ if (isOnetimeModal) {
113
+ return 'onetime';
114
+ }
115
+ const pricingContext = pricingModal.pricingContext;
116
+ const priceId = (_b = (_a = pricingContext === null || pricingContext === void 0 ? void 0 : pricingContext.initUserContext) === null || _a === void 0 ? void 0 : _a.xSubscription) === null || _b === void 0 ? void 0 : _b.priceId;
117
+ if (!pricingContext || !priceId) {
118
+ return undefined;
119
+ }
120
+ const providerConfig = getActiveProviderConfigUtil(pricingContext.moneyPriceConfig);
121
+ const products = providerConfig.subscriptionProducts || providerConfig.products || {};
122
+ for (const product of Object.values(products)) {
123
+ for (const [billingType, plan] of Object.entries(product.plans)) {
124
+ if (plan.priceId === priceId) {
125
+ return billingType;
126
+ }
127
+ }
128
+ }
129
+ return undefined;
130
+ }, [isOnetimeModal, pricingModal.pricingContext]);
131
+ return (jsxs(CreditNavPopoverContext.Provider, { value: contextValue, children: [jsxs(DropdownMenu, { modal: false, open: open, onOpenChange: setOpen, children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsxs("button", { type: "button", "aria-label": `${formattedBalance} ${totalLabel}`, className: cn('group relative mx-2 sm:mx-1 inline-flex items-center gap-2 overflow-hidden rounded-full border border-slate-200 bg-white pl-2 pr-4 py-1.5 text-sm font-semibold text-slate-700 shadow-sm transition-all duration-200 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100', 'hover:-translate-y-0.5 hover:scale-[1.02] hover:border-transparent hover:text-white hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-slate-400 dark:focus-visible:ring-slate-500'), ref: triggerRef, children: [jsx("span", { className: "pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-200 group-hover:opacity-100 group-focus-visible:opacity-100 bg-linear-to-bl from-indigo-200/60 via-indigo-400/90 to-purple-200/50 dark:from-indigo-300/20 dark:via-slate-400 dark:to-slate-500/50", "aria-hidden": "true" }), jsx("span", { className: "relative z-10 flex h-6 w-6 items-center justify-center rounded-full bg-slate-100 text-slate-600 transition-transform duration-200 group-hover:scale-110 group-hover:bg-white/20 group-hover:text-white dark:bg-slate-800 dark:text-slate-200 dark:group-hover:bg-white/20 dark:group-hover:text-white", children: jsx(GemIcon, { className: "h-3.5 w-3.5" }) }), jsxs("span", { className: "relative z-10 flex items-center", children: [jsx("span", { className: "text-base font-semibold leading-none", children: formattedBalance }), jsx("span", { className: "sr-only", children: ` ${totalLabel}` })] })] }) }), jsx(DropdownMenuContent, { forceMount: true, sideOffset: 12, align: "end", className: "z-50 border-0 bg-transparent p-0 shadow-none mx-4 sm:mx-2 md:mx-1", children: jsx("div", { className: "w-[90vw] max-w-[90vw] max-h-[80vh] overflow-y-auto overflow-x-hidden rounded-3xl bg-transparent sm:w-[410px] sm:max-h-[90vh] sm:max-w-[95vw]", ref: contentRef, children: children }) })] }), pricingModal.modalMoneyPriceData && pricingModal.pricingContext ? (jsx(AlertDialog, { open: pricingModal.open, onOpenChange: (open) => setPricingModal((prev) => (Object.assign(Object.assign({}, prev), { open }))), children: jsxs(AlertDialogContent, { className: cn('mt-5 sm:mt-6 md:mt-10 lg:mt-15 w-[95vw] max-w-[1200px] overflow-hidden border border-slate-200 p-0 shadow-[0_32px_90px_rgba(15,23,42,0.25)] ring-1 ring-black/5 dark:border-white/12 dark:shadow-[0_40px_120px_rgba(0,0,0,0.6)] dark:ring-white/10', themeMainBgColor), overlayClassName: dialogThemedOverlayClass, children: [jsxs(AlertDialogHeader, { className: "flex flex-row items-center justify-between border-b border-slate-200 px-6 pt-4 pb-1 dark:border-slate-800", children: [jsx(AlertDialogTitle, { asChild: true, children: jsxs("div", { className: "flex flex-wrap items-baseline gap-3 text-slate-900 dark:text-white", children: [jsx("span", { className: "text-2xl font-semibold leading-tight", children: pricingModal.modalMoneyPriceData.title }), pricingModal.modalMoneyPriceData.subtitle ? (jsx("span", { className: "text-sm font-medium text-slate-500 dark:text-slate-300", children: pricingModal.modalMoneyPriceData.subtitle })) : null] }) }), jsx("button", { type: "button", className: "rounded-full p-2 text-gray-400 transition hover:bg-gray-400 hover:text-gray-400 dark:text-white/80 dark:hover:bg-white/80 dark:hover:text-white/80", onClick: closePricingModal, children: jsx(XIcon, { className: "h-6 w-6" }) })] }), jsx("div", { className: "max-h-[60vh] sm:max-h-[80vh] overflow-y-auto px-4 pt-2 pb-6", children: jsx("div", { className: "mx-auto w-full", children: jsx(MoneyPriceInteractive, { data: pricingModal.modalMoneyPriceData, config: pricingModal.pricingContext.moneyPriceConfig, checkoutApiEndpoint: pricingModal.pricingContext.checkoutApiEndpoint, customerPortalApiEndpoint: pricingModal.pricingContext.customerPortalApiEndpoint, enableSubscriptionUpgrade: pricingModal.pricingContext.enableSubscriptionUpgrade, initialBillingType: modalInitialBillingType, disableAutoDetectBilling: isOnetimeModal, initUserContext: pricingModal.pricingContext.initUserContext }, pricingModal.mode) }) })] }) })) : null] }));
108
132
  }
109
133
  const CreditNavPopoverContext = createContext(null);
110
134
  function useCreditNavPopover() {
@@ -7,8 +7,8 @@ var icons = require('@windrun-huaiin/base-ui/icons');
7
7
  var Link = require('next/link');
8
8
  var footerEmail = require('./footer-email.js');
9
9
  var tIntl = require('../lib/t-intl.js');
10
- var lib = require('@windrun-huaiin/lib');
11
- var lib$1 = require('@windrun-huaiin/base-ui/lib');
10
+ var utils = require('@windrun-huaiin/lib/utils');
11
+ var lib = require('@windrun-huaiin/base-ui/lib');
12
12
 
13
13
  function Footer(_a) {
14
14
  return tslib.__awaiter(this, arguments, void 0, function* ({ locale, localePrefixAsNeeded = true, defaultLocale = 'en' }) {
@@ -23,7 +23,7 @@ function Footer(_a) {
23
23
  clickToCopyText: tIntl.safeT(tFooter, 'clickToCopy', 'Click to copy'),
24
24
  copiedText: tIntl.safeT(tFooter, 'copied', 'Copied!'),
25
25
  };
26
- return (jsxRuntime.jsxs("div", { className: "mb-10 w-full mx-auto", children: [jsxRuntime.jsx("div", { className: lib.cn("w-full border-current border-t", lib$1.themeIconColor) }), jsxRuntime.jsx("footer", { children: jsxRuntime.jsxs("div", { className: "w-full flex flex-col items-center justify-center px-4 py-8 space-y-3", children: [jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-x-2 gap-y-2 text-xs sm:text-sm sm:gap-x-6", children: [jsxRuntime.jsxs(Link, { href: lib.getAsNeededLocalizedUrl(locale, "/legal/terms", localePrefixAsNeeded, defaultLocale), className: "flex items-center space-x-1 hover:underline", children: [jsxRuntime.jsx(icons.ReceiptTextIcon, { className: "h-3.5 w-3.5" }), jsxRuntime.jsx("span", { children: data.terms })] }), jsxRuntime.jsxs(Link, { href: lib.getAsNeededLocalizedUrl(locale, "/legal/privacy", localePrefixAsNeeded, defaultLocale), className: "flex items-center space-x-1 hover:underline", children: [jsxRuntime.jsx(icons.ShieldUserIcon, { className: "h-3.5 w-3.5" }), jsxRuntime.jsx("span", { children: data.privacy })] }), jsxRuntime.jsxs(footerEmail.FooterEmail, { email: data.email, clickToCopyText: data.clickToCopyText, copiedText: data.copiedText, children: [jsxRuntime.jsx(icons.MailIcon, { className: "h-3.5 w-3.5" }), jsxRuntime.jsx("span", { children: data.contactUs })] })] }), jsxRuntime.jsx("div", { className: "text-xs sm:text-sm text-center", children: jsxRuntime.jsx("span", { children: data.copyright }) })] }) })] }));
26
+ return (jsxRuntime.jsxs("div", { className: "mb-10 w-full mx-auto", children: [jsxRuntime.jsx("div", { className: utils.cn("w-full border-current border-t", lib.themeIconColor) }), jsxRuntime.jsx("footer", { children: jsxRuntime.jsxs("div", { className: "w-full flex flex-col items-center justify-center px-4 py-8 space-y-3", children: [jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-center gap-x-2 gap-y-2 text-xs sm:text-sm sm:gap-x-6", children: [jsxRuntime.jsxs(Link, { href: utils.getAsNeededLocalizedUrl(locale, "/legal/terms", localePrefixAsNeeded, defaultLocale), className: "flex items-center space-x-1 hover:underline", children: [jsxRuntime.jsx(icons.ReceiptTextIcon, { className: "h-3.5 w-3.5" }), jsxRuntime.jsx("span", { children: data.terms })] }), jsxRuntime.jsxs(Link, { href: utils.getAsNeededLocalizedUrl(locale, "/legal/privacy", localePrefixAsNeeded, defaultLocale), className: "flex items-center space-x-1 hover:underline", children: [jsxRuntime.jsx(icons.ShieldUserIcon, { className: "h-3.5 w-3.5" }), jsxRuntime.jsx("span", { children: data.privacy })] }), jsxRuntime.jsxs(footerEmail.FooterEmail, { email: data.email, clickToCopyText: data.clickToCopyText, copiedText: data.copiedText, children: [jsxRuntime.jsx(icons.MailIcon, { className: "h-3.5 w-3.5" }), jsxRuntime.jsx("span", { children: data.contactUs })] })] }), jsxRuntime.jsx("div", { className: "text-xs sm:text-sm text-center", children: jsxRuntime.jsx("span", { children: data.copyright }) })] }) })] }));
27
27
  });
28
28
  }
29
29
 
@@ -5,7 +5,7 @@ import { ReceiptTextIcon, ShieldUserIcon, MailIcon } from '@windrun-huaiin/base-
5
5
  import Link from 'next/link';
6
6
  import { FooterEmail } from './footer-email.mjs';
7
7
  import { safeT } from '../lib/t-intl.mjs';
8
- import { cn, getAsNeededLocalizedUrl } from '@windrun-huaiin/lib';
8
+ import { cn, getAsNeededLocalizedUrl } from '@windrun-huaiin/lib/utils';
9
9
  import { themeIconColor } from '@windrun-huaiin/base-ui/lib';
10
10
 
11
11
  function Footer(_a) {
@@ -9,11 +9,11 @@ var moneyPriceTypes = require('./money-price-types.js');
9
9
  var React = require('react');
10
10
 
11
11
  function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction, texts, isProcessing = false, isAnyProcessing = false, isInitLoading = false, enableSubscriptionUpgrade = true }) {
12
+ const [isLoading, setIsLoading] = React.useState(false);
12
13
  if (isInitLoading) {
13
- return (jsxRuntime.jsx("div", { className: "w-full h-11 md:h-12 mt-4 md:mt-auto rounded-full bg-transparent", "aria-hidden": "true", "data-plan-button-placeholder": planKey }));
14
+ return (jsxRuntime.jsx("div", { className: "relative w-full h-11 md:h-12 mt-4 md:mt-auto overflow-hidden rounded-full bg-gray-100/70 dark:bg-gray-800/40 animate-pulse transition-opacity duration-300 ease-out", "aria-hidden": "true", "data-plan-button-placeholder": planKey, children: jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-r from-transparent via-white/50 to-transparent dark:via-white/10" }) }));
14
15
  }
15
16
  const { isAuthenticated, subscriptionStatus } = userContext;
16
- const [isLoading, setIsLoading] = React.useState(false);
17
17
  const subscriptionBilling = userContext.subscriptionType;
18
18
  const planTier = planKey;
19
19
  const planBilling = billingType;
@@ -7,11 +7,11 @@ import { UserState } from './money-price-types.mjs';
7
7
  import { useState } from 'react';
8
8
 
9
9
  function MoneyPriceButton({ planKey, userContext, billingType, onAuth, onAction, texts, isProcessing = false, isAnyProcessing = false, isInitLoading = false, enableSubscriptionUpgrade = true }) {
10
+ const [isLoading, setIsLoading] = useState(false);
10
11
  if (isInitLoading) {
11
- return (jsx("div", { className: "w-full h-11 md:h-12 mt-4 md:mt-auto rounded-full bg-transparent", "aria-hidden": "true", "data-plan-button-placeholder": planKey }));
12
+ return (jsx("div", { className: "relative w-full h-11 md:h-12 mt-4 md:mt-auto overflow-hidden rounded-full bg-gray-100/70 dark:bg-gray-800/40 animate-pulse transition-opacity duration-300 ease-out", "aria-hidden": "true", "data-plan-button-placeholder": planKey, children: jsx("div", { className: "absolute inset-0 bg-gradient-to-r from-transparent via-white/50 to-transparent dark:via-white/10" }) }));
12
13
  }
13
14
  const { isAuthenticated, subscriptionStatus } = userContext;
14
- const [isLoading, setIsLoading] = useState(false);
15
15
  const subscriptionBilling = userContext.subscriptionType;
16
16
  const planTier = planKey;
17
17
  const planBilling = billingType;
@@ -1,2 +1,2 @@
1
1
  import { type MoneyPriceInteractiveProps } from './money-price-types';
2
- export declare function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPortalApiEndpoint, enableClerkModal, enabledBillingTypes, enableSubscriptionUpgrade, initialBillingType, disableAutoDetectBilling, initUserContext, }: MoneyPriceInteractiveProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPortalApiEndpoint, enableClerkModal, enabledBillingTypes, enableSubscriptionUpgrade, initialBillingType, disableAutoDetectBilling, initUserContext, isInitLoading, }: MoneyPriceInteractiveProps): import("react/jsx-runtime").JSX.Element;
@@ -14,8 +14,8 @@ var customerPortal = require('./customer-portal.js');
14
14
  var lib = require('@windrun-huaiin/base-ui/lib');
15
15
 
16
16
  const PLAN_KEYS = ['F1', 'P2', 'U3'];
17
- function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPortalApiEndpoint, enableClerkModal = false, enabledBillingTypes, enableSubscriptionUpgrade = true, initialBillingType, disableAutoDetectBilling = false, initUserContext, }) {
18
- var _a, _b, _c, _d;
17
+ function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPortalApiEndpoint, enableClerkModal = false, enabledBillingTypes, enableSubscriptionUpgrade = true, initialBillingType, disableAutoDetectBilling = false, initUserContext, isInitLoading = false, }) {
18
+ var _a, _b, _c, _d, _e, _f;
19
19
  const { redirectToSignIn, redirectToSignUp, user: clerkUser, openSignUp } = nextjs.useClerk();
20
20
  const router = navigation.useRouter();
21
21
  const providerConfig = React.useMemo(() => moneyPriceConfigUtil.getActiveProviderConfigUtil(config), [config]);
@@ -103,20 +103,16 @@ function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPort
103
103
  subscriptionSnapshot === null || subscriptionSnapshot === void 0 ? void 0 : subscriptionSnapshot.priceId,
104
104
  priceIdsByCycle,
105
105
  ]);
106
- const initialBillingCandidate = React.useMemo(() => {
107
- if (initialBillingType) {
108
- return resolvedInitialBilling;
109
- }
110
- if (detectedBillingType) {
111
- return detectedBillingType;
106
+ const explicitInitialBilling = React.useMemo(() => {
107
+ if (initialBillingType &&
108
+ billingOptions.some(option => option.key === initialBillingType)) {
109
+ return initialBillingType;
112
110
  }
113
- return resolvedInitialBilling;
114
- }, [initialBillingType, resolvedInitialBilling, detectedBillingType]);
115
- const [billingType, setBillingType] = React.useState(initialBillingCandidate);
111
+ return null;
112
+ }, [initialBillingType, billingOptions]);
113
+ const [userSelectedBillingType, setUserSelectedBillingType] = React.useState(null);
114
+ const billingType = (_c = (_b = userSelectedBillingType !== null && userSelectedBillingType !== void 0 ? userSelectedBillingType : explicitInitialBilling) !== null && _b !== void 0 ? _b : detectedBillingType) !== null && _c !== void 0 ? _c : resolvedInitialBilling;
116
115
  const navigationLockRef = React.useRef(false);
117
- React.useEffect(() => {
118
- setBillingType(prev => (prev === initialBillingCandidate ? prev : initialBillingCandidate));
119
- }, [initialBillingCandidate]);
120
116
  const [processingTarget, setProcessingTarget] = React.useState(null);
121
117
  const [isTouchDevice, setIsTouchDevice] = React.useState(false);
122
118
  React.useEffect(() => {
@@ -156,8 +152,8 @@ function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPort
156
152
  detectedBillingType,
157
153
  subscriptionSnapshot === null || subscriptionSnapshot === void 0 ? void 0 : subscriptionSnapshot.subPeriodEnd
158
154
  ]);
159
- const fingerprintId = (_b = initUserContext === null || initUserContext === void 0 ? void 0 : initUserContext.fingerprintId) !== null && _b !== void 0 ? _b : null;
160
- const initUserId = (_d = (_c = initUserContext === null || initUserContext === void 0 ? void 0 : initUserContext.xUser) === null || _c === void 0 ? void 0 : _c.userId) !== null && _d !== void 0 ? _d : null;
155
+ const fingerprintId = (_d = initUserContext === null || initUserContext === void 0 ? void 0 : initUserContext.fingerprintId) !== null && _d !== void 0 ? _d : null;
156
+ const initUserId = (_f = (_e = initUserContext === null || initUserContext === void 0 ? void 0 : initUserContext.xUser) === null || _e === void 0 ? void 0 : _e.userId) !== null && _f !== void 0 ? _f : null;
161
157
  const handleAuth = React.useCallback(() => {
162
158
  if (!enableClerkModal) {
163
159
  redirectToSignUp();
@@ -317,7 +313,7 @@ function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPort
317
313
  ? utils.cn('text-white rounded-full shadow-sm', lib.themeButtonGradientClass, lib.themeButtonGradientHoverClass)
318
314
  : 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full';
319
315
  const showBadge = option.key === billingType && !!discountBadgeText;
320
- return (jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center mx-1", children: [showBadge && (jsxRuntime.jsx("span", { className: "absolute z-10 left-1/2 -translate-x-1/2 -top-3 sm:-top-4 translate-y-[-50%] px-3 py-0.5 text-[0.625rem] sm:text-xs rounded-md bg-yellow-100 text-yellow-800 font-semibold shadow-sm whitespace-nowrap", children: discountBadgeText })), jsxRuntime.jsx("button", { className: utils.cn('text-sm md:text-base font-medium transition relative text-center z-10 px-2 sm:px-4 py-2 min-w-[100px] sm:min-w-[120px]', buttonClasses), type: "button", "data-billing-button": option.key, onClick: () => setBillingType(option.key), children: option.name })] }, option.key));
316
+ return (jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center mx-1", children: [showBadge && (jsxRuntime.jsx("span", { className: "absolute z-10 left-1/2 -translate-x-1/2 -top-3 sm:-top-4 translate-y-[-50%] px-3 py-0.5 text-[0.625rem] sm:text-xs rounded-md bg-yellow-100 text-yellow-800 font-semibold shadow-sm whitespace-nowrap", children: discountBadgeText })), jsxRuntime.jsx("button", { className: utils.cn('text-sm md:text-base font-medium transition relative text-center z-10 px-2 sm:px-4 py-2 min-w-[100px] sm:min-w-[120px]', buttonClasses), type: "button", "data-billing-button": option.key, onClick: () => setUserSelectedBillingType(option.key), children: option.name })] }, option.key));
321
317
  }) }) }), jsxRuntime.jsx("div", { className: "w-full", children: jsxRuntime.jsx("div", { className: "flex flex-wrap justify-center gap-5 md:gap-6 xl:gap-8 w-full max-w-6xl mx-auto", children: currentPlans.map((plan) => {
322
318
  const planKey = plan.key;
323
319
  if (!PLAN_KEYS.includes(planKey)) {
@@ -333,7 +329,7 @@ function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPort
333
329
  jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(selectedBillingOption === null || selectedBillingOption === void 0 ? void 0 : selectedBillingOption.subTitle) && (jsxRuntime.jsx("span", { className: "text-[11px] md:text-xs text-gray-700 dark:text-gray-300 font-medium", children: selectedBillingOption.subTitle })), plan.subtitle && (jsxRuntime.jsxs("span", { className: "px-2 py-0.5 text-[11px] md:text-xs rounded bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200 font-semibold align-middle", children: ["+", plan.subtitle] }))] })) : (
334
330
  // 其他模式下保持原逻辑
335
331
  showBillingSubtitle && (jsxRuntime.jsx("span", { className: "text-[11px] md:text-xs text-gray-700 dark:text-gray-300 font-medium", children: (selectedBillingOption === null || selectedBillingOption === void 0 ? void 0 : selectedBillingOption.subTitle) || '' }))) })] })] }), jsxRuntime.jsx("ul", { className: "flex-1 mb-6 mt-4 text-xs md:text-sm leading-5", children: getFeatureRows(plan).map((feature, i) => (jsxRuntime.jsxs("li", { className: "flex items-start gap-2 mb-2 min-h-[24px] md:min-h-[28px]", "data-feature-item": `${planKey}-${i}`, children: [feature ? (jsxRuntime.jsx("span", { className: "inline-flex items-center justify-center w-5 h-5 rounded-full bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-200 mr-1", children: feature.icon ? jsxRuntime.jsx("span", { children: feature.icon }) : jsxRuntime.jsx("span", { className: "font-bold", children: "\u2713" }) })) : (jsxRuntime.jsx("span", { className: "inline-flex items-center justify-center w-5 h-5 rounded-full mr-1", children: "\u00A0" })), feature && feature.tag && (jsxRuntime.jsx("span", { className: "px-1 py-0.5 text-[6px] rounded bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 font-semibold align-middle", children: feature.tag })), feature ? (jsxRuntime.jsxs("div", { className: "flex-1 text-gray-800 dark:text-gray-200", children: [jsxRuntime.jsx("span", { children: feature.description }), feature.tooltip && (jsxRuntime.jsx("span", { className: "block text-[11px] text-gray-500 dark:text-gray-400 mt-1", children: feature.tooltip }))] })) : (jsxRuntime.jsx("span", { children: "\u00A0" }))] }, i))) }), jsxRuntime.jsx("div", { className: "flex-1" }), jsxRuntime.jsx(moneyPriceButton.MoneyPriceButton, { planKey: planKey, userContext: userContext, billingType: billingType, onAuth: handleAuth, onAction: handleAction, texts: data.buttonTexts, isProcessing: (processingTarget === null || processingTarget === void 0 ? void 0 : processingTarget.plan) === planKey &&
336
- (processingTarget === null || processingTarget === void 0 ? void 0 : processingTarget.billing) === billingType, isAnyProcessing: !!processingTarget, isInitLoading: false, enableSubscriptionUpgrade: enableSubscriptionUpgrade })] }, plan.key));
332
+ (processingTarget === null || processingTarget === void 0 ? void 0 : processingTarget.billing) === billingType, isAnyProcessing: !!processingTarget, isInitLoading: isInitLoading, enableSubscriptionUpgrade: enableSubscriptionUpgrade })] }, plan.key));
337
333
  }) }) })] }));
338
334
  }
339
335
 
@@ -12,8 +12,8 @@ import { redirectToCustomerPortal } from './customer-portal.mjs';
12
12
  import { themeButtonGradientClass, themeButtonGradientHoverClass, themeIconColor } from '@windrun-huaiin/base-ui/lib';
13
13
 
14
14
  const PLAN_KEYS = ['F1', 'P2', 'U3'];
15
- function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPortalApiEndpoint, enableClerkModal = false, enabledBillingTypes, enableSubscriptionUpgrade = true, initialBillingType, disableAutoDetectBilling = false, initUserContext, }) {
16
- var _a, _b, _c, _d;
15
+ function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPortalApiEndpoint, enableClerkModal = false, enabledBillingTypes, enableSubscriptionUpgrade = true, initialBillingType, disableAutoDetectBilling = false, initUserContext, isInitLoading = false, }) {
16
+ var _a, _b, _c, _d, _e, _f;
17
17
  const { redirectToSignIn, redirectToSignUp, user: clerkUser, openSignUp } = useClerk();
18
18
  const router = useRouter();
19
19
  const providerConfig = useMemo(() => getActiveProviderConfigUtil(config), [config]);
@@ -101,20 +101,16 @@ function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPort
101
101
  subscriptionSnapshot === null || subscriptionSnapshot === void 0 ? void 0 : subscriptionSnapshot.priceId,
102
102
  priceIdsByCycle,
103
103
  ]);
104
- const initialBillingCandidate = useMemo(() => {
105
- if (initialBillingType) {
106
- return resolvedInitialBilling;
107
- }
108
- if (detectedBillingType) {
109
- return detectedBillingType;
104
+ const explicitInitialBilling = useMemo(() => {
105
+ if (initialBillingType &&
106
+ billingOptions.some(option => option.key === initialBillingType)) {
107
+ return initialBillingType;
110
108
  }
111
- return resolvedInitialBilling;
112
- }, [initialBillingType, resolvedInitialBilling, detectedBillingType]);
113
- const [billingType, setBillingType] = useState(initialBillingCandidate);
109
+ return null;
110
+ }, [initialBillingType, billingOptions]);
111
+ const [userSelectedBillingType, setUserSelectedBillingType] = useState(null);
112
+ const billingType = (_c = (_b = userSelectedBillingType !== null && userSelectedBillingType !== void 0 ? userSelectedBillingType : explicitInitialBilling) !== null && _b !== void 0 ? _b : detectedBillingType) !== null && _c !== void 0 ? _c : resolvedInitialBilling;
114
113
  const navigationLockRef = useRef(false);
115
- useEffect(() => {
116
- setBillingType(prev => (prev === initialBillingCandidate ? prev : initialBillingCandidate));
117
- }, [initialBillingCandidate]);
118
114
  const [processingTarget, setProcessingTarget] = useState(null);
119
115
  const [isTouchDevice, setIsTouchDevice] = useState(false);
120
116
  useEffect(() => {
@@ -154,8 +150,8 @@ function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPort
154
150
  detectedBillingType,
155
151
  subscriptionSnapshot === null || subscriptionSnapshot === void 0 ? void 0 : subscriptionSnapshot.subPeriodEnd
156
152
  ]);
157
- const fingerprintId = (_b = initUserContext === null || initUserContext === void 0 ? void 0 : initUserContext.fingerprintId) !== null && _b !== void 0 ? _b : null;
158
- const initUserId = (_d = (_c = initUserContext === null || initUserContext === void 0 ? void 0 : initUserContext.xUser) === null || _c === void 0 ? void 0 : _c.userId) !== null && _d !== void 0 ? _d : null;
153
+ const fingerprintId = (_d = initUserContext === null || initUserContext === void 0 ? void 0 : initUserContext.fingerprintId) !== null && _d !== void 0 ? _d : null;
154
+ const initUserId = (_f = (_e = initUserContext === null || initUserContext === void 0 ? void 0 : initUserContext.xUser) === null || _e === void 0 ? void 0 : _e.userId) !== null && _f !== void 0 ? _f : null;
159
155
  const handleAuth = useCallback(() => {
160
156
  if (!enableClerkModal) {
161
157
  redirectToSignUp();
@@ -315,7 +311,7 @@ function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPort
315
311
  ? cn('text-white rounded-full shadow-sm', themeButtonGradientClass, themeButtonGradientHoverClass)
316
312
  : 'text-gray-800 dark:text-gray-200 hover:text-gray-900 dark:hover:text-gray-100 rounded-full';
317
313
  const showBadge = option.key === billingType && !!discountBadgeText;
318
- return (jsxs("div", { className: "relative flex items-center justify-center mx-1", children: [showBadge && (jsx("span", { className: "absolute z-10 left-1/2 -translate-x-1/2 -top-3 sm:-top-4 translate-y-[-50%] px-3 py-0.5 text-[0.625rem] sm:text-xs rounded-md bg-yellow-100 text-yellow-800 font-semibold shadow-sm whitespace-nowrap", children: discountBadgeText })), jsx("button", { className: cn('text-sm md:text-base font-medium transition relative text-center z-10 px-2 sm:px-4 py-2 min-w-[100px] sm:min-w-[120px]', buttonClasses), type: "button", "data-billing-button": option.key, onClick: () => setBillingType(option.key), children: option.name })] }, option.key));
314
+ return (jsxs("div", { className: "relative flex items-center justify-center mx-1", children: [showBadge && (jsx("span", { className: "absolute z-10 left-1/2 -translate-x-1/2 -top-3 sm:-top-4 translate-y-[-50%] px-3 py-0.5 text-[0.625rem] sm:text-xs rounded-md bg-yellow-100 text-yellow-800 font-semibold shadow-sm whitespace-nowrap", children: discountBadgeText })), jsx("button", { className: cn('text-sm md:text-base font-medium transition relative text-center z-10 px-2 sm:px-4 py-2 min-w-[100px] sm:min-w-[120px]', buttonClasses), type: "button", "data-billing-button": option.key, onClick: () => setUserSelectedBillingType(option.key), children: option.name })] }, option.key));
319
315
  }) }) }), jsx("div", { className: "w-full", children: jsx("div", { className: "flex flex-wrap justify-center gap-5 md:gap-6 xl:gap-8 w-full max-w-6xl mx-auto", children: currentPlans.map((plan) => {
320
316
  const planKey = plan.key;
321
317
  if (!PLAN_KEYS.includes(planKey)) {
@@ -331,7 +327,7 @@ function MoneyPriceInteractive({ data, config, checkoutApiEndpoint, customerPort
331
327
  jsxs(Fragment, { children: [(selectedBillingOption === null || selectedBillingOption === void 0 ? void 0 : selectedBillingOption.subTitle) && (jsx("span", { className: "text-[11px] md:text-xs text-gray-700 dark:text-gray-300 font-medium", children: selectedBillingOption.subTitle })), plan.subtitle && (jsxs("span", { className: "px-2 py-0.5 text-[11px] md:text-xs rounded bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200 font-semibold align-middle", children: ["+", plan.subtitle] }))] })) : (
332
328
  // 其他模式下保持原逻辑
333
329
  showBillingSubtitle && (jsx("span", { className: "text-[11px] md:text-xs text-gray-700 dark:text-gray-300 font-medium", children: (selectedBillingOption === null || selectedBillingOption === void 0 ? void 0 : selectedBillingOption.subTitle) || '' }))) })] })] }), jsx("ul", { className: "flex-1 mb-6 mt-4 text-xs md:text-sm leading-5", children: getFeatureRows(plan).map((feature, i) => (jsxs("li", { className: "flex items-start gap-2 mb-2 min-h-[24px] md:min-h-[28px]", "data-feature-item": `${planKey}-${i}`, children: [feature ? (jsx("span", { className: "inline-flex items-center justify-center w-5 h-5 rounded-full bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-200 mr-1", children: feature.icon ? jsx("span", { children: feature.icon }) : jsx("span", { className: "font-bold", children: "\u2713" }) })) : (jsx("span", { className: "inline-flex items-center justify-center w-5 h-5 rounded-full mr-1", children: "\u00A0" })), feature && feature.tag && (jsx("span", { className: "px-1 py-0.5 text-[6px] rounded bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 font-semibold align-middle", children: feature.tag })), feature ? (jsxs("div", { className: "flex-1 text-gray-800 dark:text-gray-200", children: [jsx("span", { children: feature.description }), feature.tooltip && (jsx("span", { className: "block text-[11px] text-gray-500 dark:text-gray-400 mt-1", children: feature.tooltip }))] })) : (jsx("span", { children: "\u00A0" }))] }, i))) }), jsx("div", { className: "flex-1" }), jsx(MoneyPriceButton, { planKey: planKey, userContext: userContext, billingType: billingType, onAuth: handleAuth, onAction: handleAction, texts: data.buttonTexts, isProcessing: (processingTarget === null || processingTarget === void 0 ? void 0 : processingTarget.plan) === planKey &&
334
- (processingTarget === null || processingTarget === void 0 ? void 0 : processingTarget.billing) === billingType, isAnyProcessing: !!processingTarget, isInitLoading: false, enableSubscriptionUpgrade: enableSubscriptionUpgrade })] }, plan.key));
330
+ (processingTarget === null || processingTarget === void 0 ? void 0 : processingTarget.billing) === billingType, isAnyProcessing: !!processingTarget, isInitLoading: isInitLoading, enableSubscriptionUpgrade: enableSubscriptionUpgrade })] }, plan.key));
335
331
  }) }) })] }));
336
332
  }
337
333
 
@@ -96,6 +96,7 @@ export interface MoneyPriceInteractiveProps {
96
96
  initialBillingType?: string;
97
97
  disableAutoDetectBilling?: boolean;
98
98
  initUserContext?: InitUserContext;
99
+ isInitLoading?: boolean;
99
100
  }
100
101
  export interface MoneyPriceButtonProps {
101
102
  planKey: 'F1' | 'P2' | 'U3';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/third-ui",
3
- "version": "27.0.0",
3
+ "version": "28.0.0",
4
4
  "description": "Third-party integrated UI components for windrun-huaiin projects",
5
5
  "exports": {
6
6
  "./clerk": {
@@ -98,6 +98,21 @@
98
98
  "import": "./dist/fuma/server.mjs",
99
99
  "require": "./dist/fuma/server.js"
100
100
  },
101
+ "./fuma/server/page-generator": {
102
+ "types": "./dist/fuma/server/page-generator.d.ts",
103
+ "import": "./dist/fuma/server/page-generator.mjs",
104
+ "require": "./dist/fuma/server/page-generator.js"
105
+ },
106
+ "./fuma/server/llm-copy-handler": {
107
+ "types": "./dist/fuma/server/llm-copy-handler.d.ts",
108
+ "import": "./dist/fuma/server/llm-copy-handler.mjs",
109
+ "require": "./dist/fuma/server/llm-copy-handler.js"
110
+ },
111
+ "./fuma/fuma-translate-util": {
112
+ "types": "./dist/fuma/fuma-translate-util.d.ts",
113
+ "import": "./dist/fuma/fuma-translate-util.mjs",
114
+ "require": "./dist/fuma/fuma-translate-util.js"
115
+ },
101
116
  "./fuma/server/site-mdx/base": {
102
117
  "types": "./dist/fuma/server/site-mdx-base.d.ts",
103
118
  "import": "./dist/fuma/server/site-mdx-base.mjs",
@@ -143,6 +158,31 @@
143
158
  "import": "./dist/fuma/base/index.mjs",
144
159
  "require": "./dist/fuma/base/index.js"
145
160
  },
161
+ "./fuma/base/docs-root-provider": {
162
+ "types": "./dist/fuma/base/docs-root-provider.d.ts",
163
+ "import": "./dist/fuma/base/docs-root-provider.mjs",
164
+ "require": "./dist/fuma/base/docs-root-provider.js"
165
+ },
166
+ "./fuma/base/nav-config": {
167
+ "types": "./dist/fuma/base/nav-config.d.ts",
168
+ "import": "./dist/fuma/base/nav-config.mjs",
169
+ "require": "./dist/fuma/base/nav-config.js"
170
+ },
171
+ "./fuma/base/site-docs-layout": {
172
+ "types": "./dist/fuma/base/site-docs-layout.d.ts",
173
+ "import": "./dist/fuma/base/site-docs-layout.mjs",
174
+ "require": "./dist/fuma/base/site-docs-layout.js"
175
+ },
176
+ "./fuma/base/site-home-layout": {
177
+ "types": "./dist/fuma/base/site-home-layout.d.ts",
178
+ "import": "./dist/fuma/base/site-home-layout.mjs",
179
+ "require": "./dist/fuma/base/site-home-layout.js"
180
+ },
181
+ "./fuma/base/site-layout-shared": {
182
+ "types": "./dist/fuma/base/site-layout-shared.d.ts",
183
+ "import": "./dist/fuma/base/site-layout-shared.mjs",
184
+ "require": "./dist/fuma/base/site-layout-shared.js"
185
+ },
146
186
  "./lib/server": {
147
187
  "types": "./dist/lib/server.d.ts",
148
188
  "import": "./dist/lib/server.mjs",
@@ -187,9 +227,9 @@
187
227
  "tslib": "^2.8.1",
188
228
  "unified": "^11.0.5",
189
229
  "zod": "^4.3.6",
190
- "@windrun-huaiin/base-ui": "^27.0.0",
191
- "@windrun-huaiin/lib": "^27.0.0",
192
- "@windrun-huaiin/contracts": "^27.0.0"
230
+ "@windrun-huaiin/base-ui": "^28.0.0",
231
+ "@windrun-huaiin/lib": "^28.0.0",
232
+ "@windrun-huaiin/contracts": "^28.0.0"
193
233
  },
194
234
  "peerDependencies": {
195
235
  "clsx": "^2.1.1",
@@ -35,7 +35,7 @@ import { Popover, PopoverContent, PopoverTrigger } from 'fumadocs-ui/components/
35
35
  import { buttonVariants } from 'fumadocs-ui/components/ui/button';
36
36
  import { useI18n } from 'fumadocs-ui/contexts/i18n';
37
37
  import { HeaderThemeSwitch } from './header-theme-switch';
38
- import type { ExtendedLinkItem } from './custom-home-layout';
38
+ import type { ExtendedLinkItem } from './site-layout-shared';
39
39
 
40
40
  export type NavbarCSSVars = CSSProperties & {
41
41
  '--fd-banner-height'?: string;
@@ -1,6 +1,5 @@
1
1
  import type { CSSProperties, ReactNode } from 'react';
2
2
  import { HomeLayout, type HomeLayoutProps } from 'fumadocs-ui/layouts/home';
3
- import { type LinkItemType } from 'fumadocs-ui/layouts/shared';
4
3
  import { FumaBannerSuit } from '../fuma-banner-suit';
5
4
  import { Footer } from '../../main/footer';
6
5
  import { GoToTop } from '../../main/go-to-top';
@@ -12,11 +11,6 @@ import {
12
11
  type MobileMenuAction,
13
12
  } from './custom-header';
14
13
 
15
- export type ExtendedLinkItem = LinkItemType & {
16
- mobilePinned?: boolean;
17
- prefetch?: boolean;
18
- };
19
-
20
14
  // - bannerHeight/headerHeight 换成你项目期望的 rem 值即可(如果没有 Banner 就把 bannerHeight 设成 0)。
21
15
  // - layoutStyle 同时把变量传给 HomeLayout 的 main 元素,这样内容整体会往下错开,不需要 has-banner/no-banner class。
22
16
  // - CustomHomeHeader 直接接受 HomeLayout 的各类 props(links、nav、searchToggle、themeSwitch、i18n 等),内部会复用 Fumadocs 原本的导航功能。
@@ -0,0 +1,58 @@
1
+ import type { ComponentProps, ReactNode } from 'react';
2
+ import { NextProvider } from 'fumadocs-core/framework/next';
3
+ import { I18nProvider, type I18nProviderProps } from 'fumadocs-ui/contexts/i18n';
4
+ import { ThemeProvider, type ThemeProviderProps } from 'next-themes';
5
+
6
+ type NextProviderComponents = {
7
+ Link?: ComponentProps<typeof NextProvider>['Link'];
8
+ Image?: ComponentProps<typeof NextProvider>['Image'];
9
+ };
10
+
11
+ type ThemeOptions = ThemeProviderProps & {
12
+ enabled?: boolean;
13
+ };
14
+
15
+ export interface DocsRootProviderProps {
16
+ i18n: Omit<I18nProviderProps, 'children'>;
17
+ theme?: ThemeOptions;
18
+ components?: NextProviderComponents;
19
+ children: ReactNode;
20
+ }
21
+
22
+ export function DocsRootProvider({
23
+ i18n,
24
+ theme = {},
25
+ components,
26
+ children,
27
+ }: DocsRootProviderProps) {
28
+ let body = children;
29
+
30
+ if (theme.enabled !== false) {
31
+ body = (
32
+ <ThemeProvider
33
+ attribute="class"
34
+ defaultTheme="system"
35
+ enableSystem
36
+ disableTransitionOnChange
37
+ {...theme}
38
+ >
39
+ {body}
40
+ </ThemeProvider>
41
+ );
42
+ }
43
+
44
+ body = (
45
+ <I18nProvider {...i18n}>
46
+ {body}
47
+ </I18nProvider>
48
+ );
49
+
50
+ return (
51
+ <NextProvider
52
+ Link={components?.Link}
53
+ Image={components?.Image}
54
+ >
55
+ {body}
56
+ </NextProvider>
57
+ );
58
+ }
@@ -1,4 +1,8 @@
1
1
  export * from './custom-header';
2
2
  export * from './custom-home-layout';
3
+ export * from './docs-root-provider';
3
4
  export * from './nav-config';
5
+ export * from './site-docs-layout';
6
+ export * from './site-home-layout';
4
7
  export * from './site-layout';
8
+ export * from './site-layout-shared';