@windrun-huaiin/third-ui 28.0.0 → 29.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,68 +0,0 @@
1
- 'use strict';
2
-
3
- var tslib = require('tslib');
4
- var server = require('@windrun-huaiin/base-ui/components/server');
5
- var source = require('@windrun-huaiin/fumadocs-local-md/server/source');
6
- var base = require('@windrun-huaiin/fumadocs-local-md/presets/fuma-docs/base');
7
- var fumaSchemaCheckUtil = require('./fuma-schema-check-util.js');
8
- var siteMdxBase = require('../fuma/server/site-mdx-base.js');
9
-
10
- function resolveLocalMdMode() {
11
- var _a;
12
- const enableDevRuntime = ((_a = process.env.LOCAL_MD_DEV_RUNTIME) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'true';
13
- if (process.env.NODE_ENV !== 'production' && enableDevRuntime) {
14
- return 'runtime';
15
- }
16
- return 'build';
17
- }
18
- function createSiteDocsI18nConfig(appConfig) {
19
- return {
20
- defaultLanguage: appConfig.i18n.defaultLocale,
21
- languages: appConfig.i18n.locales,
22
- hideLocale: appConfig.i18n.localePrefixAsNeeded ? 'default-locale' : 'never',
23
- };
24
- }
25
- function createSiteDocsHelper(options) {
26
- const { appConfig, sourceRootDir, appRoot = process.cwd(), sourceFeatures = [], mdxFeatures = [], additionalComponents, frontmatterSchema = fumaSchemaCheckUtil.createCommonDocsSchema(), metaSchema = fumaSchemaCheckUtil.createCommonMetaSchema(), } = options;
27
- const i18n = createSiteDocsI18nConfig(appConfig);
28
- const sharedConfig = {
29
- i18n,
30
- frontmatterSchema,
31
- metaSchema,
32
- sourceRootDir,
33
- appRoot,
34
- icon(icon) {
35
- return server.getGlobalIcon(icon, true);
36
- },
37
- };
38
- const buildConfig = Object.assign(Object.assign({}, sharedConfig), base.createFumaDocsBaseCompilerOptions({
39
- features: sourceFeatures,
40
- }));
41
- const sourceFactory = source.createConfiguredLocalMdSourceFactory(sharedConfig);
42
- const getMDXComponents = siteMdxBase.createSiteMdxComponents({
43
- baseOptions: {
44
- imageFallbackSrc: appConfig.style.placeHolder.image,
45
- cdnBaseUrl: appConfig.style.cdnBaseUrl,
46
- },
47
- features: mdxFeatures,
48
- additionalComponents: Object.assign(Object.assign({}, server.globalLucideIcons), additionalComponents),
49
- });
50
- function getContentSource(sourceKey, overrides) {
51
- return tslib.__awaiter(this, void 0, void 0, function* () {
52
- return sourceFactory.getCachedSource(sourceKey, Object.assign({ mode: resolveLocalMdMode() }, overrides));
53
- });
54
- }
55
- return {
56
- i18n,
57
- buildConfig,
58
- sourceFactory,
59
- getContentSource,
60
- getMDXComponents,
61
- useMDXComponents: getMDXComponents,
62
- createSourceSharedConfig() {
63
- return Object.assign({}, sharedConfig);
64
- },
65
- };
66
- }
67
-
68
- exports.createSiteDocsHelper = createSiteDocsHelper;
@@ -1,66 +0,0 @@
1
- import { __awaiter } from 'tslib';
2
- import { globalLucideIcons, getGlobalIcon } from '@windrun-huaiin/base-ui/components/server';
3
- import { createConfiguredLocalMdSourceFactory } from '@windrun-huaiin/fumadocs-local-md/server/source';
4
- import { createFumaDocsBaseCompilerOptions } from '@windrun-huaiin/fumadocs-local-md/presets/fuma-docs/base';
5
- import { createCommonMetaSchema, createCommonDocsSchema } from './fuma-schema-check-util.mjs';
6
- import { createSiteMdxComponents } from '../fuma/server/site-mdx-base.mjs';
7
-
8
- function resolveLocalMdMode() {
9
- var _a;
10
- const enableDevRuntime = ((_a = process.env.LOCAL_MD_DEV_RUNTIME) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'true';
11
- if (process.env.NODE_ENV !== 'production' && enableDevRuntime) {
12
- return 'runtime';
13
- }
14
- return 'build';
15
- }
16
- function createSiteDocsI18nConfig(appConfig) {
17
- return {
18
- defaultLanguage: appConfig.i18n.defaultLocale,
19
- languages: appConfig.i18n.locales,
20
- hideLocale: appConfig.i18n.localePrefixAsNeeded ? 'default-locale' : 'never',
21
- };
22
- }
23
- function createSiteDocsHelper(options) {
24
- const { appConfig, sourceRootDir, appRoot = process.cwd(), sourceFeatures = [], mdxFeatures = [], additionalComponents, frontmatterSchema = createCommonDocsSchema(), metaSchema = createCommonMetaSchema(), } = options;
25
- const i18n = createSiteDocsI18nConfig(appConfig);
26
- const sharedConfig = {
27
- i18n,
28
- frontmatterSchema,
29
- metaSchema,
30
- sourceRootDir,
31
- appRoot,
32
- icon(icon) {
33
- return getGlobalIcon(icon, true);
34
- },
35
- };
36
- const buildConfig = Object.assign(Object.assign({}, sharedConfig), createFumaDocsBaseCompilerOptions({
37
- features: sourceFeatures,
38
- }));
39
- const sourceFactory = createConfiguredLocalMdSourceFactory(sharedConfig);
40
- const getMDXComponents = createSiteMdxComponents({
41
- baseOptions: {
42
- imageFallbackSrc: appConfig.style.placeHolder.image,
43
- cdnBaseUrl: appConfig.style.cdnBaseUrl,
44
- },
45
- features: mdxFeatures,
46
- additionalComponents: Object.assign(Object.assign({}, globalLucideIcons), additionalComponents),
47
- });
48
- function getContentSource(sourceKey, overrides) {
49
- return __awaiter(this, void 0, void 0, function* () {
50
- return sourceFactory.getCachedSource(sourceKey, Object.assign({ mode: resolveLocalMdMode() }, overrides));
51
- });
52
- }
53
- return {
54
- i18n,
55
- buildConfig,
56
- sourceFactory,
57
- getContentSource,
58
- getMDXComponents,
59
- useMDXComponents: getMDXComponents,
60
- createSourceSharedConfig() {
61
- return Object.assign({}, sharedConfig);
62
- },
63
- };
64
- }
65
-
66
- export { createSiteDocsHelper };
@@ -1,72 +0,0 @@
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 {};
@@ -1,114 +0,0 @@
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;
@@ -1,112 +0,0 @@
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 };
@@ -1,39 +0,0 @@
1
- import { ReactNode } from 'react';
2
- type XButtonVariant = 'default' | 'soft' | 'subtle';
3
- interface BaseButtonConfig {
4
- icon: ReactNode;
5
- text: string;
6
- onClick: () => void | Promise<void>;
7
- disabled?: boolean;
8
- }
9
- interface MenuItemConfig extends BaseButtonConfig {
10
- tag?: {
11
- text: string;
12
- color?: string;
13
- };
14
- splitTopBorder?: boolean;
15
- }
16
- interface SingleButtonProps {
17
- type: 'single';
18
- button: BaseButtonConfig;
19
- loadingText?: string;
20
- minWidth?: string;
21
- className?: string;
22
- iconClassName?: string;
23
- variant?: XButtonVariant;
24
- }
25
- interface SplitButtonProps {
26
- type: 'split';
27
- mainButton: BaseButtonConfig;
28
- menuItems: MenuItemConfig[];
29
- loadingText?: string;
30
- menuWidth?: string;
31
- className?: string;
32
- mainButtonClassName?: string;
33
- dropdownButtonClassName?: string;
34
- iconClassName?: string;
35
- variant?: XButtonVariant;
36
- }
37
- type xButtonProps = SingleButtonProps | SplitButtonProps;
38
- export declare function XButton(props: xButtonProps): import("react/jsx-runtime").JSX.Element;
39
- export {};
@@ -1,102 +0,0 @@
1
- "use client";
2
- 'use strict';
3
-
4
- var tslib = require('tslib');
5
- var jsxRuntime = require('react/jsx-runtime');
6
- var React = require('react');
7
- var icons = require('@windrun-huaiin/base-ui/icons');
8
- var lib = require('@windrun-huaiin/base-ui/lib');
9
- var utils = require('@windrun-huaiin/lib/utils');
10
-
11
- function XButton(props) {
12
- var _a, _b, _c;
13
- const [isLoading, setIsLoading] = React.useState(false);
14
- const [menuOpen, setMenuOpen] = React.useState(false);
15
- const menuRef = React.useRef(null);
16
- const { iconClassName } = props;
17
- const defaultIconClass = "w-5 h-5";
18
- const variant = (_a = props.variant) !== null && _a !== void 0 ? _a : 'default';
19
- const finalIconClass = utils.cn(variant === 'default' ? '' : lib.themeIconColor, iconClassName || defaultIconClass);
20
- const loadingIconClass = utils.cn(finalIconClass, "mr-1 animate-spin");
21
- const chevronIconClass = "w-6 h-6";
22
- const renderIcon = (icon) => {
23
- if (React.isValidElement(icon)) {
24
- return React.cloneElement(icon, {
25
- className: utils.cn(finalIconClass, icon.props.className),
26
- });
27
- }
28
- return icon;
29
- };
30
- // click outside to close menu
31
- React.useEffect(() => {
32
- if (props.type === 'split') {
33
- const handleClickOutside = (event) => {
34
- if (menuRef.current && !menuRef.current.contains(event.target)) {
35
- setMenuOpen(false);
36
- }
37
- };
38
- if (menuOpen) {
39
- document.addEventListener('mousedown', handleClickOutside);
40
- }
41
- return () => {
42
- document.removeEventListener('mousedown', handleClickOutside);
43
- };
44
- }
45
- }, [menuOpen, props.type]);
46
- // handle button click
47
- const handleButtonClick = (onClick) => tslib.__awaiter(this, void 0, void 0, function* () {
48
- if (isLoading)
49
- return;
50
- setIsLoading(true);
51
- try {
52
- yield onClick();
53
- }
54
- catch (error) {
55
- console.error('Button click error:', error);
56
- }
57
- finally {
58
- setIsLoading(false);
59
- }
60
- });
61
- // base style class
62
- const baseButtonClass = "flex items-center justify-center gap-2 px-4 py-2 text-sm font-semibold transition-colors";
63
- const singleButtonVariantClass = variant === 'soft'
64
- ? utils.cn(lib.themeBgColor, lib.themeIconColor, lib.themeBorderColor, "border hover:brightness-95")
65
- : variant === 'subtle'
66
- ? utils.cn(lib.themeMainBgColor, lib.themeIconColor, "border border-neutral-200 hover:bg-neutral-50 dark:border-neutral-800 dark:hover:bg-neutral-800")
67
- : "bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-white hover:bg-neutral-300 dark:hover:bg-neutral-700";
68
- const splitMainButtonVariantClass = variant === 'soft'
69
- ? utils.cn("bg-transparent hover:bg-black/5 dark:hover:bg-white/5", lib.themeIconColor)
70
- : variant === 'subtle'
71
- ? utils.cn("bg-transparent hover:bg-neutral-50 dark:hover:bg-neutral-800", lib.themeIconColor)
72
- : "bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-white hover:bg-neutral-300 dark:hover:bg-neutral-700";
73
- const splitDropdownVariantClass = variant === 'soft'
74
- ? utils.cn("bg-transparent hover:bg-black/5 dark:hover:bg-white/5 sm:border-l", lib.themeIconColor, lib.themeBorderColor)
75
- : variant === 'subtle'
76
- ? utils.cn("bg-transparent hover:bg-neutral-50 dark:hover:bg-neutral-800 sm:border-l", lib.themeIconColor, "border-neutral-200 dark:border-neutral-800")
77
- : "bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-white hover:bg-neutral-300 dark:hover:bg-neutral-700 sm:border-l sm:border-neutral-300 sm:dark:border-neutral-700";
78
- const disabledClass = "opacity-60 cursor-not-allowed";
79
- if (props.type === 'single') {
80
- const { button, loadingText, minWidth = 'min-w-[110px]', className = '' } = props;
81
- const isDisabled = button.disabled || isLoading;
82
- // loadingText: props.loadingText > button.text > 'Loading...'
83
- const actualLoadingText = loadingText || ((_b = button.text) === null || _b === void 0 ? void 0 : _b.trim()) || 'Loading...';
84
- return (jsxRuntime.jsx("button", { onClick: () => handleButtonClick(button.onClick), disabled: isDisabled, className: utils.cn("w-full sm:w-auto", minWidth, baseButtonClass, singleButtonVariantClass, "rounded-full", isDisabled && disabledClass, className), title: button.text, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(icons.Loader2Icon, { className: loadingIconClass }), jsxRuntime.jsx("span", { children: actualLoadingText })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderIcon(button.icon), jsxRuntime.jsx("span", { children: button.text })] })) }));
85
- }
86
- // Split button
87
- const { mainButton, menuItems, loadingText, menuWidth = 'w-full sm:w-40', className = '', mainButtonClassName = '', dropdownButtonClassName = '' } = props;
88
- const isMainDisabled = mainButton.disabled || isLoading;
89
- // loadingText prioty:props.loadingText > mainButton.text > 'Loading...'
90
- const actualLoadingText = loadingText || ((_c = mainButton.text) === null || _c === void 0 ? void 0 : _c.trim()) || 'Loading...';
91
- return (jsxRuntime.jsxs("div", { className: utils.cn("relative flex flex-row items-stretch w-full sm:w-auto rounded-full gap-0", menuOpen && "z-90", variant === 'soft'
92
- ? utils.cn(lib.themeBgColor, lib.themeBorderColor, "border")
93
- : variant === 'subtle'
94
- ? utils.cn(lib.themeMainBgColor, "border border-neutral-200 dark:border-neutral-800")
95
- : "bg-neutral-200 dark:bg-neutral-800", className), children: [jsxRuntime.jsx("button", { onClick: () => handleButtonClick(mainButton.onClick), disabled: isMainDisabled, className: utils.cn("min-w-0 flex-1", baseButtonClass, splitMainButtonVariantClass, "rounded-l-full rounded-r-none", isMainDisabled && disabledClass, mainButtonClassName), onMouseDown: e => { if (e.button === 2)
96
- e.preventDefault(); }, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(icons.Loader2Icon, { className: loadingIconClass }), jsxRuntime.jsx("span", { children: actualLoadingText })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderIcon(mainButton.icon), jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: mainButton.text })] })) }), jsxRuntime.jsx("button", { type: "button", className: utils.cn("flex h-full w-9 shrink-0 items-center justify-center px-0 py-1.5 cursor-pointer transition rounded-r-full rounded-l-none border-l sm:w-10", splitDropdownVariantClass, dropdownButtonClassName), onClick: e => { e.stopPropagation(); setMenuOpen(v => !v); }, "aria-label": "More actions", "aria-expanded": menuOpen, children: jsxRuntime.jsx(icons.ChevronDownIcon, { className: chevronIconClass }) }), menuOpen && (jsxRuntime.jsx("div", { ref: menuRef, className: `absolute right-0 top-full ${menuWidth} bg-white dark:bg-neutral-800 text-neutral-800 dark:text-white text-sm rounded-xl shadow-lg z-100 border border-neutral-200 dark:border-neutral-700 overflow-hidden animate-fade-in`, children: menuItems.map((item, index) => (jsxRuntime.jsxs("button", { onClick: () => {
97
- handleButtonClick(item.onClick);
98
- setMenuOpen(false);
99
- }, disabled: item.disabled, className: `flex items-center w-full px-4 py-3 transition hover:bg-neutral-300 dark:hover:bg-neutral-600 text-left relative ${item.disabled ? disabledClass : ''}`, style: item.splitTopBorder ? { borderTop: '1px solid #AC62FD' } : undefined, children: [jsxRuntime.jsxs("span", { className: "flex items-center", children: [item.icon, jsxRuntime.jsx("span", { children: item.text })] }), item.tag && (jsxRuntime.jsx("span", { className: "absolute right-3 top-1 text-[10px] font-semibold", style: { color: item.tag.color || '#A855F7', pointerEvents: 'none' }, children: item.tag.text }))] }, index))) }))] }));
100
- }
101
-
102
- exports.XButton = XButton;