@windrun-huaiin/third-ui 26.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 (210) hide show
  1. package/dist/ai/ai-prompt-textarea.d.ts +72 -0
  2. package/dist/ai/ai-prompt-textarea.js +114 -0
  3. package/dist/ai/ai-prompt-textarea.mjs +112 -0
  4. package/dist/ai/index.d.ts +1 -0
  5. package/dist/ai/index.js +2 -0
  6. package/dist/ai/index.mjs +1 -0
  7. package/dist/clerk/clerk-provider-client.js +0 -1
  8. package/dist/clerk/clerk-provider-client.mjs +0 -1
  9. package/dist/clerk/fingerprint/fingerprint-client.js +0 -4
  10. package/dist/clerk/fingerprint/fingerprint-client.mjs +0 -4
  11. package/dist/clerk/fingerprint/use-fingerprint.js +0 -6
  12. package/dist/clerk/fingerprint/use-fingerprint.mjs +0 -6
  13. package/dist/clerk/signin-with-fingerprint-client.js +0 -9
  14. package/dist/clerk/signin-with-fingerprint-client.mjs +0 -9
  15. package/dist/clerk/signup-button-with-fingerprint-client.js +0 -16
  16. package/dist/clerk/signup-button-with-fingerprint-client.mjs +0 -16
  17. package/dist/clerk/signup-with-fingerprint-client.js +0 -9
  18. package/dist/clerk/signup-with-fingerprint-client.mjs +0 -9
  19. package/dist/fuma/base/custom-header.js +10 -8
  20. package/dist/fuma/base/custom-header.mjs +10 -8
  21. package/dist/fuma/base/custom-home-layout.d.ts +0 -4
  22. package/dist/fuma/base/docs-root-provider.d.ts +19 -0
  23. package/dist/fuma/base/docs-root-provider.js +17 -0
  24. package/dist/fuma/base/docs-root-provider.mjs +15 -0
  25. package/dist/fuma/base/index.d.ts +5 -0
  26. package/dist/fuma/base/index.js +16 -7
  27. package/dist/fuma/base/index.mjs +5 -1
  28. package/dist/fuma/base/nav-config.d.ts +10 -0
  29. package/dist/fuma/base/nav-config.js +32 -0
  30. package/dist/fuma/base/nav-config.mjs +28 -0
  31. package/dist/fuma/base/site-docs-layout.d.ts +11 -0
  32. package/dist/fuma/base/site-docs-layout.js +15 -0
  33. package/dist/fuma/base/site-docs-layout.mjs +13 -0
  34. package/dist/fuma/base/site-home-layout.d.ts +24 -0
  35. package/dist/fuma/base/site-home-layout.js +16 -0
  36. package/dist/fuma/base/site-home-layout.mjs +14 -0
  37. package/dist/fuma/base/site-layout-shared.d.ts +89 -0
  38. package/dist/fuma/base/site-layout-shared.js +48 -0
  39. package/dist/fuma/base/site-layout-shared.mjs +42 -0
  40. package/dist/fuma/base/site-layout.d.ts +4 -116
  41. package/dist/fuma/base/site-layout.js +2 -2
  42. package/dist/fuma/base/site-layout.mjs +2 -2
  43. package/dist/fuma/fuma-page-genarator.d.ts +1 -1
  44. package/dist/fuma/fuma-page-genarator.js +65 -10
  45. package/dist/fuma/fuma-page-genarator.mjs +61 -6
  46. package/dist/fuma/llm-copy-handler.js +0 -9
  47. package/dist/fuma/llm-copy-handler.mjs +0 -9
  48. package/dist/fuma/mdx/index.d.ts +0 -1
  49. package/dist/fuma/mdx/index.js +0 -2
  50. package/dist/fuma/mdx/index.mjs +0 -1
  51. package/dist/fuma/mdx/suno-embed.js +3 -1
  52. package/dist/fuma/mdx/suno-embed.mjs +3 -1
  53. package/dist/fuma/mdx/toc-base.js +0 -1
  54. package/dist/fuma/mdx/toc-base.mjs +0 -1
  55. package/dist/fuma/server/features/widgets.js +5 -1
  56. package/dist/fuma/server/features/widgets.mjs +5 -1
  57. package/dist/fuma/server/llm-copy-handler.d.ts +2 -0
  58. package/dist/fuma/server/llm-copy-handler.js +7 -0
  59. package/dist/fuma/server/llm-copy-handler.mjs +1 -0
  60. package/dist/fuma/server/page-generator.d.ts +2 -0
  61. package/dist/fuma/server/page-generator.js +7 -0
  62. package/dist/fuma/server/page-generator.mjs +1 -0
  63. package/dist/lib/seo-metadata.js +3 -3
  64. package/dist/lib/seo-metadata.mjs +1 -1
  65. package/dist/lib/seo-util.js +4 -4
  66. package/dist/lib/seo-util.mjs +1 -1
  67. package/dist/lib/site-docs-helper.d.ts +51 -0
  68. package/dist/lib/site-docs-helper.js +68 -0
  69. package/dist/lib/site-docs-helper.mjs +66 -0
  70. package/dist/main/alert-dialog/index.js +14 -0
  71. package/dist/main/alert-dialog/index.mjs +5 -0
  72. package/dist/main/buttons/gradient-button.d.ts +20 -0
  73. package/dist/main/buttons/gradient-button.js +88 -0
  74. package/dist/main/buttons/gradient-button.mjs +86 -0
  75. package/dist/main/buttons/index.d.ts +3 -0
  76. package/dist/main/buttons/index.js +12 -0
  77. package/dist/main/buttons/index.mjs +4 -0
  78. package/dist/main/buttons/x-button.d.ts +39 -0
  79. package/dist/main/buttons/x-button.js +92 -0
  80. package/dist/main/buttons/x-button.mjs +90 -0
  81. package/dist/main/buttons/x-toggle-button.d.ts +32 -0
  82. package/dist/main/buttons/x-toggle-button.js +95 -0
  83. package/dist/main/buttons/x-toggle-button.mjs +74 -0
  84. package/dist/main/credit/credit-nav-button.js +25 -1
  85. package/dist/main/credit/credit-nav-button.mjs +25 -1
  86. package/dist/main/credit/credit-overview-client.js +3 -2
  87. package/dist/main/credit/credit-overview-client.mjs +3 -2
  88. package/dist/main/credit/index.d.ts +4 -0
  89. package/dist/main/credit/index.js +10 -0
  90. package/dist/main/credit/index.mjs +3 -0
  91. package/dist/main/credit/server.d.ts +2 -0
  92. package/dist/main/credit/server.js +7 -0
  93. package/dist/main/credit/server.mjs +1 -0
  94. package/dist/main/cta.js +4 -2
  95. package/dist/main/cta.mjs +4 -2
  96. package/dist/main/footer.js +3 -3
  97. package/dist/main/footer.mjs +1 -1
  98. package/dist/main/hero/index.d.ts +2 -0
  99. package/dist/main/hero/index.js +10 -0
  100. package/dist/main/hero/index.mjs +3 -0
  101. package/dist/main/home/server.d.ts +7 -0
  102. package/dist/main/home/server.js +19 -0
  103. package/dist/main/home/server.mjs +7 -0
  104. package/dist/main/index.d.ts +0 -15
  105. package/dist/main/index.js +0 -43
  106. package/dist/main/index.mjs +0 -21
  107. package/dist/main/loading/index.d.ts +1 -0
  108. package/dist/main/loading/index.js +9 -0
  109. package/dist/main/loading/index.mjs +2 -0
  110. package/dist/main/loading-frame/index.d.ts +1 -0
  111. package/dist/main/loading-frame/index.js +9 -0
  112. package/dist/main/loading-frame/index.mjs +2 -0
  113. package/dist/main/money-price/index.d.ts +4 -0
  114. package/dist/main/money-price/index.js +15 -0
  115. package/dist/main/money-price/index.mjs +4 -0
  116. package/dist/main/money-price/money-price-button.d.ts +1 -1
  117. package/dist/main/money-price/money-price-button.js +12 -9
  118. package/dist/main/money-price/money-price-button.mjs +12 -9
  119. package/dist/main/money-price/money-price-interactive.d.ts +1 -1
  120. package/dist/main/money-price/money-price-interactive.js +22 -25
  121. package/dist/main/money-price/money-price-interactive.mjs +22 -25
  122. package/dist/main/money-price/money-price-types.d.ts +2 -0
  123. package/dist/main/money-price/server.d.ts +5 -0
  124. package/dist/main/money-price/server.js +18 -0
  125. package/dist/main/money-price/server.mjs +4 -0
  126. package/package.json +94 -4
  127. package/src/ai/index.ts +1 -0
  128. package/src/clerk/clerk-provider-client.tsx +1 -3
  129. package/src/clerk/fingerprint/fingerprint-client.ts +0 -4
  130. package/src/clerk/fingerprint/use-fingerprint.ts +0 -6
  131. package/src/clerk/signin-with-fingerprint-client.tsx +0 -10
  132. package/src/clerk/signup-button-with-fingerprint-client.tsx +0 -17
  133. package/src/clerk/signup-with-fingerprint-client.tsx +0 -10
  134. package/src/fuma/base/custom-header.tsx +12 -8
  135. package/src/fuma/base/custom-home-layout.tsx +3 -6
  136. package/src/fuma/base/docs-root-provider.tsx +58 -0
  137. package/src/fuma/base/index.ts +5 -0
  138. package/src/fuma/base/nav-config.ts +81 -0
  139. package/src/fuma/base/site-docs-layout.tsx +35 -0
  140. package/src/fuma/base/site-home-layout.tsx +78 -0
  141. package/src/fuma/base/site-layout-shared.tsx +190 -0
  142. package/src/fuma/base/site-layout.tsx +4 -289
  143. package/src/fuma/fuma-banner-suit.tsx +1 -1
  144. package/src/fuma/fuma-page-genarator.tsx +61 -8
  145. package/src/fuma/llm-copy-handler.ts +0 -11
  146. package/src/fuma/mdx/index.ts +0 -1
  147. package/src/fuma/mdx/suno-embed.tsx +1 -1
  148. package/src/fuma/mdx/toc-base.tsx +0 -1
  149. package/src/fuma/mdx/toc-footer-wrapper.tsx +2 -2
  150. package/src/fuma/server/features/widgets.tsx +1 -1
  151. package/src/fuma/server/llm-copy-handler.ts +2 -0
  152. package/src/fuma/server/page-generator.ts +2 -0
  153. package/src/lib/seo-metadata.ts +1 -1
  154. package/src/lib/seo-util.ts +2 -2
  155. package/src/lib/server.ts +1 -1
  156. package/src/{fuma/mdx → main/buttons}/gradient-button.tsx +10 -21
  157. package/src/main/buttons/index.ts +5 -0
  158. package/src/main/{x-button.tsx → buttons/x-button.tsx} +28 -42
  159. package/src/main/credit/credit-nav-button.tsx +36 -3
  160. package/src/main/credit/credit-overview-client.tsx +1 -1
  161. package/src/main/credit/index.ts +11 -0
  162. package/src/main/credit/server.ts +7 -0
  163. package/src/main/cta.tsx +1 -1
  164. package/src/main/footer.tsx +1 -2
  165. package/src/main/hero/index.ts +4 -0
  166. package/src/main/home/server.ts +7 -0
  167. package/src/main/index.ts +1 -20
  168. package/src/main/language-detector.tsx +0 -1
  169. package/src/main/loading/index.ts +3 -0
  170. package/src/main/loading-frame/index.ts +3 -0
  171. package/src/main/money-price/index.ts +18 -0
  172. package/src/main/money-price/money-price-button.tsx +17 -9
  173. package/src/main/money-price/money-price-interactive.tsx +30 -25
  174. package/src/main/money-price/money-price-types.ts +2 -0
  175. package/src/main/money-price/server.ts +22 -0
  176. package/dist/fuma/mdx/features.d.ts +0 -8
  177. package/dist/fuma/mdx/features.js +0 -92
  178. package/dist/fuma/mdx/features.mjs +0 -85
  179. package/dist/fuma/mdx/image-grid.d.ts +0 -6
  180. package/dist/fuma/mdx/image-grid.js +0 -17
  181. package/dist/fuma/mdx/image-grid.mjs +0 -15
  182. package/dist/fuma/mdx/image-zoom.d.ts +0 -22
  183. package/dist/fuma/mdx/image-zoom.js +0 -39
  184. package/dist/fuma/mdx/image-zoom.mjs +0 -37
  185. package/dist/fuma/mdx/markdown-component-map.d.ts +0 -3
  186. package/dist/fuma/mdx/markdown-component-map.js +0 -79
  187. package/dist/fuma/mdx/markdown-component-map.mjs +0 -77
  188. package/dist/fuma/mdx/math.d.ts +0 -17
  189. package/dist/fuma/mdx/math.js +0 -60
  190. package/dist/fuma/mdx/math.mjs +0 -57
  191. package/dist/fuma/mdx/mermaid.d.ts +0 -13
  192. package/dist/fuma/mdx/mermaid.js +0 -360
  193. package/dist/fuma/mdx/mermaid.mjs +0 -358
  194. package/dist/fuma/mdx/site-mdx-components.d.ts +0 -13
  195. package/dist/fuma/mdx/site-mdx-components.js +0 -19
  196. package/dist/fuma/mdx/site-mdx-components.mjs +0 -17
  197. package/dist/fuma/mdx/site-mdx-presets.d.ts +0 -13
  198. package/dist/fuma/mdx/site-mdx-presets.js +0 -49
  199. package/dist/fuma/mdx/site-mdx-presets.mjs +0 -45
  200. package/dist/fuma/server/optional-features.d.ts +0 -6
  201. package/dist/fuma/server/optional-features.js +0 -17
  202. package/dist/fuma/server/optional-features.mjs +0 -6
  203. package/dist/fuma/server/site-mdx-components.d.ts +0 -13
  204. package/dist/fuma/server/site-mdx-components.js +0 -18
  205. package/dist/fuma/server/site-mdx-components.mjs +0 -16
  206. package/dist/fuma/server/site-mdx-presets.d.ts +0 -195
  207. package/dist/fuma/server/site-mdx-presets.js +0 -55
  208. package/dist/fuma/server/site-mdx-presets.mjs +0 -52
  209. /package/src/{main → ai}/ai-prompt-textarea.tsx +0 -0
  210. /package/src/main/{x-toggle-button.tsx → buttons/x-toggle-button.tsx} +0 -0
@@ -0,0 +1,72 @@
1
+ interface AIPromptTextareaProps {
2
+ /**
3
+ * Textarea value reference
4
+ */
5
+ value: string;
6
+ /**
7
+ * Textarea value change handler
8
+ */
9
+ onChange: (value: string) => void;
10
+ /**
11
+ * Word limit value reference
12
+ */
13
+ isWordLimit: boolean;
14
+ /**
15
+ * Word limit value change handler
16
+ */
17
+ onWordLimitChange: (isLimit: boolean) => void;
18
+ /**
19
+ * Placeholder
20
+ */
21
+ placeholder?: string;
22
+ /**
23
+ * Disabled switch condition, default is false
24
+ */
25
+ disabled?: boolean;
26
+ /**
27
+ * Maximum words
28
+ */
29
+ maxWords?: number;
30
+ /**
31
+ * Word count unit title
32
+ */
33
+ wordUnitTitle?: string;
34
+ /**
35
+ * Minimum height, px
36
+ */
37
+ minHeight?: number;
38
+ /**
39
+ * Maximum height, px
40
+ */
41
+ maxHeight?: number;
42
+ /**
43
+ * Word count switch, default is true
44
+ */
45
+ showWordCount?: boolean;
46
+ /**
47
+ * Auto scroll switch, default is true
48
+ */
49
+ autoScroll?: boolean;
50
+ /**
51
+ * Extra scroll space, px
52
+ */
53
+ extraScrollSpace?: number;
54
+ /**
55
+ * Custome tailwindcss style
56
+ */
57
+ className?: string;
58
+ /**
59
+ * Title text, if not provided, no title will be rendered
60
+ */
61
+ title?: string;
62
+ /**
63
+ * Description text
64
+ */
65
+ description?: string;
66
+ /**
67
+ * Embed title inside textarea, default is false
68
+ */
69
+ embed?: boolean;
70
+ }
71
+ export declare function AIPromptTextarea({ value, onChange, placeholder, disabled, maxWords, wordUnitTitle, minHeight, maxHeight, className, showWordCount, autoScroll, extraScrollSpace, isWordLimit, onWordLimitChange, title, description, embed }: AIPromptTextareaProps): import("react/jsx-runtime").JSX.Element;
72
+ export {};
@@ -0,0 +1,114 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var React = require('react');
6
+ var utils = require('@windrun-huaiin/lib/utils');
7
+
8
+ function AIPromptTextarea({ value, onChange, placeholder = "Enter your prompt...", disabled = false, maxWords = 400, wordUnitTitle = "words", minHeight = 150, maxHeight = 300, className = "", showWordCount = true, autoScroll = true, extraScrollSpace = 100, isWordLimit, onWordLimitChange, title, description, embed = false }) {
9
+ const textareaRef = React.useRef(null);
10
+ // count words
11
+ const wordArray = value.trim().split(/\s+/).filter(Boolean);
12
+ const wordCount = wordArray.length;
13
+ // auto adjust textarea height
14
+ const adjustTextareaHeight = () => {
15
+ if (textareaRef.current) {
16
+ const textarea = textareaRef.current;
17
+ const oldHeight = textarea.style.height;
18
+ // reset height
19
+ textarea.style.height = 'auto';
20
+ // calculate content height
21
+ const contentHeight = textarea.scrollHeight;
22
+ // auto adjust height between min and max height
23
+ let newHeight = Math.max(contentHeight, minHeight);
24
+ newHeight = Math.min(newHeight, maxHeight);
25
+ textarea.style.height = `${newHeight}px`;
26
+ // if content height is greater than max height, show scrollbar
27
+ if (contentHeight > maxHeight) {
28
+ textarea.style.overflowY = 'auto';
29
+ }
30
+ else {
31
+ textarea.style.overflowY = 'hidden';
32
+ }
33
+ // if height increased and auto scroll is enabled, scroll to appropriate position
34
+ if (autoScroll && (newHeight > parseInt(oldHeight) || !oldHeight)) {
35
+ setTimeout(() => {
36
+ const rect = textarea.getBoundingClientRect();
37
+ window.scrollTo({
38
+ top: window.pageYOffset + rect.bottom + extraScrollSpace - window.innerHeight,
39
+ behavior: 'smooth'
40
+ });
41
+ }, 0);
42
+ }
43
+ }
44
+ };
45
+ // when value changes, adjust height
46
+ React.useEffect(() => {
47
+ const timer = setTimeout(() => {
48
+ adjustTextareaHeight();
49
+ }, 0);
50
+ return () => clearTimeout(timer);
51
+ // eslint-disable-next-line react-hooks/exhaustive-deps
52
+ }, [value, minHeight, maxHeight, autoScroll, extraScrollSpace]);
53
+ // handle input, limit max words
54
+ const handleInputChange = (e) => {
55
+ const inputValue = e.target.value;
56
+ const words = inputValue.trim().split(/\s+/).filter(Boolean);
57
+ // if already reached max words, and this input will exceed limit, do not update
58
+ if (wordCount >= maxWords && words.length > maxWords) {
59
+ onWordLimitChange(true);
60
+ return;
61
+ }
62
+ if (words.length > maxWords) {
63
+ onChange(words.slice(0, maxWords).join(' '));
64
+ onWordLimitChange(true);
65
+ }
66
+ else {
67
+ onChange(inputValue);
68
+ onWordLimitChange(false);
69
+ }
70
+ };
71
+ // when paste, also check word count
72
+ const handlePaste = (e) => {
73
+ const paste = e.clipboardData.getData('text');
74
+ const currentWords = value.trim().split(/\s+/).filter(Boolean);
75
+ const pasteWords = paste.trim().split(/\s+/).filter(Boolean);
76
+ if (currentWords.length >= maxWords) {
77
+ e.preventDefault();
78
+ onWordLimitChange(true);
79
+ return;
80
+ }
81
+ // only allow paste remaining words
82
+ const allowed = maxWords - currentWords.length;
83
+ if (pasteWords.length > allowed) {
84
+ e.preventDefault();
85
+ const newWords = currentWords.concat(pasteWords.slice(0, allowed));
86
+ onChange(newWords.join(' '));
87
+ onWordLimitChange(true);
88
+ }
89
+ };
90
+ // 渲染标题组件
91
+ const renderTitle = () => {
92
+ if (!(title === null || title === void 0 ? void 0 : title.trim()))
93
+ return null;
94
+ return (jsxRuntime.jsxs("div", { className: "space-y-1", children: [title && jsxRuntime.jsx("span", { className: "text-xl font-semibold text-foreground", children: title }), (description === null || description === void 0 ? void 0 : description.trim()) && jsxRuntime.jsx("span", { className: "text-sm text-gray-400 ml-2", children: description })] }));
95
+ };
96
+ // 渲染textarea组件
97
+ const renderTextarea = (isEmbedded = false) => (jsxRuntime.jsx("textarea", { ref: textareaRef, value: value, onChange: handleInputChange, onPaste: handlePaste, placeholder: placeholder, disabled: disabled, className: utils.cn('w-full p-4 bg-transparent transition-colors text-foreground placeholder-muted-foreground placeholder:text-base disabled:bg-muted disabled:cursor-not-allowed resize-none', isEmbedded
98
+ ? 'border-0 hover:border-2 hover:border-purple-500 focus:outline-none focus:border-2 focus:border-purple-500'
99
+ : 'border-2 border-border rounded-lg hover:border-purple-500 focus:outline-none focus:border-purple-500', className), style: { minHeight: `${minHeight}px` } }));
100
+ // 渲染单词计数
101
+ const renderWordCount = () => {
102
+ if (!showWordCount)
103
+ return null;
104
+ return (jsxRuntime.jsx("div", { className: "flex justify-end", children: jsxRuntime.jsxs("span", { className: `text-sm ${wordCount >= maxWords ? 'text-red-500' : wordCount > maxWords * 0.75 ? 'text-orange-500' : 'text-muted-foreground'} ${isWordLimit ? 'animate-bounce' : ''}`, onAnimationEnd: () => onWordLimitChange(false), children: [wordCount, "/", maxWords, " ", wordUnitTitle] }) }));
105
+ };
106
+ // 如果有标题且需要嵌入,则渲染内部标题布局
107
+ if (embed && (title)) {
108
+ return (jsxRuntime.jsxs("div", { className: "space-y-2", children: [jsxRuntime.jsxs("div", { className: "border-2 border-border rounded-lg bg-transparent", children: [jsxRuntime.jsx("div", { className: "p-4 pb-2", children: renderTitle() }), jsxRuntime.jsx("hr", { className: "border-t border-border" }), jsxRuntime.jsx("div", { className: "p-1", children: renderTextarea(true) })] }), renderWordCount()] }));
109
+ }
110
+ // 默认布局:外部标题或无标题
111
+ return (jsxRuntime.jsxs("div", { className: "space-y-2", children: [renderTitle(), renderTextarea(), renderWordCount()] }));
112
+ }
113
+
114
+ exports.AIPromptTextarea = AIPromptTextarea;
@@ -0,0 +1,112 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { useRef, useEffect } from 'react';
4
+ import { cn } from '@windrun-huaiin/lib/utils';
5
+
6
+ function AIPromptTextarea({ value, onChange, placeholder = "Enter your prompt...", disabled = false, maxWords = 400, wordUnitTitle = "words", minHeight = 150, maxHeight = 300, className = "", showWordCount = true, autoScroll = true, extraScrollSpace = 100, isWordLimit, onWordLimitChange, title, description, embed = false }) {
7
+ const textareaRef = useRef(null);
8
+ // count words
9
+ const wordArray = value.trim().split(/\s+/).filter(Boolean);
10
+ const wordCount = wordArray.length;
11
+ // auto adjust textarea height
12
+ const adjustTextareaHeight = () => {
13
+ if (textareaRef.current) {
14
+ const textarea = textareaRef.current;
15
+ const oldHeight = textarea.style.height;
16
+ // reset height
17
+ textarea.style.height = 'auto';
18
+ // calculate content height
19
+ const contentHeight = textarea.scrollHeight;
20
+ // auto adjust height between min and max height
21
+ let newHeight = Math.max(contentHeight, minHeight);
22
+ newHeight = Math.min(newHeight, maxHeight);
23
+ textarea.style.height = `${newHeight}px`;
24
+ // if content height is greater than max height, show scrollbar
25
+ if (contentHeight > maxHeight) {
26
+ textarea.style.overflowY = 'auto';
27
+ }
28
+ else {
29
+ textarea.style.overflowY = 'hidden';
30
+ }
31
+ // if height increased and auto scroll is enabled, scroll to appropriate position
32
+ if (autoScroll && (newHeight > parseInt(oldHeight) || !oldHeight)) {
33
+ setTimeout(() => {
34
+ const rect = textarea.getBoundingClientRect();
35
+ window.scrollTo({
36
+ top: window.pageYOffset + rect.bottom + extraScrollSpace - window.innerHeight,
37
+ behavior: 'smooth'
38
+ });
39
+ }, 0);
40
+ }
41
+ }
42
+ };
43
+ // when value changes, adjust height
44
+ useEffect(() => {
45
+ const timer = setTimeout(() => {
46
+ adjustTextareaHeight();
47
+ }, 0);
48
+ return () => clearTimeout(timer);
49
+ // eslint-disable-next-line react-hooks/exhaustive-deps
50
+ }, [value, minHeight, maxHeight, autoScroll, extraScrollSpace]);
51
+ // handle input, limit max words
52
+ const handleInputChange = (e) => {
53
+ const inputValue = e.target.value;
54
+ const words = inputValue.trim().split(/\s+/).filter(Boolean);
55
+ // if already reached max words, and this input will exceed limit, do not update
56
+ if (wordCount >= maxWords && words.length > maxWords) {
57
+ onWordLimitChange(true);
58
+ return;
59
+ }
60
+ if (words.length > maxWords) {
61
+ onChange(words.slice(0, maxWords).join(' '));
62
+ onWordLimitChange(true);
63
+ }
64
+ else {
65
+ onChange(inputValue);
66
+ onWordLimitChange(false);
67
+ }
68
+ };
69
+ // when paste, also check word count
70
+ const handlePaste = (e) => {
71
+ const paste = e.clipboardData.getData('text');
72
+ const currentWords = value.trim().split(/\s+/).filter(Boolean);
73
+ const pasteWords = paste.trim().split(/\s+/).filter(Boolean);
74
+ if (currentWords.length >= maxWords) {
75
+ e.preventDefault();
76
+ onWordLimitChange(true);
77
+ return;
78
+ }
79
+ // only allow paste remaining words
80
+ const allowed = maxWords - currentWords.length;
81
+ if (pasteWords.length > allowed) {
82
+ e.preventDefault();
83
+ const newWords = currentWords.concat(pasteWords.slice(0, allowed));
84
+ onChange(newWords.join(' '));
85
+ onWordLimitChange(true);
86
+ }
87
+ };
88
+ // 渲染标题组件
89
+ const renderTitle = () => {
90
+ if (!(title === null || title === void 0 ? void 0 : title.trim()))
91
+ return null;
92
+ return (jsxs("div", { className: "space-y-1", children: [title && jsx("span", { className: "text-xl font-semibold text-foreground", children: title }), (description === null || description === void 0 ? void 0 : description.trim()) && jsx("span", { className: "text-sm text-gray-400 ml-2", children: description })] }));
93
+ };
94
+ // 渲染textarea组件
95
+ const renderTextarea = (isEmbedded = false) => (jsx("textarea", { ref: textareaRef, value: value, onChange: handleInputChange, onPaste: handlePaste, placeholder: placeholder, disabled: disabled, className: cn('w-full p-4 bg-transparent transition-colors text-foreground placeholder-muted-foreground placeholder:text-base disabled:bg-muted disabled:cursor-not-allowed resize-none', isEmbedded
96
+ ? 'border-0 hover:border-2 hover:border-purple-500 focus:outline-none focus:border-2 focus:border-purple-500'
97
+ : 'border-2 border-border rounded-lg hover:border-purple-500 focus:outline-none focus:border-purple-500', className), style: { minHeight: `${minHeight}px` } }));
98
+ // 渲染单词计数
99
+ const renderWordCount = () => {
100
+ if (!showWordCount)
101
+ return null;
102
+ return (jsx("div", { className: "flex justify-end", children: jsxs("span", { className: `text-sm ${wordCount >= maxWords ? 'text-red-500' : wordCount > maxWords * 0.75 ? 'text-orange-500' : 'text-muted-foreground'} ${isWordLimit ? 'animate-bounce' : ''}`, onAnimationEnd: () => onWordLimitChange(false), children: [wordCount, "/", maxWords, " ", wordUnitTitle] }) }));
103
+ };
104
+ // 如果有标题且需要嵌入,则渲染内部标题布局
105
+ if (embed && (title)) {
106
+ return (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "border-2 border-border rounded-lg bg-transparent", children: [jsx("div", { className: "p-4 pb-2", children: renderTitle() }), jsx("hr", { className: "border-t border-border" }), jsx("div", { className: "p-1", children: renderTextarea(true) })] }), renderWordCount()] }));
107
+ }
108
+ // 默认布局:外部标题或无标题
109
+ return (jsxs("div", { className: "space-y-2", children: [renderTitle(), renderTextarea(), renderWordCount()] }));
110
+ }
111
+
112
+ export { AIPromptTextarea };
@@ -9,3 +9,4 @@ export * from './ai-message-content';
9
9
  export * from './ai-message-meta';
10
10
  export * from './ai-message-actions';
11
11
  export * from './ai-status-indicator';
12
+ export * from './ai-prompt-textarea';
package/dist/ai/index.js CHANGED
@@ -11,6 +11,7 @@ var aiMessageContent = require('./ai-message-content.js');
11
11
  var aiMessageMeta = require('./ai-message-meta.js');
12
12
  var aiMessageActions = require('./ai-message-actions.js');
13
13
  var aiStatusIndicator = require('./ai-status-indicator.js');
14
+ var aiPromptTextarea = require('./ai-prompt-textarea.js');
14
15
 
15
16
 
16
17
 
@@ -31,3 +32,4 @@ exports.AIMessageContent = aiMessageContent.AIMessageContent;
31
32
  exports.AIMessageMeta = aiMessageMeta.AIMessageMeta;
32
33
  exports.AIMessageActions = aiMessageActions.AIMessageActions;
33
34
  exports.AIStatusIndicator = aiStatusIndicator.AIStatusIndicator;
35
+ exports.AIPromptTextarea = aiPromptTextarea.AIPromptTextarea;
package/dist/ai/index.mjs CHANGED
@@ -9,3 +9,4 @@ export { AIMessageContent } from './ai-message-content.mjs';
9
9
  export { AIMessageMeta } from './ai-message-meta.mjs';
10
10
  export { AIMessageActions } from './ai-message-actions.mjs';
11
11
  export { AIStatusIndicator } from './ai-status-indicator.mjs';
12
+ export { AIPromptTextarea } from './ai-prompt-textarea.mjs';
@@ -37,7 +37,6 @@ function ClerkProviderClient({ children, locale, localePrefixAsNeeded = true, de
37
37
  if (waitlistWithLocale) {
38
38
  clerkProviderProps.waitlistUrl = waitlistWithLocale;
39
39
  }
40
- // console.log('ClerkProviderClient props:', clerkProviderProps);
41
40
  return (jsxRuntime.jsx(nextjs.ClerkProvider, Object.assign({}, clerkProviderProps, { children: children })));
42
41
  }
43
42
 
@@ -35,7 +35,6 @@ function ClerkProviderClient({ children, locale, localePrefixAsNeeded = true, de
35
35
  if (waitlistWithLocale) {
36
36
  clerkProviderProps.waitlistUrl = waitlistWithLocale;
37
37
  }
38
- // console.log('ClerkProviderClient props:', clerkProviderProps);
39
38
  return (jsx(ClerkProvider, Object.assign({}, clerkProviderProps, { children: children })));
40
39
  }
41
40
 
@@ -163,7 +163,6 @@ function generateFingerprintId() {
163
163
  // 检查现有 ID
164
164
  const existingId = checkStoredFingerprintId();
165
165
  if (existingId) {
166
- console.log('Using existing fingerprint ID:', existingId);
167
166
  return existingId;
168
167
  }
169
168
  try {
@@ -174,7 +173,6 @@ function generateFingerprintId() {
174
173
  // 存储到 localStorage 和 cookie
175
174
  setLocalStorageValue(fingerprintShared.FINGERPRINT_STORAGE_KEY, fingerprintId);
176
175
  setCookie(fingerprintShared.FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
177
- console.log('Generated new fingerprint ID:', fingerprintId);
178
176
  return fingerprintId;
179
177
  }
180
178
  catch (error) {
@@ -183,7 +181,6 @@ function generateFingerprintId() {
183
181
  const fallbackId = `fp_fallback_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
184
182
  setLocalStorageValue(fingerprintShared.FINGERPRINT_STORAGE_KEY, fallbackId);
185
183
  setCookie(fingerprintShared.FINGERPRINT_COOKIE_NAME, fallbackId, 365);
186
- console.log('Generated fallback fingerprint ID:', fallbackId);
187
184
  return fallbackId;
188
185
  }
189
186
  });
@@ -225,7 +222,6 @@ function getOrGenerateFingerprintId() {
225
222
  return tslib.__awaiter(this, void 0, void 0, function* () {
226
223
  const existingId = checkStoredFingerprintId();
227
224
  if (existingId) {
228
- console.log('Retrieved existing fingerprint ID:', existingId);
229
225
  return existingId;
230
226
  }
231
227
  return yield generateFingerprintId();
@@ -161,7 +161,6 @@ function generateFingerprintId() {
161
161
  // 检查现有 ID
162
162
  const existingId = checkStoredFingerprintId();
163
163
  if (existingId) {
164
- console.log('Using existing fingerprint ID:', existingId);
165
164
  return existingId;
166
165
  }
167
166
  try {
@@ -172,7 +171,6 @@ function generateFingerprintId() {
172
171
  // 存储到 localStorage 和 cookie
173
172
  setLocalStorageValue(FINGERPRINT_STORAGE_KEY, fingerprintId);
174
173
  setCookie(FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
175
- console.log('Generated new fingerprint ID:', fingerprintId);
176
174
  return fingerprintId;
177
175
  }
178
176
  catch (error) {
@@ -181,7 +179,6 @@ function generateFingerprintId() {
181
179
  const fallbackId = `fp_fallback_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
182
180
  setLocalStorageValue(FINGERPRINT_STORAGE_KEY, fallbackId);
183
181
  setCookie(FINGERPRINT_COOKIE_NAME, fallbackId, 365);
184
- console.log('Generated fallback fingerprint ID:', fallbackId);
185
182
  return fallbackId;
186
183
  }
187
184
  });
@@ -223,7 +220,6 @@ function getOrGenerateFingerprintId() {
223
220
  return __awaiter(this, void 0, void 0, function* () {
224
221
  const existingId = checkStoredFingerprintId();
225
222
  if (existingId) {
226
- console.log('Retrieved existing fingerprint ID:', existingId);
227
223
  return existingId;
228
224
  }
229
225
  return yield generateFingerprintId();
@@ -46,7 +46,6 @@ function useFingerprint(config) {
46
46
  // Capture first-touch as early as possible before any in-site navigation can overwrite context.
47
47
  fingerprintClient.getOrCreateFirstTouchData();
48
48
  const currentFingerprintId = yield fingerprintClient.getOrGenerateFingerprintId();
49
- console.log('Initialized fingerprintId:', currentFingerprintId);
50
49
  setFingerprintIdState(currentFingerprintId);
51
50
  return currentFingerprintId;
52
51
  }
@@ -67,11 +66,9 @@ function useFingerprint(config) {
67
66
  return;
68
67
  }
69
68
  if (isInitializingAnonymousUserRef.current) {
70
- console.log('Skipping anonymous user initialization because a request is already in flight:', fingerprintId);
71
69
  return;
72
70
  }
73
71
  if (requestedAnonymousFingerprintRef.current === fingerprintId && isInitialized) {
74
- console.log('Skipping anonymous user initialization because fingerprint is already initialized:', fingerprintId);
75
72
  return;
76
73
  }
77
74
  try {
@@ -79,7 +76,6 @@ function useFingerprint(config) {
79
76
  requestedAnonymousFingerprintRef.current = fingerprintId;
80
77
  setIsLoading(true);
81
78
  setError(null);
82
- console.log('Initializing anonymous user with fingerprintId:', fingerprintId);
83
79
  const fingerprintHeaders = yield fingerprintClient.createFingerprintHeaders();
84
80
  const response = yield fetch(config.apiEndpoint, {
85
81
  method: 'POST',
@@ -91,10 +87,8 @@ function useFingerprint(config) {
91
87
  throw new Error(errorData.error || 'Failed to initialize anonymous user');
92
88
  }
93
89
  const data = yield response.json();
94
- console.log('API response in initializeAnonymousUser:', data);
95
90
  if (data.success) {
96
91
  const updatedXUser = data.xUser || { userId: '', fingerprintId, clerkUserId: '', email: '', status: '', createdAt: '' };
97
- console.log('Setting xUser:', updatedXUser);
98
92
  setXUser(updatedXUser);
99
93
  setXCredit(data.xCredit || null);
100
94
  setXSubscription(data.xSubscription || null);
@@ -44,7 +44,6 @@ function useFingerprint(config) {
44
44
  // Capture first-touch as early as possible before any in-site navigation can overwrite context.
45
45
  getOrCreateFirstTouchData();
46
46
  const currentFingerprintId = yield getOrGenerateFingerprintId();
47
- console.log('Initialized fingerprintId:', currentFingerprintId);
48
47
  setFingerprintIdState(currentFingerprintId);
49
48
  return currentFingerprintId;
50
49
  }
@@ -65,11 +64,9 @@ function useFingerprint(config) {
65
64
  return;
66
65
  }
67
66
  if (isInitializingAnonymousUserRef.current) {
68
- console.log('Skipping anonymous user initialization because a request is already in flight:', fingerprintId);
69
67
  return;
70
68
  }
71
69
  if (requestedAnonymousFingerprintRef.current === fingerprintId && isInitialized) {
72
- console.log('Skipping anonymous user initialization because fingerprint is already initialized:', fingerprintId);
73
70
  return;
74
71
  }
75
72
  try {
@@ -77,7 +74,6 @@ function useFingerprint(config) {
77
74
  requestedAnonymousFingerprintRef.current = fingerprintId;
78
75
  setIsLoading(true);
79
76
  setError(null);
80
- console.log('Initializing anonymous user with fingerprintId:', fingerprintId);
81
77
  const fingerprintHeaders = yield createFingerprintHeaders();
82
78
  const response = yield fetch(config.apiEndpoint, {
83
79
  method: 'POST',
@@ -89,10 +85,8 @@ function useFingerprint(config) {
89
85
  throw new Error(errorData.error || 'Failed to initialize anonymous user');
90
86
  }
91
87
  const data = yield response.json();
92
- console.log('API response in initializeAnonymousUser:', data);
93
88
  if (data.success) {
94
89
  const updatedXUser = data.xUser || { userId: '', fingerprintId, clerkUserId: '', email: '', status: '', createdAt: '' };
95
- console.log('Setting xUser:', updatedXUser);
96
90
  setXUser(updatedXUser);
97
91
  setXCredit(data.xCredit || null);
98
92
  setXSubscription(data.xSubscription || null);
@@ -27,15 +27,6 @@ function SignInWithFingerprint() {
27
27
  initializeAnonymousUser();
28
28
  }
29
29
  }, [fingerprintId, isInitialized, initializeAnonymousUser]);
30
- // 调试日志和处理登录逻辑
31
- React.useEffect(() => {
32
- console.log('SignInWithFingerprint on [redirect] DEBUG:', {
33
- fingerprintProvider: fingerprintContext ? 'Available' : 'Not found',
34
- fingerprintId: fingerprintId || 'Not generated',
35
- xUser: xUser ? 'Initialized' : 'Not initialized',
36
- clerkMetadata: unsafeMetadata
37
- });
38
- }, [xUser, fingerprintId, fingerprintContext, unsafeMetadata]);
39
30
  return jsxRuntime.jsx(nextjs.SignIn, { unsafeMetadata: unsafeMetadata });
40
31
  }
41
32
 
@@ -25,15 +25,6 @@ function SignInWithFingerprint() {
25
25
  initializeAnonymousUser();
26
26
  }
27
27
  }, [fingerprintId, isInitialized, initializeAnonymousUser]);
28
- // 调试日志和处理登录逻辑
29
- useEffect(() => {
30
- console.log('SignInWithFingerprint on [redirect] DEBUG:', {
31
- fingerprintProvider: fingerprintContext ? 'Available' : 'Not found',
32
- fingerprintId: fingerprintId || 'Not generated',
33
- xUser: xUser ? 'Initialized' : 'Not initialized',
34
- clerkMetadata: unsafeMetadata
35
- });
36
- }, [xUser, fingerprintId, fingerprintContext, unsafeMetadata]);
37
28
  return jsx(SignIn, { unsafeMetadata: unsafeMetadata });
38
29
  }
39
30
 
@@ -28,27 +28,11 @@ function SignUpButtonWithFingerprint({ mode, signUp, }) {
28
28
  initializeAnonymousUser();
29
29
  }
30
30
  }, [fingerprintId, isInitialized, initializeAnonymousUser]);
31
- // 调试日志和处理注册逻辑
32
- React.useEffect(() => {
33
- console.log('SignUpWithFingerprint on [modal] DEBUG:', {
34
- fingerprintProvider: fingerprintContext ? 'Available' : 'Not found',
35
- fingerprintId: fingerprintId || 'Not generated',
36
- xUser: xUser ? 'Initialized' : 'Not initialized',
37
- clerkMetadata: unsafeMetadata
38
- });
39
- }, [xUser, fingerprintId, fingerprintContext, unsafeMetadata]);
40
31
  const { openSignUp } = nextjs.useClerk();
41
32
  const handleClick = () => {
42
33
  openSignUp({
43
34
  unsafeMetadata,
44
35
  });
45
- // 记录日志
46
- console.log('SignUpButton on [modal] clicked', {
47
- timestamp: new Date().toISOString(),
48
- mode,
49
- userId,
50
- fingerprintId
51
- });
52
36
  };
53
37
  return (jsxRuntime.jsx("button", { className: "w-16 sm:w-20 h-8 sm:h-9 px-1.5 sm:px-2 border border-gray-300 rounded-full hover:bg-gray-100 dark:border-gray-600 dark:hover:bg-gray-800 text-center text-xs sm:text-sm whitespace-nowrap", onClick: handleClick, children: signUp }));
54
38
  }
@@ -26,27 +26,11 @@ function SignUpButtonWithFingerprint({ mode, signUp, }) {
26
26
  initializeAnonymousUser();
27
27
  }
28
28
  }, [fingerprintId, isInitialized, initializeAnonymousUser]);
29
- // 调试日志和处理注册逻辑
30
- useEffect(() => {
31
- console.log('SignUpWithFingerprint on [modal] DEBUG:', {
32
- fingerprintProvider: fingerprintContext ? 'Available' : 'Not found',
33
- fingerprintId: fingerprintId || 'Not generated',
34
- xUser: xUser ? 'Initialized' : 'Not initialized',
35
- clerkMetadata: unsafeMetadata
36
- });
37
- }, [xUser, fingerprintId, fingerprintContext, unsafeMetadata]);
38
29
  const { openSignUp } = useClerk();
39
30
  const handleClick = () => {
40
31
  openSignUp({
41
32
  unsafeMetadata,
42
33
  });
43
- // 记录日志
44
- console.log('SignUpButton on [modal] clicked', {
45
- timestamp: new Date().toISOString(),
46
- mode,
47
- userId,
48
- fingerprintId
49
- });
50
34
  };
51
35
  return (jsx("button", { className: "w-16 sm:w-20 h-8 sm:h-9 px-1.5 sm:px-2 border border-gray-300 rounded-full hover:bg-gray-100 dark:border-gray-600 dark:hover:bg-gray-800 text-center text-xs sm:text-sm whitespace-nowrap", onClick: handleClick, children: signUp }));
52
36
  }
@@ -27,15 +27,6 @@ function SignUpWithFingerprint() {
27
27
  initializeAnonymousUser();
28
28
  }
29
29
  }, [fingerprintId, isInitialized, initializeAnonymousUser]);
30
- // 调试日志和处理注册逻辑
31
- React.useEffect(() => {
32
- console.log('SignUpWithFingerprint on [redirect] DEBUG:', {
33
- fingerprintProvider: fingerprintContext ? 'Available' : 'Not found',
34
- fingerprintId: fingerprintId || 'Not generated',
35
- xUser: xUser ? 'Initialized' : 'Not initialized',
36
- clerkMetadata: unsafeMetadata
37
- });
38
- }, [xUser, fingerprintId, fingerprintContext, unsafeMetadata]);
39
30
  return jsxRuntime.jsx(nextjs.SignUp, { unsafeMetadata: unsafeMetadata });
40
31
  }
41
32
 
@@ -25,15 +25,6 @@ function SignUpWithFingerprint() {
25
25
  initializeAnonymousUser();
26
26
  }
27
27
  }, [fingerprintId, isInitialized, initializeAnonymousUser]);
28
- // 调试日志和处理注册逻辑
29
- useEffect(() => {
30
- console.log('SignUpWithFingerprint on [redirect] DEBUG:', {
31
- fingerprintProvider: fingerprintContext ? 'Available' : 'Not found',
32
- fingerprintId: fingerprintId || 'Not generated',
33
- xUser: xUser ? 'Initialized' : 'Not initialized',
34
- clerkMetadata: unsafeMetadata
35
- });
36
- }, [xUser, fingerprintId, fingerprintContext, unsafeMetadata]);
37
28
  return jsx(SignUp, { unsafeMetadata: unsafeMetadata });
38
29
  }
39
30