@windrun-huaiin/third-ui 5.9.4 → 5.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/third-ui",
3
- "version": "5.9.4",
3
+ "version": "5.9.5",
4
4
  "description": "Third-party integrated UI components for windrun-huaiin projects",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -53,7 +53,7 @@
53
53
  "mermaid": "^11.6.0",
54
54
  "react-medium-image-zoom": "^5.2.14",
55
55
  "zod": "^3.22.4",
56
- "@windrun-huaiin/base-ui": "^5.3.2"
56
+ "@windrun-huaiin/base-ui": "^5.3.3"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "react": "19.1.0",
@@ -3,21 +3,41 @@
3
3
  import { Button } from "@base-ui/ui/button";
4
4
  import { globalLucideIcons as icons } from "@base-ui/components/global-icon";
5
5
  import Link from "next/link";
6
- import React from 'react';
6
+ import React, { useState } from 'react';
7
+
8
+ export interface GradientButtonProps {
9
+ title: React.ReactNode;
10
+ icon?: React.ReactNode;
11
+ align?: 'left' | 'center' | 'right';
12
+ disabled?: boolean;
13
+ className?: string;
14
+
15
+ // 跳转模式
16
+ href?: string;
17
+ openInNewTab?: boolean;
18
+
19
+ // 点击模式
20
+ onClick?: () => void | Promise<void>;
21
+
22
+ // 加载状态配置
23
+ loadingText?: React.ReactNode;
24
+ preventDoubleClick?: boolean;
25
+ }
7
26
 
8
27
  export function GradientButton({
9
28
  title,
10
29
  icon,
11
- href,
12
30
  align = 'left',
31
+ disabled = false,
32
+ className = "",
33
+ href,
13
34
  openInNewTab = true,
14
- }: {
15
- title: React.ReactNode;
16
- icon?: React.ReactNode;
17
- href: string;
18
- align?: 'left' | 'center' | 'right';
19
- openInNewTab?: boolean;
20
- }) {
35
+ onClick,
36
+ loadingText = "Loading...",
37
+ preventDoubleClick = true,
38
+ }: GradientButtonProps) {
39
+ const [isLoading, setIsLoading] = useState(false);
40
+
21
41
  // set justify class according to alignment
22
42
  const getAlignmentClass = () => {
23
43
  switch (align) {
@@ -30,39 +50,99 @@ export function GradientButton({
30
50
  }
31
51
  };
32
52
 
53
+ // 处理点击事件
54
+ const handleClick = async (e: React.MouseEvent) => {
55
+ if (disabled || isLoading) {
56
+ e.preventDefault();
57
+ return;
58
+ }
59
+
60
+ if (onClick) {
61
+ e.preventDefault();
62
+
63
+ if (preventDoubleClick) {
64
+ setIsLoading(true);
65
+ }
66
+
67
+ try {
68
+ await onClick();
69
+ } catch (error) {
70
+ console.error('GradientButton onClick error:', error);
71
+ } finally {
72
+ if (preventDoubleClick) {
73
+ setIsLoading(false);
74
+ }
75
+ }
76
+ }
77
+ };
78
+
79
+ // 按钮是否处于禁用状态
80
+ const isDisabled = disabled || isLoading;
81
+
82
+ // 显示的标题内容
83
+ const displayTitle = isLoading ? loadingText : title;
84
+
85
+ // 显示的图标
86
+ const displayIcon = isLoading ? (
87
+ <icons.Loader2 className="h-4 w-4 text-white animate-spin" />
88
+ ) : icon ? (
89
+ React.cloneElement(icon as React.ReactElement<{ className?: string }>, {
90
+ className: "h-4 w-4 text-white"
91
+ })
92
+ ) : (
93
+ <icons.ArrowRight className="h-4 w-4 text-white" />
94
+ );
95
+
96
+ const buttonContent = (
97
+ <>
98
+ <span>{displayTitle}</span>
99
+ <span className="ml-1">{displayIcon}</span>
100
+ </>
101
+ );
102
+
103
+ const buttonClassName = `
104
+ bg-gradient-to-r
105
+ from-purple-400 to-pink-500
106
+ hover:from-purple-500 hover:to-pink-600
107
+ dark:from-purple-500 dark:to-pink-600
108
+ dark:hover:from-purple-600 dark:hover:to-pink-700
109
+ text-white text-base font-bold shadow-lg hover:shadow-xl
110
+ transition-all duration-300
111
+ rounded-full
112
+ ${isDisabled ? 'opacity-50 cursor-not-allowed' : ''}
113
+ ${className}
114
+ `;
115
+
33
116
  return (
34
117
  <div className={`flex flex-col sm:flex-row gap-3 ${getAlignmentClass()}`}>
35
- <Button
36
- asChild
37
- size="lg"
38
- className="
39
- bg-gradient-to-r
40
- from-purple-400 to-pink-500
41
- hover:from-purple-500 hover:to-pink-600
42
- dark:from-purple-500 dark:to-pink-600
43
- dark:hover:from-purple-600 dark:hover:to-pink-700
44
- text-white text-base font-bold shadow-lg hover:shadow-xl
45
- transition-all duration-300
46
- rounded-full
47
- "
48
- >
49
- <Link
50
- href={href}
51
- className="no-underline hover:no-underline"
52
- {...(openInNewTab ? { target: "_blank", rel: "noopener noreferrer" } : {})}
118
+ {onClick ? (
119
+ // 点击模式
120
+ <Button
121
+ size="lg"
122
+ className={buttonClassName}
123
+ onClick={handleClick}
124
+ disabled={isDisabled}
125
+ >
126
+ {buttonContent}
127
+ </Button>
128
+ ) : (
129
+ // 跳转模式
130
+ <Button
131
+ asChild
132
+ size="lg"
133
+ className={buttonClassName}
134
+ disabled={isDisabled}
53
135
  >
54
- <span>{title}</span>
55
- <span className="ml-1">
56
- {icon ?
57
- React.cloneElement(icon as React.ReactElement<{ className?: string }>, {
58
- className: "h-4 w-4 text-white"
59
- }) :
60
- <icons.ArrowRight className="h-4 w-4 text-white" />
61
- }
62
- </span>
63
- </Link>
64
- </Button>
136
+ <Link
137
+ href={href || "#"}
138
+ className="no-underline hover:no-underline"
139
+ {...(openInNewTab ? { target: "_blank", rel: "noopener noreferrer" } : {})}
140
+ onClick={isDisabled ? (e) => e.preventDefault() : undefined}
141
+ >
142
+ {buttonContent}
143
+ </Link>
144
+ </Button>
145
+ )}
65
146
  </div>
66
-
67
147
  );
68
148
  }