best-unit 1.2.17 → 1.2.19
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/dist/best-unit.cjs +1 -1
- package/dist/best-unit.js +1 -1
- package/package.json +4 -1
- package/BEST_UNIT_USAGE.md +0 -402
- package/index.html +0 -13
- package/src/api/axiosInstance.ts +0 -111
- package/src/api/index.ts +0 -136
- package/src/api/proxy.ts +0 -11
- package/src/components/business/recharge-sdk/components/offline-transfer-form/index.tsx +0 -158
- package/src/components/business/recharge-sdk/components/offline-transfer-form/theme.tsx +0 -238
- package/src/components/business/recharge-sdk/components/online-recharge-form/index.tsx +0 -199
- package/src/components/business/recharge-sdk/components/online-recharge-form/theme.tsx +0 -151
- package/src/components/business/recharge-sdk/components/recharge/index.tsx +0 -152
- package/src/components/business/recharge-sdk/components/recharge/theme.tsx +0 -64
- package/src/components/business/recharge-sdk/index.tsx +0 -37
- package/src/components/business/refresh-button/index.tsx +0 -99
- package/src/components/business/refresh-button/theme.tsx +0 -58
- package/src/components/business/statistical-balance/index.tsx +0 -190
- package/src/components/business/statistical-balance/theme.tsx +0 -110
- package/src/components/common/button/index.tsx +0 -17
- package/src/components/common/button/theme.tsx +0 -48
- package/src/components/common/hover-popover/index.tsx +0 -179
- package/src/components/common/hover-popover/theme.tsx +0 -39
- package/src/components/common/message/index.tsx +0 -321
- package/src/components/common/message/theme.tsx +0 -25
- package/src/components/common/modal/index.tsx +0 -99
- package/src/components/common/modal/theme.tsx +0 -91
- package/src/components/common/select/index.tsx +0 -229
- package/src/components/common/select/theme.tsx +0 -104
- package/src/components/common/upload/index.tsx +0 -140
- package/src/components/common/upload/theme.tsx +0 -89
- package/src/demo/App.tsx +0 -685
- package/src/demo/index.tsx +0 -4
- package/src/demo/testBalanceData.tsx +0 -79
- package/src/demo/theme-config-example.tsx +0 -1
- package/src/local/en.ts +0 -63
- package/src/local/index.ts +0 -36
- package/src/local/zh.ts +0 -62
- package/src/main.ts +0 -26
- package/src/types/global.d.ts +0 -146
- package/src/types/index.ts +0 -31
- package/src/types/preact-custom-element.d.ts +0 -1
- package/src/utils/business/index.ts +0 -132
- package/src/utils/common/index.ts +0 -8
- package/src/vite-env.d.ts +0 -8
- package/tsconfig.app.json +0 -33
- package/tsconfig.json +0 -15
- package/tsconfig.node.json +0 -24
- package/vite.config.ts +0 -24
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { Theme } from "@/types";
|
|
2
|
-
import { getInitParams } from "@/utils/business";
|
|
3
|
-
|
|
4
|
-
export const refreshButtonThemes = {
|
|
5
|
-
white: {
|
|
6
|
-
background: "#1890ff",
|
|
7
|
-
color: "#fff",
|
|
8
|
-
border: "none",
|
|
9
|
-
borderRadius: 6,
|
|
10
|
-
cursor: "pointer",
|
|
11
|
-
fontWeight: 600,
|
|
12
|
-
transition: "all 0.2s ease",
|
|
13
|
-
},
|
|
14
|
-
dark: {
|
|
15
|
-
background: "#00E8C6",
|
|
16
|
-
color: "#fff",
|
|
17
|
-
border: "none",
|
|
18
|
-
borderRadius: 6,
|
|
19
|
-
cursor: "pointer",
|
|
20
|
-
fontWeight: 600,
|
|
21
|
-
transition: "all 0.2s ease",
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export function getRefreshButtonTheme(color?: string) {
|
|
26
|
-
const theme = getInitParams<Theme>("theme");
|
|
27
|
-
const whiteTheme = theme === Theme.WHITE;
|
|
28
|
-
|
|
29
|
-
return whiteTheme
|
|
30
|
-
? {
|
|
31
|
-
...refreshButtonThemes.white,
|
|
32
|
-
background: color || refreshButtonThemes.white.background,
|
|
33
|
-
}
|
|
34
|
-
: {
|
|
35
|
-
...refreshButtonThemes.dark,
|
|
36
|
-
background: color || refreshButtonThemes.dark.background,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function getRefreshButtonSizeStyles(size: "small" | "medium" | "large") {
|
|
41
|
-
switch (size) {
|
|
42
|
-
case "small":
|
|
43
|
-
return {
|
|
44
|
-
fontSize: "12px",
|
|
45
|
-
gap: "2px",
|
|
46
|
-
};
|
|
47
|
-
case "large":
|
|
48
|
-
return {
|
|
49
|
-
fontSize: "18px",
|
|
50
|
-
gap: "6px",
|
|
51
|
-
};
|
|
52
|
-
default:
|
|
53
|
-
return {
|
|
54
|
-
fontSize: "14px",
|
|
55
|
-
gap: "4px",
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
}
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from "preact/hooks";
|
|
2
|
-
import HoverPopover, {
|
|
3
|
-
type PopoverPosition,
|
|
4
|
-
} from "@/components/common/hover-popover";
|
|
5
|
-
import { getBalance } from "@/api";
|
|
6
|
-
import { t } from "@/local";
|
|
7
|
-
import register from "preact-custom-element";
|
|
8
|
-
import { getStatisticalBalanceTheme } from "./theme";
|
|
9
|
-
|
|
10
|
-
function formatNumber(num: number) {
|
|
11
|
-
return num.toLocaleString("en-US", {
|
|
12
|
-
minimumFractionDigits: 2,
|
|
13
|
-
maximumFractionDigits: 2,
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface DetailItem {
|
|
18
|
-
label: string;
|
|
19
|
-
value: number;
|
|
20
|
-
color: string;
|
|
21
|
-
dot: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function StatisticalBalance(props: { popoverPosition?: PopoverPosition }) {
|
|
25
|
-
const [balanceData, setBalanceData] = useState<{
|
|
26
|
-
available: number;
|
|
27
|
-
currency: string;
|
|
28
|
-
symbol: string;
|
|
29
|
-
details: DetailItem[];
|
|
30
|
-
}>({
|
|
31
|
-
available: 0,
|
|
32
|
-
currency: "USD",
|
|
33
|
-
symbol: "$",
|
|
34
|
-
details: [],
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const fetchBalance = async () => {
|
|
38
|
-
try {
|
|
39
|
-
const balance = await getBalance();
|
|
40
|
-
|
|
41
|
-
// 根据 API 返回的数据构建 balanceData,只保存数值数据
|
|
42
|
-
const details: DetailItem[] = [
|
|
43
|
-
{
|
|
44
|
-
label: "", // 翻译在渲染时处理
|
|
45
|
-
value: balance.totalAmount,
|
|
46
|
-
color: "#15b36b",
|
|
47
|
-
dot: "#15b36b",
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
label: "",
|
|
51
|
-
value: balance.frozenAmount,
|
|
52
|
-
color: "#f59e0b",
|
|
53
|
-
dot: "#f59e0b",
|
|
54
|
-
},
|
|
55
|
-
...(balance.isCredit
|
|
56
|
-
? [
|
|
57
|
-
{
|
|
58
|
-
label: "",
|
|
59
|
-
value: balance.creditLimit,
|
|
60
|
-
color: "#1890ff",
|
|
61
|
-
dot: "#1890ff",
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
label: "",
|
|
65
|
-
value: balance.creditUsed,
|
|
66
|
-
color: "#ff0000",
|
|
67
|
-
dot: "#ff0000",
|
|
68
|
-
},
|
|
69
|
-
]
|
|
70
|
-
: []),
|
|
71
|
-
{
|
|
72
|
-
label: "",
|
|
73
|
-
value: balance.availableAmount,
|
|
74
|
-
color: "#1890ff",
|
|
75
|
-
dot: "#15b36b",
|
|
76
|
-
},
|
|
77
|
-
];
|
|
78
|
-
|
|
79
|
-
const newBalanceData = {
|
|
80
|
-
available: balance.availableAmount,
|
|
81
|
-
currency: "USD",
|
|
82
|
-
symbol: "$",
|
|
83
|
-
details,
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
setBalanceData(newBalanceData);
|
|
87
|
-
} catch (err) {
|
|
88
|
-
console.error("获取余额失败:", err);
|
|
89
|
-
// 获取失败时保持默认的 $0 USD 显示
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
useEffect(() => {
|
|
94
|
-
fetchBalance();
|
|
95
|
-
}, []);
|
|
96
|
-
|
|
97
|
-
useEffect(() => {
|
|
98
|
-
// 监听refresh-balance事件
|
|
99
|
-
const handleRefreshBalance = () => {
|
|
100
|
-
fetchBalance();
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
// 添加事件监听器
|
|
104
|
-
document.addEventListener(
|
|
105
|
-
"refresh-balance",
|
|
106
|
-
handleRefreshBalance as EventListener
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
// 清理函数
|
|
110
|
-
return () => {
|
|
111
|
-
document.removeEventListener(
|
|
112
|
-
"refresh-balance",
|
|
113
|
-
handleRefreshBalance as EventListener
|
|
114
|
-
);
|
|
115
|
-
};
|
|
116
|
-
}, []);
|
|
117
|
-
|
|
118
|
-
const theme = getStatisticalBalanceTheme();
|
|
119
|
-
|
|
120
|
-
// 在渲染时动态生成翻译后的详情数据
|
|
121
|
-
const translatedDetails = [
|
|
122
|
-
{
|
|
123
|
-
label: t("真实金额"),
|
|
124
|
-
value: balanceData.details[0]?.value || 0,
|
|
125
|
-
color: "#15b36b",
|
|
126
|
-
dot: "#15b36b",
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
label: t("冻结金额"),
|
|
130
|
-
value: balanceData.details[1]?.value || 0,
|
|
131
|
-
color: "#f59e0b",
|
|
132
|
-
dot: "#f59e0b",
|
|
133
|
-
},
|
|
134
|
-
...(balanceData.details.length > 4
|
|
135
|
-
? [
|
|
136
|
-
{
|
|
137
|
-
label: t("信用额度"),
|
|
138
|
-
value: balanceData.details[2]?.value || 0,
|
|
139
|
-
color: "#1890ff",
|
|
140
|
-
dot: "#1890ff",
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
label: t("已用额度"),
|
|
144
|
-
value: balanceData.details[3]?.value || 0,
|
|
145
|
-
color: "#ff0000",
|
|
146
|
-
dot: "#ff0000",
|
|
147
|
-
},
|
|
148
|
-
]
|
|
149
|
-
: []),
|
|
150
|
-
{
|
|
151
|
-
label: t("可用余额"),
|
|
152
|
-
value: balanceData.details[balanceData.details.length - 1]?.value || 0,
|
|
153
|
-
color: "#1890ff",
|
|
154
|
-
dot: "#15b36b",
|
|
155
|
-
},
|
|
156
|
-
];
|
|
157
|
-
|
|
158
|
-
return (
|
|
159
|
-
<HoverPopover
|
|
160
|
-
popover={
|
|
161
|
-
<>
|
|
162
|
-
<div style={theme.popoverTitle}>{t("余额详情")}</div>
|
|
163
|
-
{translatedDetails.map((item) => (
|
|
164
|
-
<div key={item.label} style={theme.detailRow}>
|
|
165
|
-
<span style={theme.detailLabel}>
|
|
166
|
-
<span style={theme.detailDot(item.dot)} />
|
|
167
|
-
{item.label}
|
|
168
|
-
</span>
|
|
169
|
-
<span style={theme.detailValue(item.color)}>
|
|
170
|
-
{balanceData.symbol}
|
|
171
|
-
{formatNumber(item.value)}
|
|
172
|
-
</span>
|
|
173
|
-
</div>
|
|
174
|
-
))}
|
|
175
|
-
</>
|
|
176
|
-
}
|
|
177
|
-
popoverPosition={props.popoverPosition || "bottom"}
|
|
178
|
-
>
|
|
179
|
-
<div style={theme.main}>
|
|
180
|
-
{balanceData.symbol}
|
|
181
|
-
{formatNumber(balanceData.available)}
|
|
182
|
-
<span style={theme.currency}>{balanceData.currency}</span>
|
|
183
|
-
</div>
|
|
184
|
-
</HoverPopover>
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
register(StatisticalBalance, "best-statistical-balance");
|
|
189
|
-
|
|
190
|
-
export default StatisticalBalance;
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { Size, Theme } from "@/types";
|
|
2
|
-
import { getInitParams } from "@/utils/business";
|
|
3
|
-
const size = getInitParams<Size>("size");
|
|
4
|
-
|
|
5
|
-
export const statisticalBalanceThemes = {
|
|
6
|
-
white: {
|
|
7
|
-
popoverTitle: {
|
|
8
|
-
fontSize: size === Size.SMALL ? 12 : 16,
|
|
9
|
-
fontWeight: 600,
|
|
10
|
-
color: "#222",
|
|
11
|
-
marginBottom: size === Size.SMALL ? 12 : 16,
|
|
12
|
-
textAlign: "center",
|
|
13
|
-
},
|
|
14
|
-
detailRow: {
|
|
15
|
-
display: "flex",
|
|
16
|
-
justifyContent: "space-between",
|
|
17
|
-
alignItems: "center",
|
|
18
|
-
padding: size === Size.SMALL ? "6px 0" : "8px 0",
|
|
19
|
-
borderBottom: "1px solid #e5e7eb",
|
|
20
|
-
fontSize: size === Size.SMALL ? 12 : 15,
|
|
21
|
-
},
|
|
22
|
-
detailLabel: {
|
|
23
|
-
display: "flex",
|
|
24
|
-
alignItems: "center",
|
|
25
|
-
color: "#6b7280",
|
|
26
|
-
fontWeight: 500,
|
|
27
|
-
},
|
|
28
|
-
detailDot: (color: string) => ({
|
|
29
|
-
display: "inline-block",
|
|
30
|
-
width: size === Size.SMALL ? 6 : 8,
|
|
31
|
-
height: size === Size.SMALL ? 6 : 8,
|
|
32
|
-
borderRadius: "50%",
|
|
33
|
-
background: color,
|
|
34
|
-
marginRight: size === Size.SMALL ? 6 : 8,
|
|
35
|
-
}),
|
|
36
|
-
detailValue: (color: string) => ({
|
|
37
|
-
color,
|
|
38
|
-
fontWeight: 600,
|
|
39
|
-
fontSize: size === Size.SMALL ? 12 : 15,
|
|
40
|
-
}),
|
|
41
|
-
main: {
|
|
42
|
-
fontSize: size === Size.SMALL ? 18 : 24,
|
|
43
|
-
fontWeight: 800,
|
|
44
|
-
color: "#111827",
|
|
45
|
-
display: "inline-block",
|
|
46
|
-
},
|
|
47
|
-
currency: {
|
|
48
|
-
fontSize: size === Size.SMALL ? 16 : 18,
|
|
49
|
-
color: "#6b7280",
|
|
50
|
-
marginLeft: size === Size.SMALL ? 6 : 8,
|
|
51
|
-
fontWeight: 600,
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
dark: {
|
|
55
|
-
popoverTitle: {
|
|
56
|
-
fontSize: size === Size.SMALL ? 14 : 16,
|
|
57
|
-
fontWeight: 600,
|
|
58
|
-
color: "#fff",
|
|
59
|
-
marginBottom: size === Size.SMALL ? 14 : 16,
|
|
60
|
-
textAlign: "center",
|
|
61
|
-
},
|
|
62
|
-
detailRow: {
|
|
63
|
-
display: "flex",
|
|
64
|
-
justifyContent: "space-between",
|
|
65
|
-
alignItems: "center",
|
|
66
|
-
padding: size === Size.SMALL ? "6px 0" : "8px 0",
|
|
67
|
-
borderBottom: "1px solid #374151",
|
|
68
|
-
fontSize: size === Size.SMALL ? 12 : 15,
|
|
69
|
-
},
|
|
70
|
-
detailLabel: {
|
|
71
|
-
display: "flex",
|
|
72
|
-
alignItems: "center",
|
|
73
|
-
color: "#B5B8BE",
|
|
74
|
-
fontWeight: 500,
|
|
75
|
-
},
|
|
76
|
-
detailDot: (color: string) => ({
|
|
77
|
-
display: "inline-block",
|
|
78
|
-
width: size === Size.SMALL ? 6 : 8,
|
|
79
|
-
height: size === Size.SMALL ? 6 : 8,
|
|
80
|
-
borderRadius: "50%",
|
|
81
|
-
background: color,
|
|
82
|
-
marginRight: size === Size.SMALL ? 6 : 8,
|
|
83
|
-
}),
|
|
84
|
-
detailValue: (color: string) => ({
|
|
85
|
-
color,
|
|
86
|
-
fontWeight: 600,
|
|
87
|
-
fontSize: size === Size.SMALL ? 12 : 15,
|
|
88
|
-
}),
|
|
89
|
-
main: {
|
|
90
|
-
fontSize: size === Size.SMALL ? 18 : 24,
|
|
91
|
-
fontWeight: 800,
|
|
92
|
-
color: "#fff",
|
|
93
|
-
display: "inline-block",
|
|
94
|
-
},
|
|
95
|
-
currency: {
|
|
96
|
-
fontSize: size === Size.SMALL ? 16 : 18,
|
|
97
|
-
color: "#B5B8BE",
|
|
98
|
-
marginLeft: size === Size.SMALL ? 6 : 8,
|
|
99
|
-
fontWeight: 600,
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
export function getStatisticalBalanceTheme() {
|
|
105
|
-
const theme = getInitParams<Theme>("theme");
|
|
106
|
-
const whiteTheme = theme === Theme.WHITE;
|
|
107
|
-
return whiteTheme
|
|
108
|
-
? statisticalBalanceThemes.white
|
|
109
|
-
: statisticalBalanceThemes.dark;
|
|
110
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { ComponentChildren } from "preact";
|
|
2
|
-
import { getButtonTheme } from "./theme";
|
|
3
|
-
|
|
4
|
-
interface ButtonProps {
|
|
5
|
-
onClick?: () => void;
|
|
6
|
-
color?: string;
|
|
7
|
-
children: ComponentChildren;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function Button({ onClick, color, children }: ButtonProps) {
|
|
11
|
-
const style = getButtonTheme(color);
|
|
12
|
-
return (
|
|
13
|
-
<button style={style} onClick={onClick} type="button">
|
|
14
|
-
{children}
|
|
15
|
-
</button>
|
|
16
|
-
);
|
|
17
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { Size, Theme, type ThemeConfig } from "@/types";
|
|
2
|
-
import { getInitParams } from "@/utils/business";
|
|
3
|
-
const size = getInitParams<Size>("size");
|
|
4
|
-
export const buttonThemes = {
|
|
5
|
-
white: {
|
|
6
|
-
background: "#1890ff",
|
|
7
|
-
color: "#fff",
|
|
8
|
-
border: "none",
|
|
9
|
-
borderRadius: 6,
|
|
10
|
-
padding: size === Size.SMALL ? "6px 10px" : "8px 16px",
|
|
11
|
-
cursor: "pointer",
|
|
12
|
-
fontSize: size === Size.SMALL ? 12 : 16,
|
|
13
|
-
fontWeight: 600,
|
|
14
|
-
},
|
|
15
|
-
dark: {
|
|
16
|
-
background: "#00E8C6",
|
|
17
|
-
color: "#fff",
|
|
18
|
-
border: "none",
|
|
19
|
-
borderRadius: 6,
|
|
20
|
-
padding: size === Size.SMALL ? "6px 10px" : "8px 16px",
|
|
21
|
-
cursor: "pointer",
|
|
22
|
-
fontSize: size === Size.SMALL ? 12 : 16,
|
|
23
|
-
fontWeight: 600,
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export function getButtonTheme(color?: string) {
|
|
28
|
-
const theme = getInitParams<Theme>("theme");
|
|
29
|
-
const themeConfig = getInitParams<ThemeConfig>("themeConfig");
|
|
30
|
-
const whiteTheme = theme === Theme.WHITE;
|
|
31
|
-
|
|
32
|
-
// 优先使用传入的 color 参数,其次使用 themeConfig 中的配置
|
|
33
|
-
let buttonColor = color;
|
|
34
|
-
if (!buttonColor && themeConfig) {
|
|
35
|
-
const config = whiteTheme ? themeConfig.white : themeConfig.dark;
|
|
36
|
-
buttonColor = config?.color;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return whiteTheme
|
|
40
|
-
? {
|
|
41
|
-
...buttonThemes.white,
|
|
42
|
-
background: buttonColor || buttonThemes.white.background,
|
|
43
|
-
}
|
|
44
|
-
: {
|
|
45
|
-
...buttonThemes.dark,
|
|
46
|
-
background: buttonColor || buttonThemes.dark.background,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import { useState, useRef } from "preact/hooks";
|
|
2
|
-
import type { FunctionalComponent, JSX } from "preact";
|
|
3
|
-
import { getHoverPopoverTheme } from "./theme";
|
|
4
|
-
|
|
5
|
-
export type PopoverPosition = "top" | "bottom" | "leftTop" | "rightTop";
|
|
6
|
-
interface HoverPopoverProps {
|
|
7
|
-
popover: JSX.Element;
|
|
8
|
-
children: JSX.Element;
|
|
9
|
-
popoverWidth?: number;
|
|
10
|
-
popoverMinWidth?: number;
|
|
11
|
-
offsetY?: number; // 弹层与目标元素的垂直间距
|
|
12
|
-
offsetX?: number; // 弹层与目标元素的水平间距
|
|
13
|
-
popoverPosition?: "top" | "bottom" | "leftTop" | "rightTop";
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* 通用 HoverPopover 组件,支持上下、左上、右上浮层、箭头、位置自适应
|
|
18
|
-
*/
|
|
19
|
-
const HoverPopover: FunctionalComponent<HoverPopoverProps> = ({
|
|
20
|
-
popover,
|
|
21
|
-
children,
|
|
22
|
-
popoverWidth = 300,
|
|
23
|
-
popoverMinWidth = 200,
|
|
24
|
-
offsetY = 16,
|
|
25
|
-
offsetX = 16,
|
|
26
|
-
popoverPosition = "top",
|
|
27
|
-
}) => {
|
|
28
|
-
const [show, setShow] = useState(false);
|
|
29
|
-
const [position, setPosition] = useState<
|
|
30
|
-
"top" | "bottom" | "leftTop" | "rightTop"
|
|
31
|
-
>(popoverPosition);
|
|
32
|
-
const ref = useRef<HTMLDivElement>(null);
|
|
33
|
-
const timerRef = useRef<number | null>(null);
|
|
34
|
-
const theme = getHoverPopoverTheme();
|
|
35
|
-
|
|
36
|
-
const handleMouseEnter = () => {
|
|
37
|
-
if (timerRef.current) {
|
|
38
|
-
clearTimeout(timerRef.current);
|
|
39
|
-
timerRef.current = null;
|
|
40
|
-
}
|
|
41
|
-
if (popoverPosition === "top" || popoverPosition === "bottom") {
|
|
42
|
-
if (ref.current) {
|
|
43
|
-
const rect = ref.current.getBoundingClientRect();
|
|
44
|
-
if (popoverPosition === "top" && rect.top < 100) {
|
|
45
|
-
setPosition("bottom");
|
|
46
|
-
} else if (
|
|
47
|
-
popoverPosition === "bottom" &&
|
|
48
|
-
window.innerHeight - rect.bottom < 100
|
|
49
|
-
) {
|
|
50
|
-
setPosition("top");
|
|
51
|
-
} else {
|
|
52
|
-
setPosition(popoverPosition);
|
|
53
|
-
}
|
|
54
|
-
} else {
|
|
55
|
-
setPosition(popoverPosition);
|
|
56
|
-
}
|
|
57
|
-
} else {
|
|
58
|
-
setPosition(popoverPosition);
|
|
59
|
-
}
|
|
60
|
-
setShow(true);
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const handleMouseLeave = () => {
|
|
64
|
-
// 延迟关闭,防止鼠标快速移动到弹窗内容时闪烁
|
|
65
|
-
timerRef.current = window.setTimeout(() => {
|
|
66
|
-
setShow(false);
|
|
67
|
-
}, 120);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
// 弹层定位样式
|
|
71
|
-
let popoverStyle: any = {
|
|
72
|
-
position: "absolute",
|
|
73
|
-
zIndex: 999,
|
|
74
|
-
borderRadius: 6,
|
|
75
|
-
fontSize: 15,
|
|
76
|
-
minWidth: popoverMinWidth,
|
|
77
|
-
width: popoverWidth,
|
|
78
|
-
padding: "8px 14px",
|
|
79
|
-
pointerEvents: "auto",
|
|
80
|
-
textAlign: "center",
|
|
81
|
-
animation: "fadeInUp 0.3s",
|
|
82
|
-
...theme.popover,
|
|
83
|
-
};
|
|
84
|
-
let arrowStyle: any = {
|
|
85
|
-
position: "absolute",
|
|
86
|
-
zIndex: 11,
|
|
87
|
-
width: 0,
|
|
88
|
-
height: 0,
|
|
89
|
-
};
|
|
90
|
-
if (position === "top") {
|
|
91
|
-
popoverStyle = {
|
|
92
|
-
...popoverStyle,
|
|
93
|
-
left: "50%",
|
|
94
|
-
top: -48,
|
|
95
|
-
transform: "translateX(-50%)",
|
|
96
|
-
};
|
|
97
|
-
arrowStyle = {
|
|
98
|
-
...arrowStyle,
|
|
99
|
-
left: "50%",
|
|
100
|
-
bottom: -8,
|
|
101
|
-
transform: "translateX(-50%)",
|
|
102
|
-
borderLeft: "8px solid transparent",
|
|
103
|
-
borderRight: "8px solid transparent",
|
|
104
|
-
borderTop: `8px solid ${theme.arrow.top}`,
|
|
105
|
-
};
|
|
106
|
-
} else if (position === "bottom") {
|
|
107
|
-
popoverStyle = {
|
|
108
|
-
...popoverStyle,
|
|
109
|
-
left: "50%",
|
|
110
|
-
top: "100%",
|
|
111
|
-
marginTop: offsetY,
|
|
112
|
-
transform: "translateX(-50%)",
|
|
113
|
-
};
|
|
114
|
-
arrowStyle = {
|
|
115
|
-
...arrowStyle,
|
|
116
|
-
left: "50%",
|
|
117
|
-
top: -8,
|
|
118
|
-
transform: "translateX(-50%)",
|
|
119
|
-
borderLeft: "8px solid transparent",
|
|
120
|
-
borderRight: "8px solid transparent",
|
|
121
|
-
borderBottom: `8px solid ${theme.arrow.bottom}`,
|
|
122
|
-
};
|
|
123
|
-
} else if (position === "leftTop") {
|
|
124
|
-
popoverStyle = {
|
|
125
|
-
...popoverStyle,
|
|
126
|
-
right: "100%",
|
|
127
|
-
top: 0,
|
|
128
|
-
marginRight: offsetX,
|
|
129
|
-
transform: "none",
|
|
130
|
-
};
|
|
131
|
-
arrowStyle = {
|
|
132
|
-
...arrowStyle,
|
|
133
|
-
right: -8,
|
|
134
|
-
top: 12,
|
|
135
|
-
borderTop: "8px solid transparent",
|
|
136
|
-
borderBottom: "8px solid transparent",
|
|
137
|
-
borderLeft: `8px solid ${theme.arrow.left}`,
|
|
138
|
-
};
|
|
139
|
-
} else if (position === "rightTop") {
|
|
140
|
-
popoverStyle = {
|
|
141
|
-
...popoverStyle,
|
|
142
|
-
left: "100%",
|
|
143
|
-
top: 0,
|
|
144
|
-
marginLeft: offsetX,
|
|
145
|
-
transform: "translateY(0)", // 右上角对齐
|
|
146
|
-
};
|
|
147
|
-
arrowStyle = {
|
|
148
|
-
...arrowStyle,
|
|
149
|
-
left: -8,
|
|
150
|
-
top: 12,
|
|
151
|
-
borderTop: "8px solid transparent",
|
|
152
|
-
borderBottom: "8px solid transparent",
|
|
153
|
-
borderRight: `8px solid ${theme.arrow.right}`,
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return (
|
|
158
|
-
<div
|
|
159
|
-
ref={ref}
|
|
160
|
-
style={{ position: "relative", display: "inline-block" }}
|
|
161
|
-
onMouseEnter={handleMouseEnter}
|
|
162
|
-
onMouseLeave={handleMouseLeave}
|
|
163
|
-
>
|
|
164
|
-
{children}
|
|
165
|
-
{show && (
|
|
166
|
-
<div
|
|
167
|
-
style={popoverStyle}
|
|
168
|
-
onMouseEnter={handleMouseEnter}
|
|
169
|
-
onMouseLeave={handleMouseLeave}
|
|
170
|
-
>
|
|
171
|
-
{popover}
|
|
172
|
-
<div style={arrowStyle} />
|
|
173
|
-
</div>
|
|
174
|
-
)}
|
|
175
|
-
</div>
|
|
176
|
-
);
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
export default HoverPopover;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { Theme } from "@/types";
|
|
2
|
-
import { getInitParams } from "@/utils/business";
|
|
3
|
-
|
|
4
|
-
export const hoverPopoverThemes = {
|
|
5
|
-
white: {
|
|
6
|
-
popover: {
|
|
7
|
-
background: "#fff",
|
|
8
|
-
color: "#222",
|
|
9
|
-
boxShadow: "0 4px 16px rgba(0,0,0,0.12)",
|
|
10
|
-
border: "none",
|
|
11
|
-
},
|
|
12
|
-
arrow: {
|
|
13
|
-
top: "#fff",
|
|
14
|
-
bottom: "#fff",
|
|
15
|
-
left: "#fff",
|
|
16
|
-
right: "#fff",
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
dark: {
|
|
20
|
-
popover: {
|
|
21
|
-
background: "#23262F",
|
|
22
|
-
color: "#fff",
|
|
23
|
-
boxShadow: "0 4px 16px rgba(0,0,0,0.32)",
|
|
24
|
-
border: "1px solid #444C5C",
|
|
25
|
-
},
|
|
26
|
-
arrow: {
|
|
27
|
-
top: "#23262F",
|
|
28
|
-
bottom: "#23262F",
|
|
29
|
-
left: "#23262F",
|
|
30
|
-
right: "#23262F",
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export function getHoverPopoverTheme() {
|
|
36
|
-
const theme = getInitParams<Theme>("theme");
|
|
37
|
-
const whiteTheme = theme === Theme.WHITE;
|
|
38
|
-
return whiteTheme ? hoverPopoverThemes.white : hoverPopoverThemes.dark;
|
|
39
|
-
}
|