@windrun-huaiin/third-ui 11.0.4 → 11.0.6

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.
@@ -5,10 +5,11 @@ export interface GradientButtonProps {
5
5
  align?: 'left' | 'center' | 'right';
6
6
  disabled?: boolean;
7
7
  className?: string;
8
+ iconSizeValue?: number;
8
9
  href?: string;
9
10
  openInNewTab?: boolean;
10
11
  onClick?: () => void | Promise<void>;
11
12
  loadingText?: React.ReactNode;
12
13
  preventDoubleClick?: boolean;
13
14
  }
14
- export declare function GradientButton({ title, icon, align, disabled, className, href, openInNewTab, onClick, loadingText, preventDoubleClick, }: GradientButtonProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function GradientButton({ title, icon, align, disabled, className, href, openInNewTab, onClick, loadingText, preventDoubleClick, iconSizeValue, }: GradientButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -9,9 +9,12 @@ var server = require('@windrun-huaiin/base-ui/components/server');
9
9
  var Link = require('next/link');
10
10
  var React = require('react');
11
11
 
12
- function GradientButton({ title, icon, align = 'left', disabled = false, className = "", href, openInNewTab = true, onClick, loadingText, preventDoubleClick = true, }) {
12
+ function GradientButton({ title, icon, align = 'left', disabled = false, className = "", href, openInNewTab = true, onClick, loadingText, preventDoubleClick = true, iconSizeValue, }) {
13
13
  const [isLoading, setIsLoading] = React.useState(false);
14
14
  const actualLoadingText = loadingText || (title === null || title === void 0 ? void 0 : title.toString().trim()) || 'Loading...';
15
+ const iconSizeClass = (iconSizeValue && Number.isInteger(iconSizeValue) && iconSizeValue > 0)
16
+ ? `h-${iconSizeValue} w-${iconSizeValue}`
17
+ : 'h-4 w-4';
15
18
  // set justify class according to alignment
16
19
  const getAlignmentClass = () => {
17
20
  switch (align) {
@@ -52,7 +55,7 @@ function GradientButton({ title, icon, align = 'left', disabled = false, classNa
52
55
  const iconProvided = icon !== undefined;
53
56
  const iconNode = (() => {
54
57
  if (isLoading) {
55
- return jsxRuntime.jsx(server.globalLucideIcons.Loader2, { className: "h-4 w-4 text-white animate-spin" });
58
+ return jsxRuntime.jsx(server.globalLucideIcons.Loader2, { className: utils.cn(iconSizeClass, 'text-white animate-spin') });
56
59
  }
57
60
  if (iconProvided) {
58
61
  if (icon === null || icon === false) {
@@ -60,12 +63,12 @@ function GradientButton({ title, icon, align = 'left', disabled = false, classNa
60
63
  }
61
64
  if (React.isValidElement(icon)) {
62
65
  return React.cloneElement(icon, {
63
- className: utils.cn('h-4 w-4 text-white', icon.props.className),
66
+ className: utils.cn(iconSizeClass, 'text-white', icon.props.className),
64
67
  });
65
68
  }
66
69
  return icon;
67
70
  }
68
- return jsxRuntime.jsx(server.globalLucideIcons.ArrowRight, { className: "h-4 w-4 text-white" });
71
+ return jsxRuntime.jsx(server.globalLucideIcons.ArrowRight, { className: utils.cn(iconSizeClass, 'text-white') });
69
72
  })();
70
73
  const shouldRenderIcon = iconNode !== null && iconNode !== undefined;
71
74
  const buttonContent = onClick ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [shouldRenderIcon ? jsxRuntime.jsx("span", { children: iconNode }) : null, jsxRuntime.jsx("span", { className: utils.cn(shouldRenderIcon && 'ml-1'), children: displayTitle })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { children: displayTitle }), shouldRenderIcon ? jsxRuntime.jsx("span", { className: "ml-1", children: iconNode }) : null] }));
@@ -7,9 +7,12 @@ import { globalLucideIcons } from '@windrun-huaiin/base-ui/components/server';
7
7
  import Link from 'next/link';
8
8
  import React, { useState } from 'react';
9
9
 
10
- function GradientButton({ title, icon, align = 'left', disabled = false, className = "", href, openInNewTab = true, onClick, loadingText, preventDoubleClick = true, }) {
10
+ function GradientButton({ title, icon, align = 'left', disabled = false, className = "", href, openInNewTab = true, onClick, loadingText, preventDoubleClick = true, iconSizeValue, }) {
11
11
  const [isLoading, setIsLoading] = useState(false);
12
12
  const actualLoadingText = loadingText || (title === null || title === void 0 ? void 0 : title.toString().trim()) || 'Loading...';
13
+ const iconSizeClass = (iconSizeValue && Number.isInteger(iconSizeValue) && iconSizeValue > 0)
14
+ ? `h-${iconSizeValue} w-${iconSizeValue}`
15
+ : 'h-4 w-4';
13
16
  // set justify class according to alignment
14
17
  const getAlignmentClass = () => {
15
18
  switch (align) {
@@ -50,7 +53,7 @@ function GradientButton({ title, icon, align = 'left', disabled = false, classNa
50
53
  const iconProvided = icon !== undefined;
51
54
  const iconNode = (() => {
52
55
  if (isLoading) {
53
- return jsx(globalLucideIcons.Loader2, { className: "h-4 w-4 text-white animate-spin" });
56
+ return jsx(globalLucideIcons.Loader2, { className: cn(iconSizeClass, 'text-white animate-spin') });
54
57
  }
55
58
  if (iconProvided) {
56
59
  if (icon === null || icon === false) {
@@ -58,12 +61,12 @@ function GradientButton({ title, icon, align = 'left', disabled = false, classNa
58
61
  }
59
62
  if (React.isValidElement(icon)) {
60
63
  return React.cloneElement(icon, {
61
- className: cn('h-4 w-4 text-white', icon.props.className),
64
+ className: cn(iconSizeClass, 'text-white', icon.props.className),
62
65
  });
63
66
  }
64
67
  return icon;
65
68
  }
66
- return jsx(globalLucideIcons.ArrowRight, { className: "h-4 w-4 text-white" });
69
+ return jsx(globalLucideIcons.ArrowRight, { className: cn(iconSizeClass, 'text-white') });
67
70
  })();
68
71
  const shouldRenderIcon = iconNode !== null && iconNode !== undefined;
69
72
  const buttonContent = onClick ? (jsxs(Fragment, { children: [shouldRenderIcon ? jsx("span", { children: iconNode }) : null, jsx("span", { className: cn(shouldRenderIcon && 'ml-1'), children: displayTitle })] })) : (jsxs(Fragment, { children: [jsx("span", { children: displayTitle }), shouldRenderIcon ? jsx("span", { className: "ml-1", children: iconNode }) : null] }));
@@ -18,6 +18,7 @@ interface SingleButtonProps {
18
18
  loadingText?: string;
19
19
  minWidth?: string;
20
20
  className?: string;
21
+ iconSizeValue?: number;
21
22
  }
22
23
  interface SplitButtonProps {
23
24
  type: 'split';
@@ -28,6 +29,7 @@ interface SplitButtonProps {
28
29
  className?: string;
29
30
  mainButtonClassName?: string;
30
31
  dropdownButtonClassName?: string;
32
+ iconSizeValue?: number;
31
33
  }
32
34
  type xButtonProps = SingleButtonProps | SplitButtonProps;
33
35
  export declare function XButton(props: xButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -12,6 +12,14 @@ function XButton(props) {
12
12
  const [isLoading, setIsLoading] = React.useState(false);
13
13
  const [menuOpen, setMenuOpen] = React.useState(false);
14
14
  const menuRef = React.useRef(null);
15
+ const { iconSizeValue } = props;
16
+ const isCustomSize = iconSizeValue && Number.isInteger(iconSizeValue) && iconSizeValue > 0;
17
+ const loadingIconClass = isCustomSize
18
+ ? `w-${iconSizeValue} h-${iconSizeValue} mr-1 animate-spin`
19
+ : "w-5 h-5 mr-1 animate-spin";
20
+ const chevronIconClass = isCustomSize
21
+ ? `w-${iconSizeValue + 1} h-${iconSizeValue + 1}`
22
+ : "w-6 h-6";
15
23
  // click outside to close menu
16
24
  React.useEffect(() => {
17
25
  if (props.type === 'split') {
@@ -51,15 +59,15 @@ function XButton(props) {
51
59
  const isDisabled = button.disabled || isLoading;
52
60
  // loadingText: props.loadingText > button.text > 'Loading...'
53
61
  const actualLoadingText = loadingText || ((_a = button.text) === null || _a === void 0 ? void 0 : _a.trim()) || 'Loading...';
54
- return (jsxRuntime.jsx("button", { onClick: () => handleButtonClick(button.onClick), disabled: isDisabled, className: utils.cn("w-full sm:w-auto", minWidth, baseButtonClass, "rounded-full", isDisabled && disabledClass, className), title: button.text, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(server.globalLucideIcons.Loader2, { className: "w-5 h-5 mr-1 animate-spin" }), jsxRuntime.jsx("span", { children: actualLoadingText })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [button.icon, jsxRuntime.jsx("span", { children: button.text })] })) }));
62
+ return (jsxRuntime.jsx("button", { onClick: () => handleButtonClick(button.onClick), disabled: isDisabled, className: utils.cn("w-full sm:w-auto", minWidth, baseButtonClass, "rounded-full", isDisabled && disabledClass, className), title: button.text, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(server.globalLucideIcons.Loader2, { className: loadingIconClass }), jsxRuntime.jsx("span", { children: actualLoadingText })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [button.icon, jsxRuntime.jsx("span", { children: button.text })] })) }));
55
63
  }
56
64
  // Split button
57
65
  const { mainButton, menuItems, loadingText, menuWidth = 'w-full sm:w-40', className = '', mainButtonClassName = '', dropdownButtonClassName = '' } = props;
58
66
  const isMainDisabled = mainButton.disabled || isLoading;
59
67
  // loadingText prioty:props.loadingText > mainButton.text > 'Loading...'
60
68
  const actualLoadingText = loadingText || ((_b = mainButton.text) === null || _b === void 0 ? void 0 : _b.trim()) || 'Loading...';
61
- return (jsxRuntime.jsxs("div", { className: utils.cn("relative flex flex-col sm:flex-row items-stretch w-full sm:w-auto bg-neutral-200 dark:bg-neutral-800 rounded-2xl sm:rounded-full gap-2 sm:gap-0", className), children: [jsxRuntime.jsx("button", { onClick: () => handleButtonClick(mainButton.onClick), disabled: isMainDisabled, className: utils.cn("flex-1 w-full", baseButtonClass, "rounded-full sm:rounded-l-full sm:rounded-r-none", isMainDisabled && disabledClass, mainButtonClassName), onMouseDown: e => { if (e.button === 2)
62
- e.preventDefault(); }, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(server.globalLucideIcons.Loader2, { className: "w-5 h-5 mr-1 animate-spin" }), jsxRuntime.jsx("span", { children: actualLoadingText })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [mainButton.icon, jsxRuntime.jsx("span", { children: mainButton.text })] })) }), jsxRuntime.jsx("button", { type: "button", className: utils.cn("flex items-center justify-center w-full sm:w-10 py-2 bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-white cursor-pointer transition hover:bg-neutral-300 dark:hover:bg-neutral-700 rounded-full sm:rounded-none sm:rounded-r-full sm:border-l sm:border-neutral-300 sm:dark:border-neutral-700", dropdownButtonClassName), onClick: e => { e.stopPropagation(); setMenuOpen(v => !v); }, "aria-label": "More actions", "aria-expanded": menuOpen, children: jsxRuntime.jsx(server.globalLucideIcons.ChevronDown, { className: "w-6 h-6" }) }), menuOpen && (jsxRuntime.jsx("div", { ref: menuRef, className: `absolute left-0 top-full sm:left-auto sm:right-0 ${menuWidth} bg-white dark:bg-neutral-800 text-neutral-800 dark:text-white text-sm rounded-xl shadow-lg z-50 border border-neutral-200 dark:border-neutral-700 overflow-hidden animate-fade-in`, children: menuItems.map((item, index) => (jsxRuntime.jsxs("button", { onClick: () => {
69
+ return (jsxRuntime.jsxs("div", { className: utils.cn("relative flex flex-col sm:flex-row items-stretch w-full sm:w-auto bg-neutral-200 dark:bg-neutral-800 rounded-full gap-2 sm:gap-0", className), children: [jsxRuntime.jsx("button", { onClick: () => handleButtonClick(mainButton.onClick), disabled: isMainDisabled, className: utils.cn("flex-1 w-full", baseButtonClass, "rounded-full sm:rounded-l-full sm:rounded-r-none", isMainDisabled && disabledClass, mainButtonClassName), onMouseDown: e => { if (e.button === 2)
70
+ e.preventDefault(); }, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(server.globalLucideIcons.Loader2, { className: loadingIconClass }), jsxRuntime.jsx("span", { children: actualLoadingText })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [mainButton.icon, jsxRuntime.jsx("span", { children: mainButton.text })] })) }), jsxRuntime.jsx("button", { type: "button", className: utils.cn("flex items-center justify-center w-full sm:w-10 py-1.5 bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-white cursor-pointer transition hover:bg-neutral-300 dark:hover:bg-neutral-700 rounded-full sm:rounded-none sm:rounded-r-full sm:border-l sm:border-neutral-300 sm:dark:border-neutral-700", dropdownButtonClassName), onClick: e => { e.stopPropagation(); setMenuOpen(v => !v); }, "aria-label": "More actions", "aria-expanded": menuOpen, children: jsxRuntime.jsx(server.globalLucideIcons.ChevronDown, { 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-50 border border-neutral-200 dark:border-neutral-700 overflow-hidden animate-fade-in`, children: menuItems.map((item, index) => (jsxRuntime.jsxs("button", { onClick: () => {
63
71
  handleButtonClick(item.onClick);
64
72
  setMenuOpen(false);
65
73
  }, 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))) }))] }));
@@ -10,6 +10,14 @@ function XButton(props) {
10
10
  const [isLoading, setIsLoading] = useState(false);
11
11
  const [menuOpen, setMenuOpen] = useState(false);
12
12
  const menuRef = useRef(null);
13
+ const { iconSizeValue } = props;
14
+ const isCustomSize = iconSizeValue && Number.isInteger(iconSizeValue) && iconSizeValue > 0;
15
+ const loadingIconClass = isCustomSize
16
+ ? `w-${iconSizeValue} h-${iconSizeValue} mr-1 animate-spin`
17
+ : "w-5 h-5 mr-1 animate-spin";
18
+ const chevronIconClass = isCustomSize
19
+ ? `w-${iconSizeValue + 1} h-${iconSizeValue + 1}`
20
+ : "w-6 h-6";
13
21
  // click outside to close menu
14
22
  useEffect(() => {
15
23
  if (props.type === 'split') {
@@ -49,15 +57,15 @@ function XButton(props) {
49
57
  const isDisabled = button.disabled || isLoading;
50
58
  // loadingText: props.loadingText > button.text > 'Loading...'
51
59
  const actualLoadingText = loadingText || ((_a = button.text) === null || _a === void 0 ? void 0 : _a.trim()) || 'Loading...';
52
- return (jsx("button", { onClick: () => handleButtonClick(button.onClick), disabled: isDisabled, className: cn("w-full sm:w-auto", minWidth, baseButtonClass, "rounded-full", isDisabled && disabledClass, className), title: button.text, children: isLoading ? (jsxs(Fragment, { children: [jsx(globalLucideIcons.Loader2, { className: "w-5 h-5 mr-1 animate-spin" }), jsx("span", { children: actualLoadingText })] })) : (jsxs(Fragment, { children: [button.icon, jsx("span", { children: button.text })] })) }));
60
+ return (jsx("button", { onClick: () => handleButtonClick(button.onClick), disabled: isDisabled, className: cn("w-full sm:w-auto", minWidth, baseButtonClass, "rounded-full", isDisabled && disabledClass, className), title: button.text, children: isLoading ? (jsxs(Fragment, { children: [jsx(globalLucideIcons.Loader2, { className: loadingIconClass }), jsx("span", { children: actualLoadingText })] })) : (jsxs(Fragment, { children: [button.icon, jsx("span", { children: button.text })] })) }));
53
61
  }
54
62
  // Split button
55
63
  const { mainButton, menuItems, loadingText, menuWidth = 'w-full sm:w-40', className = '', mainButtonClassName = '', dropdownButtonClassName = '' } = props;
56
64
  const isMainDisabled = mainButton.disabled || isLoading;
57
65
  // loadingText prioty:props.loadingText > mainButton.text > 'Loading...'
58
66
  const actualLoadingText = loadingText || ((_b = mainButton.text) === null || _b === void 0 ? void 0 : _b.trim()) || 'Loading...';
59
- return (jsxs("div", { className: cn("relative flex flex-col sm:flex-row items-stretch w-full sm:w-auto bg-neutral-200 dark:bg-neutral-800 rounded-2xl sm:rounded-full gap-2 sm:gap-0", className), children: [jsx("button", { onClick: () => handleButtonClick(mainButton.onClick), disabled: isMainDisabled, className: cn("flex-1 w-full", baseButtonClass, "rounded-full sm:rounded-l-full sm:rounded-r-none", isMainDisabled && disabledClass, mainButtonClassName), onMouseDown: e => { if (e.button === 2)
60
- e.preventDefault(); }, children: isLoading ? (jsxs(Fragment, { children: [jsx(globalLucideIcons.Loader2, { className: "w-5 h-5 mr-1 animate-spin" }), jsx("span", { children: actualLoadingText })] })) : (jsxs(Fragment, { children: [mainButton.icon, jsx("span", { children: mainButton.text })] })) }), jsx("button", { type: "button", className: cn("flex items-center justify-center w-full sm:w-10 py-2 bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-white cursor-pointer transition hover:bg-neutral-300 dark:hover:bg-neutral-700 rounded-full sm:rounded-none sm:rounded-r-full sm:border-l sm:border-neutral-300 sm:dark:border-neutral-700", dropdownButtonClassName), onClick: e => { e.stopPropagation(); setMenuOpen(v => !v); }, "aria-label": "More actions", "aria-expanded": menuOpen, children: jsx(globalLucideIcons.ChevronDown, { className: "w-6 h-6" }) }), menuOpen && (jsx("div", { ref: menuRef, className: `absolute left-0 top-full sm:left-auto sm:right-0 ${menuWidth} bg-white dark:bg-neutral-800 text-neutral-800 dark:text-white text-sm rounded-xl shadow-lg z-50 border border-neutral-200 dark:border-neutral-700 overflow-hidden animate-fade-in`, children: menuItems.map((item, index) => (jsxs("button", { onClick: () => {
67
+ return (jsxs("div", { className: cn("relative flex flex-col sm:flex-row items-stretch w-full sm:w-auto bg-neutral-200 dark:bg-neutral-800 rounded-full gap-2 sm:gap-0", className), children: [jsx("button", { onClick: () => handleButtonClick(mainButton.onClick), disabled: isMainDisabled, className: cn("flex-1 w-full", baseButtonClass, "rounded-full sm:rounded-l-full sm:rounded-r-none", isMainDisabled && disabledClass, mainButtonClassName), onMouseDown: e => { if (e.button === 2)
68
+ e.preventDefault(); }, children: isLoading ? (jsxs(Fragment, { children: [jsx(globalLucideIcons.Loader2, { className: loadingIconClass }), jsx("span", { children: actualLoadingText })] })) : (jsxs(Fragment, { children: [mainButton.icon, jsx("span", { children: mainButton.text })] })) }), jsx("button", { type: "button", className: cn("flex items-center justify-center w-full sm:w-10 py-1.5 bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-white cursor-pointer transition hover:bg-neutral-300 dark:hover:bg-neutral-700 rounded-full sm:rounded-none sm:rounded-r-full sm:border-l sm:border-neutral-300 sm:dark:border-neutral-700", dropdownButtonClassName), onClick: e => { e.stopPropagation(); setMenuOpen(v => !v); }, "aria-label": "More actions", "aria-expanded": menuOpen, children: jsx(globalLucideIcons.ChevronDown, { className: chevronIconClass }) }), menuOpen && (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-50 border border-neutral-200 dark:border-neutral-700 overflow-hidden animate-fade-in`, children: menuItems.map((item, index) => (jsxs("button", { onClick: () => {
61
69
  handleButtonClick(item.onClick);
62
70
  setMenuOpen(false);
63
71
  }, 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: [jsxs("span", { className: "flex items-center", children: [item.icon, jsx("span", { children: item.text })] }), item.tag && (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))) }))] }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/third-ui",
3
- "version": "11.0.4",
3
+ "version": "11.0.6",
4
4
  "description": "Third-party integrated UI components for windrun-huaiin projects",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -12,6 +12,7 @@ export interface GradientButtonProps {
12
12
  align?: 'left' | 'center' | 'right';
13
13
  disabled?: boolean;
14
14
  className?: string;
15
+ iconSizeValue?: number;
15
16
  // for Link
16
17
  href?: string;
17
18
  openInNewTab?: boolean;
@@ -33,10 +34,15 @@ export function GradientButton({
33
34
  onClick,
34
35
  loadingText,
35
36
  preventDoubleClick = true,
37
+ iconSizeValue,
36
38
  }: GradientButtonProps) {
37
39
  const [isLoading, setIsLoading] = useState(false);
38
40
  const actualLoadingText = loadingText || title?.toString().trim() || 'Loading...'
39
41
 
42
+ const iconSizeClass = (iconSizeValue && Number.isInteger(iconSizeValue) && iconSizeValue > 0)
43
+ ? `h-${iconSizeValue} w-${iconSizeValue}`
44
+ : 'h-4 w-4';
45
+
40
46
  // set justify class according to alignment
41
47
  const getAlignmentClass = () => {
42
48
  switch (align) {
@@ -83,7 +89,7 @@ export function GradientButton({
83
89
 
84
90
  const iconNode = (() => {
85
91
  if (isLoading) {
86
- return <icons.Loader2 className="h-4 w-4 text-white animate-spin" />;
92
+ return <icons.Loader2 className={cn(iconSizeClass, 'text-white animate-spin')} />;
87
93
  }
88
94
 
89
95
  if (iconProvided) {
@@ -93,14 +99,14 @@ export function GradientButton({
93
99
 
94
100
  if (React.isValidElement<{ className?: string }>(icon)) {
95
101
  return React.cloneElement(icon, {
96
- className: cn('h-4 w-4 text-white', icon.props.className),
102
+ className: cn(iconSizeClass, 'text-white', icon.props.className),
97
103
  });
98
104
  }
99
105
 
100
106
  return icon;
101
107
  }
102
108
 
103
- return <icons.ArrowRight className="h-4 w-4 text-white" />;
109
+ return <icons.ArrowRight className={cn(iconSizeClass, 'text-white')} />;
104
110
  })();
105
111
 
106
112
  const shouldRenderIcon = iconNode !== null && iconNode !== undefined;
@@ -28,6 +28,7 @@ interface SingleButtonProps {
28
28
  loadingText?: string
29
29
  minWidth?: string
30
30
  className?: string
31
+ iconSizeValue?: number
31
32
  }
32
33
 
33
34
  // split button config
@@ -40,6 +41,7 @@ interface SplitButtonProps {
40
41
  className?: string
41
42
  mainButtonClassName?: string
42
43
  dropdownButtonClassName?: string
44
+ iconSizeValue?: number
43
45
  }
44
46
 
45
47
  type xButtonProps = SingleButtonProps | SplitButtonProps
@@ -49,6 +51,17 @@ export function XButton(props: xButtonProps) {
49
51
  const [menuOpen, setMenuOpen] = useState(false)
50
52
  const menuRef = useRef<HTMLDivElement>(null)
51
53
 
54
+ const { iconSizeValue } = props
55
+ const isCustomSize = iconSizeValue && Number.isInteger(iconSizeValue) && iconSizeValue > 0
56
+
57
+ const loadingIconClass = isCustomSize
58
+ ? `w-${iconSizeValue} h-${iconSizeValue} mr-1 animate-spin`
59
+ : "w-5 h-5 mr-1 animate-spin"
60
+
61
+ const chevronIconClass = isCustomSize
62
+ ? `w-${iconSizeValue + 1} h-${iconSizeValue + 1}`
63
+ : "w-6 h-6"
64
+
52
65
  // click outside to close menu
53
66
  useEffect(() => {
54
67
  if (props.type === 'split') {
@@ -108,7 +121,7 @@ export function XButton(props: xButtonProps) {
108
121
  >
109
122
  {isLoading ? (
110
123
  <>
111
- <icons.Loader2 className="w-5 h-5 mr-1 animate-spin" />
124
+ <icons.Loader2 className={loadingIconClass} />
112
125
  <span>{actualLoadingText}</span>
113
126
  </>
114
127
  ) : (
@@ -129,7 +142,7 @@ export function XButton(props: xButtonProps) {
129
142
 
130
143
  return (
131
144
  <div className={cn(
132
- "relative flex flex-col sm:flex-row items-stretch w-full sm:w-auto bg-neutral-200 dark:bg-neutral-800 rounded-2xl sm:rounded-full gap-2 sm:gap-0",
145
+ "relative flex flex-col sm:flex-row items-stretch w-full sm:w-auto bg-neutral-200 dark:bg-neutral-800 rounded-full gap-2 sm:gap-0",
133
146
  className
134
147
  )}>
135
148
  {/* left main button */}
@@ -147,7 +160,7 @@ export function XButton(props: xButtonProps) {
147
160
  >
148
161
  {isLoading ? (
149
162
  <>
150
- <icons.Loader2 className="w-5 h-5 mr-1 animate-spin" />
163
+ <icons.Loader2 className={loadingIconClass} />
151
164
  <span>{actualLoadingText}</span>
152
165
  </>
153
166
  ) : (
@@ -162,21 +175,21 @@ export function XButton(props: xButtonProps) {
162
175
  <button
163
176
  type="button"
164
177
  className={cn(
165
- "flex items-center justify-center w-full sm:w-10 py-2 bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-white cursor-pointer transition hover:bg-neutral-300 dark:hover:bg-neutral-700 rounded-full sm:rounded-none sm:rounded-r-full sm:border-l sm:border-neutral-300 sm:dark:border-neutral-700",
178
+ "flex items-center justify-center w-full sm:w-10 py-1.5 bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-white cursor-pointer transition hover:bg-neutral-300 dark:hover:bg-neutral-700 rounded-full sm:rounded-none sm:rounded-r-full sm:border-l sm:border-neutral-300 sm:dark:border-neutral-700",
166
179
  dropdownButtonClassName
167
180
  )}
168
181
  onClick={e => { e.stopPropagation(); setMenuOpen(v => !v) }}
169
182
  aria-label="More actions"
170
183
  aria-expanded={menuOpen}
171
184
  >
172
- <icons.ChevronDown className="w-6 h-6" />
185
+ <icons.ChevronDown className={chevronIconClass} />
173
186
  </button>
174
187
 
175
188
  {/* dropdown menu */}
176
189
  {menuOpen && (
177
190
  <div
178
191
  ref={menuRef}
179
- className={`absolute left-0 top-full sm:left-auto sm:right-0 ${menuWidth} bg-white dark:bg-neutral-800 text-neutral-800 dark:text-white text-sm rounded-xl shadow-lg z-50 border border-neutral-200 dark:border-neutral-700 overflow-hidden animate-fade-in`}
192
+ 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-50 border border-neutral-200 dark:border-neutral-700 overflow-hidden animate-fade-in`}
180
193
  >
181
194
  {menuItems.map((item, index) => (
182
195
  <button