tango-ui-cw 0.0.2 → 0.2.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.
- package/dist/index.css +1 -1
- package/dist/index.js +10 -10
- package/dist/index.mjs +1086 -849
- package/package.json +1 -1
- package/src/component/CSSFab/useTangoStyle.jsx +182 -182
- package/src/component/MaterialButton/{MaterialButton.css → MaterialButton.module.css} +64 -64
- package/src/component/MaterialButton/index.jsx +69 -58
- package/src/component/MaterialInput/{MaterialInput.css → MaterialInput.module.css} +37 -33
- package/src/component/MaterialInput/index.jsx +34 -29
- package/src/component/TButton/TButton.module.css +184 -0
- package/src/component/TButton/index.jsx +81 -74
- package/src/component/TColorPicker/{TColorPicker.css → TColorPicker.module.css} +24 -24
- package/src/component/TColorPicker/index.jsx +107 -106
- package/src/component/TDate/index.jsx +146 -148
- package/src/component/TDatePicker/TDatePicker.module.css +12 -0
- package/src/component/TDatePicker/index.jsx +72 -60
- package/src/component/TDrawer/{TDrawer.css → TDrawer.module.css} +203 -202
- package/src/component/TDrawer/index.jsx +80 -74
- package/src/component/TInput/{TInput.css → TInput.module.css} +67 -80
- package/src/component/TInput/index.jsx +95 -102
- package/src/component/TLayout/TLayout.css +88 -88
- package/src/component/TLayout/index.jsx +77 -77
- package/src/component/TLine/TLine.module.css +52 -0
- package/src/component/TLine/index.jsx +48 -57
- package/src/component/TMark/{TMark.css → TMark.module.css} +6 -6
- package/src/component/TMark/index.jsx +69 -78
- package/src/component/TModal/{TModal.css → TModal.module.css} +109 -108
- package/src/component/TModal/index.jsx +75 -69
- package/src/component/TNotice/{TNotice.css → TNotice.module.css} +50 -52
- package/src/component/TNotice/index.jsx +37 -38
- package/src/component/TNotice/useNotice.jsx +54 -54
- package/src/component/TSearch/{TSearch.css → TSearch.module.css} +80 -90
- package/src/component/TSearch/index.jsx +86 -100
- package/src/component/TSpace/TSpace.module.css +43 -0
- package/src/component/TSpace/index.jsx +60 -60
- package/src/component/TTable/{TTable.css → TTable.module.css} +26 -26
- package/src/component/TTable/index.jsx +73 -77
- package/src/component/TTooltip/TTooltip.module.css +66 -0
- package/src/component/TTooltip/index.jsx +33 -25
- package/src/component/Tango/store.js +105 -105
- package/src/component/Tools/WaterMark/WaterMark.jsx +78 -78
- package/src/component/TButton/TButton.css +0 -270
- package/src/component/TDate/TDate.css +0 -0
- package/src/component/TDatePicker/TDatePicker.css +0 -13
- package/src/component/TLine/TLine.css +0 -54
- package/src/component/TSpace/TSpace.css +0 -43
- package/src/component/TTooltip/TTooltip.css +0 -105
package/package.json
CHANGED
@@ -1,182 +1,182 @@
|
|
1
|
-
// 封装sx属性值
|
2
|
-
export const useTangoStyle = (sx) => {
|
3
|
-
return Object.entries(sx).reduce((acc, [key, value]) => {
|
4
|
-
const pxValue = `${value}px`;
|
5
|
-
|
6
|
-
switch (key) {
|
7
|
-
case "mt":
|
8
|
-
acc.marginTop = typeof value === "number" ? `${value}px` : value;
|
9
|
-
break;
|
10
|
-
case "mr":
|
11
|
-
acc.marginRight = typeof value === "number" ? `${value}px` : value;
|
12
|
-
break;
|
13
|
-
case "mb":
|
14
|
-
acc.marginBottom = typeof value === "number" ? `${value}px` : value;
|
15
|
-
break;
|
16
|
-
case "ml":
|
17
|
-
acc.marginLeft = typeof value === "number" ? `${value}px` : value;
|
18
|
-
break;
|
19
|
-
case "m":
|
20
|
-
acc.margin = typeof value === "number" ? `${value}px` : value;
|
21
|
-
break;
|
22
|
-
|
23
|
-
case "pt":
|
24
|
-
acc.paddingTop = pxValue;
|
25
|
-
break;
|
26
|
-
case "pr":
|
27
|
-
acc.paddingRight = pxValue;
|
28
|
-
break;
|
29
|
-
case "pb":
|
30
|
-
acc.paddingBottom = pxValue;
|
31
|
-
break;
|
32
|
-
case "pl":
|
33
|
-
acc.paddingLeft = pxValue;
|
34
|
-
break;
|
35
|
-
case "p":
|
36
|
-
acc.padding = pxValue;
|
37
|
-
break;
|
38
|
-
case "br":
|
39
|
-
acc.borderRadius = typeof value === "number" ? `${value}px` : value;
|
40
|
-
break;
|
41
|
-
case "bg":
|
42
|
-
acc.background = value; // 直接使用传入的背景值
|
43
|
-
break;
|
44
|
-
case "c":
|
45
|
-
acc.color = value;
|
46
|
-
break;
|
47
|
-
case "b":
|
48
|
-
acc.border = value === 1 ? "1px solid red" : value; // 如果值是 1,则设置为 "1px solid red"
|
49
|
-
break;
|
50
|
-
case "center":
|
51
|
-
acc.position = "absolute"; // 设置绝对定位
|
52
|
-
acc.inset = 0; // 设置inset为0
|
53
|
-
acc.margin = "auto"; // 设置margin为auto,保证元素居中
|
54
|
-
break;
|
55
|
-
case "pot":
|
56
|
-
acc.top = pxValue;
|
57
|
-
break;
|
58
|
-
case "por":
|
59
|
-
acc.right = pxValue;
|
60
|
-
break;
|
61
|
-
case "pob":
|
62
|
-
acc.bottom = pxValue;
|
63
|
-
break;
|
64
|
-
case "pol":
|
65
|
-
acc.left = pxValue;
|
66
|
-
break;
|
67
|
-
case "rel":
|
68
|
-
acc.position = "relative"; // 设置相对定位
|
69
|
-
break;
|
70
|
-
case "ab":
|
71
|
-
acc.position = "absolute"; // 设置绝对定位
|
72
|
-
break;
|
73
|
-
case "fixed":
|
74
|
-
acc.position = "fixed"; // 设置窗口定位
|
75
|
-
break;
|
76
|
-
case "w":
|
77
|
-
acc.width = pxValue;
|
78
|
-
break;
|
79
|
-
case "h":
|
80
|
-
acc.height = pxValue;
|
81
|
-
break;
|
82
|
-
case "vw":
|
83
|
-
acc.width = `${value}vw`; // 将宽度值转换为 vw 单位
|
84
|
-
break;
|
85
|
-
case "vh":
|
86
|
-
acc.height = `${value}vh`; // 将高度值转换为 vh 单位
|
87
|
-
break;
|
88
|
-
case "presentw":
|
89
|
-
acc.width = `${value}%`; // 将宽度值转换为 % 单位
|
90
|
-
break;
|
91
|
-
case "presenth":
|
92
|
-
acc.height = `${value}%`; // 将高度值转换为 % 单位
|
93
|
-
break;
|
94
|
-
case "mw":
|
95
|
-
acc.minWidth = pxValue;
|
96
|
-
break;
|
97
|
-
case "mh":
|
98
|
-
acc.minHieght = pxValue;
|
99
|
-
break;
|
100
|
-
case "fl":
|
101
|
-
acc.float = "left";
|
102
|
-
break;
|
103
|
-
case "fr":
|
104
|
-
acc.float = "right";
|
105
|
-
break;
|
106
|
-
case "size":
|
107
|
-
acc.fontSize = pxValue;
|
108
|
-
break;
|
109
|
-
case "tac":
|
110
|
-
acc.textAlign = "center";
|
111
|
-
break;
|
112
|
-
case "z":
|
113
|
-
acc.zIndex = value;
|
114
|
-
break;
|
115
|
-
case "tran":
|
116
|
-
acc.transition = `${value}s`;
|
117
|
-
break;
|
118
|
-
case "flex":
|
119
|
-
acc.display = "flex";
|
120
|
-
break;
|
121
|
-
case "aic":
|
122
|
-
acc.alignItems = "center";
|
123
|
-
break;
|
124
|
-
case "jcc":
|
125
|
-
acc.justifyContent = "center";
|
126
|
-
break;
|
127
|
-
case "jc":
|
128
|
-
acc.justifyContent = value;
|
129
|
-
break;
|
130
|
-
case "oh":
|
131
|
-
acc.overflow = "hidden";
|
132
|
-
break;
|
133
|
-
case "ohauto":
|
134
|
-
acc.overflow = "auto";
|
135
|
-
break;
|
136
|
-
case "op":
|
137
|
-
acc.opacity = value;
|
138
|
-
break;
|
139
|
-
case "none":
|
140
|
-
acc.display = "none";
|
141
|
-
break;
|
142
|
-
case "ar":
|
143
|
-
acc.aspectRatio = value;
|
144
|
-
break;
|
145
|
-
case "ls":
|
146
|
-
acc.letterSpacing = pxValue;
|
147
|
-
break;
|
148
|
-
case "lh":
|
149
|
-
acc.lineHeight = pxValue;
|
150
|
-
break;
|
151
|
-
case "fwb":
|
152
|
-
acc.fontWeight = "bold";
|
153
|
-
break;
|
154
|
-
case "boxsizing":
|
155
|
-
acc.boxSizing = "border-box";
|
156
|
-
break;
|
157
|
-
case "boxshadow":
|
158
|
-
acc.boxShadow = value;
|
159
|
-
break;
|
160
|
-
|
161
|
-
case "f":
|
162
|
-
acc.flex = typeof value === "number" ? value : `${value}`; // 支持数字或字符串
|
163
|
-
break;
|
164
|
-
case "bColor":
|
165
|
-
acc.borderColor = value; // 直接使用传入的背景值
|
166
|
-
break;
|
167
|
-
case "bgSize":
|
168
|
-
acc.backgroundSize = value; // 直接使用传入的背景值
|
169
|
-
break;
|
170
|
-
case "bgPosition":
|
171
|
-
acc.backgroundPosition = value; // 直接使用传入的背景值
|
172
|
-
break;
|
173
|
-
case "bgRepeat":
|
174
|
-
acc.backgroundRepeat = value; // 直接使用传入的背景值
|
175
|
-
break;
|
176
|
-
default:
|
177
|
-
acc[key] = value; // 允许其他样式直接传入,理论上可以支持所有的CSS样式传入
|
178
|
-
}
|
179
|
-
|
180
|
-
return acc;
|
181
|
-
}, {});
|
182
|
-
};
|
1
|
+
// 封装sx属性值
|
2
|
+
export const useTangoStyle = (sx) => {
|
3
|
+
return Object.entries(sx).reduce((acc, [key, value]) => {
|
4
|
+
const pxValue = `${value}px`;
|
5
|
+
|
6
|
+
switch (key) {
|
7
|
+
case "mt":
|
8
|
+
acc.marginTop = typeof value === "number" ? `${value}px` : value;
|
9
|
+
break;
|
10
|
+
case "mr":
|
11
|
+
acc.marginRight = typeof value === "number" ? `${value}px` : value;
|
12
|
+
break;
|
13
|
+
case "mb":
|
14
|
+
acc.marginBottom = typeof value === "number" ? `${value}px` : value;
|
15
|
+
break;
|
16
|
+
case "ml":
|
17
|
+
acc.marginLeft = typeof value === "number" ? `${value}px` : value;
|
18
|
+
break;
|
19
|
+
case "m":
|
20
|
+
acc.margin = typeof value === "number" ? `${value}px` : value;
|
21
|
+
break;
|
22
|
+
|
23
|
+
case "pt":
|
24
|
+
acc.paddingTop = pxValue;
|
25
|
+
break;
|
26
|
+
case "pr":
|
27
|
+
acc.paddingRight = pxValue;
|
28
|
+
break;
|
29
|
+
case "pb":
|
30
|
+
acc.paddingBottom = pxValue;
|
31
|
+
break;
|
32
|
+
case "pl":
|
33
|
+
acc.paddingLeft = pxValue;
|
34
|
+
break;
|
35
|
+
case "p":
|
36
|
+
acc.padding = pxValue;
|
37
|
+
break;
|
38
|
+
case "br":
|
39
|
+
acc.borderRadius = typeof value === "number" ? `${value}px` : value;
|
40
|
+
break;
|
41
|
+
case "bg":
|
42
|
+
acc.background = value; // 直接使用传入的背景值
|
43
|
+
break;
|
44
|
+
case "c":
|
45
|
+
acc.color = value;
|
46
|
+
break;
|
47
|
+
case "b":
|
48
|
+
acc.border = value === 1 ? "1px solid red" : value; // 如果值是 1,则设置为 "1px solid red"
|
49
|
+
break;
|
50
|
+
case "center":
|
51
|
+
acc.position = "absolute"; // 设置绝对定位
|
52
|
+
acc.inset = 0; // 设置inset为0
|
53
|
+
acc.margin = "auto"; // 设置margin为auto,保证元素居中
|
54
|
+
break;
|
55
|
+
case "pot":
|
56
|
+
acc.top = pxValue;
|
57
|
+
break;
|
58
|
+
case "por":
|
59
|
+
acc.right = pxValue;
|
60
|
+
break;
|
61
|
+
case "pob":
|
62
|
+
acc.bottom = pxValue;
|
63
|
+
break;
|
64
|
+
case "pol":
|
65
|
+
acc.left = pxValue;
|
66
|
+
break;
|
67
|
+
case "rel":
|
68
|
+
acc.position = "relative"; // 设置相对定位
|
69
|
+
break;
|
70
|
+
case "ab":
|
71
|
+
acc.position = "absolute"; // 设置绝对定位
|
72
|
+
break;
|
73
|
+
case "fixed":
|
74
|
+
acc.position = "fixed"; // 设置窗口定位
|
75
|
+
break;
|
76
|
+
case "w":
|
77
|
+
acc.width = pxValue;
|
78
|
+
break;
|
79
|
+
case "h":
|
80
|
+
acc.height = pxValue;
|
81
|
+
break;
|
82
|
+
case "vw":
|
83
|
+
acc.width = `${value}vw`; // 将宽度值转换为 vw 单位
|
84
|
+
break;
|
85
|
+
case "vh":
|
86
|
+
acc.height = `${value}vh`; // 将高度值转换为 vh 单位
|
87
|
+
break;
|
88
|
+
case "presentw":
|
89
|
+
acc.width = `${value}%`; // 将宽度值转换为 % 单位
|
90
|
+
break;
|
91
|
+
case "presenth":
|
92
|
+
acc.height = `${value}%`; // 将高度值转换为 % 单位
|
93
|
+
break;
|
94
|
+
case "mw":
|
95
|
+
acc.minWidth = pxValue;
|
96
|
+
break;
|
97
|
+
case "mh":
|
98
|
+
acc.minHieght = pxValue;
|
99
|
+
break;
|
100
|
+
case "fl":
|
101
|
+
acc.float = "left";
|
102
|
+
break;
|
103
|
+
case "fr":
|
104
|
+
acc.float = "right";
|
105
|
+
break;
|
106
|
+
case "size":
|
107
|
+
acc.fontSize = pxValue;
|
108
|
+
break;
|
109
|
+
case "tac":
|
110
|
+
acc.textAlign = "center";
|
111
|
+
break;
|
112
|
+
case "z":
|
113
|
+
acc.zIndex = value;
|
114
|
+
break;
|
115
|
+
case "tran":
|
116
|
+
acc.transition = `${value}s`;
|
117
|
+
break;
|
118
|
+
case "flex":
|
119
|
+
acc.display = "flex";
|
120
|
+
break;
|
121
|
+
case "aic":
|
122
|
+
acc.alignItems = "center";
|
123
|
+
break;
|
124
|
+
case "jcc":
|
125
|
+
acc.justifyContent = "center";
|
126
|
+
break;
|
127
|
+
case "jc":
|
128
|
+
acc.justifyContent = value;
|
129
|
+
break;
|
130
|
+
case "oh":
|
131
|
+
acc.overflow = "hidden";
|
132
|
+
break;
|
133
|
+
case "ohauto":
|
134
|
+
acc.overflow = "auto";
|
135
|
+
break;
|
136
|
+
case "op":
|
137
|
+
acc.opacity = value;
|
138
|
+
break;
|
139
|
+
case "none":
|
140
|
+
acc.display = "none";
|
141
|
+
break;
|
142
|
+
case "ar":
|
143
|
+
acc.aspectRatio = value;
|
144
|
+
break;
|
145
|
+
case "ls":
|
146
|
+
acc.letterSpacing = pxValue;
|
147
|
+
break;
|
148
|
+
case "lh":
|
149
|
+
acc.lineHeight = pxValue;
|
150
|
+
break;
|
151
|
+
case "fwb":
|
152
|
+
acc.fontWeight = "bold";
|
153
|
+
break;
|
154
|
+
case "boxsizing":
|
155
|
+
acc.boxSizing = "border-box";
|
156
|
+
break;
|
157
|
+
case "boxshadow":
|
158
|
+
acc.boxShadow = value;
|
159
|
+
break;
|
160
|
+
|
161
|
+
case "f":
|
162
|
+
acc.flex = typeof value === "number" ? value : `${value}`; // 支持数字或字符串
|
163
|
+
break;
|
164
|
+
case "bColor":
|
165
|
+
acc.borderColor = value; // 直接使用传入的背景值
|
166
|
+
break;
|
167
|
+
case "bgSize":
|
168
|
+
acc.backgroundSize = value; // 直接使用传入的背景值
|
169
|
+
break;
|
170
|
+
case "bgPosition":
|
171
|
+
acc.backgroundPosition = value; // 直接使用传入的背景值
|
172
|
+
break;
|
173
|
+
case "bgRepeat":
|
174
|
+
acc.backgroundRepeat = value; // 直接使用传入的背景值
|
175
|
+
break;
|
176
|
+
default:
|
177
|
+
acc[key] = value; // 允许其他样式直接传入,理论上可以支持所有的CSS样式传入
|
178
|
+
}
|
179
|
+
|
180
|
+
return acc;
|
181
|
+
}, {});
|
182
|
+
};
|
@@ -1,64 +1,64 @@
|
|
1
|
-
.
|
2
|
-
position: relative;
|
3
|
-
overflow: hidden;
|
4
|
-
border: none;
|
5
|
-
border-radius: 6px;
|
6
|
-
cursor: pointer;
|
7
|
-
font-family: Arial, sans-serif;
|
8
|
-
font-weight: 500;
|
9
|
-
color: white;
|
10
|
-
background-color: #4caf50;
|
11
|
-
transition: background-color 0.3s ease;
|
12
|
-
user-select: none;
|
13
|
-
outline: none;
|
14
|
-
padding: 10px 20px;
|
15
|
-
}
|
16
|
-
|
17
|
-
.
|
18
|
-
background-color: #45a047;
|
19
|
-
}
|
20
|
-
|
21
|
-
.
|
22
|
-
background-color: #388e3c;
|
23
|
-
}
|
24
|
-
|
25
|
-
/* 不同大小 */
|
26
|
-
.
|
27
|
-
font-size: 12px;
|
28
|
-
padding: 6px 12px;
|
29
|
-
}
|
30
|
-
|
31
|
-
.
|
32
|
-
font-size: 14px;
|
33
|
-
padding: 10px 20px;
|
34
|
-
}
|
35
|
-
|
36
|
-
.
|
37
|
-
font-size: 18px;
|
38
|
-
padding: 14px 28px;
|
39
|
-
}
|
40
|
-
|
41
|
-
/* 禁用 */
|
42
|
-
.
|
43
|
-
background-color: #e0e0e0;
|
44
|
-
color: #a0a0a0;
|
45
|
-
cursor: not-allowed;
|
46
|
-
}
|
47
|
-
|
48
|
-
/* 波纹效果 */
|
49
|
-
.ripple {
|
50
|
-
position: absolute;
|
51
|
-
border-radius: 50%;
|
52
|
-
background: rgba(255, 255, 255, 0.6);
|
53
|
-
transform: scale(0);
|
54
|
-
animation: ripple-effect 600ms linear;
|
55
|
-
pointer-events: none;
|
56
|
-
z-index: 0;
|
57
|
-
}
|
58
|
-
|
59
|
-
@keyframes ripple-effect {
|
60
|
-
to {
|
61
|
-
transform: scale(4);
|
62
|
-
opacity: 0;
|
63
|
-
}
|
64
|
-
}
|
1
|
+
.materialBtn {
|
2
|
+
position: relative;
|
3
|
+
overflow: hidden;
|
4
|
+
border: none;
|
5
|
+
border-radius: 6px;
|
6
|
+
cursor: pointer;
|
7
|
+
font-family: Arial, sans-serif;
|
8
|
+
font-weight: 500;
|
9
|
+
color: white;
|
10
|
+
background-color: #4caf50;
|
11
|
+
transition: background-color 0.3s ease;
|
12
|
+
user-select: none;
|
13
|
+
outline: none;
|
14
|
+
padding: 10px 20px;
|
15
|
+
}
|
16
|
+
|
17
|
+
.materialBtn:hover:not(.materialBtnDisabled) {
|
18
|
+
background-color: #45a047;
|
19
|
+
}
|
20
|
+
|
21
|
+
.materialBtn:active:not(.materialBtnDisabled) {
|
22
|
+
background-color: #388e3c;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* 不同大小 */
|
26
|
+
.materialBtnSmall {
|
27
|
+
font-size: 12px;
|
28
|
+
padding: 6px 12px;
|
29
|
+
}
|
30
|
+
|
31
|
+
.materialBtnMedium {
|
32
|
+
font-size: 14px;
|
33
|
+
padding: 10px 20px;
|
34
|
+
}
|
35
|
+
|
36
|
+
.materialBtnLarge {
|
37
|
+
font-size: 18px;
|
38
|
+
padding: 14px 28px;
|
39
|
+
}
|
40
|
+
|
41
|
+
/* 禁用 */
|
42
|
+
.materialBtnDisabled {
|
43
|
+
background-color: #e0e0e0;
|
44
|
+
color: #a0a0a0;
|
45
|
+
cursor: not-allowed;
|
46
|
+
}
|
47
|
+
|
48
|
+
/* 波纹效果 */
|
49
|
+
.ripple {
|
50
|
+
position: absolute;
|
51
|
+
border-radius: 50%;
|
52
|
+
background: rgba(255, 255, 255, 0.6);
|
53
|
+
transform: scale(0);
|
54
|
+
animation: ripple-effect 600ms linear;
|
55
|
+
pointer-events: none;
|
56
|
+
z-index: 0;
|
57
|
+
}
|
58
|
+
|
59
|
+
@keyframes ripple-effect {
|
60
|
+
to {
|
61
|
+
transform: scale(4);
|
62
|
+
opacity: 0;
|
63
|
+
}
|
64
|
+
}
|
@@ -1,58 +1,69 @@
|
|
1
|
-
import React, { useRef } from "react";
|
2
|
-
import "./MaterialButton.css"
|
3
|
-
import { useTangoStyle } from "../CSSFab/useTangoStyle";
|
4
|
-
|
5
|
-
export default function MaterialButton({
|
6
|
-
size = "medium",
|
7
|
-
sx = {},
|
8
|
-
style = {},
|
9
|
-
className = "",
|
10
|
-
onClick,
|
11
|
-
children,
|
12
|
-
disabled = false,
|
13
|
-
...rest
|
14
|
-
}) {
|
15
|
-
|
16
|
-
|
17
|
-
const sxStyle = useTangoStyle(sx);
|
18
|
-
const combinedStyle = { ...sxStyle, ...style };
|
19
|
-
|
20
|
-
function handleRipple(e) {
|
21
|
-
if (disabled) return;
|
22
|
-
|
23
|
-
const button = buttonRef.current;
|
24
|
-
const circle = document.createElement("span");
|
25
|
-
const diameter = Math.max(button.clientWidth, button.clientHeight);
|
26
|
-
const radius = diameter / 2;
|
27
|
-
|
28
|
-
circle.classList.add(
|
29
|
-
circle.style.width = circle.style.height = `${diameter}px`;
|
30
|
-
circle.style.left = `${e.clientX - button.getBoundingClientRect().left - radius}px`;
|
31
|
-
circle.style.top = `${e.clientY - button.getBoundingClientRect().top - radius}px`;
|
32
|
-
|
33
|
-
const
|
34
|
-
if (
|
35
|
-
|
36
|
-
button.appendChild(circle);
|
37
|
-
}
|
38
|
-
|
39
|
-
const sizeClass = `
|
40
|
-
const combinedClassName =
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
{
|
53
|
-
|
54
|
-
{
|
55
|
-
|
56
|
-
|
57
|
-
}
|
58
|
-
|
1
|
+
import React, { useRef } from "react";
|
2
|
+
import styles from "./MaterialButton.module.css"; // 使用模块化 CSS
|
3
|
+
import { useTangoStyle } from "../CSSFab/useTangoStyle";
|
4
|
+
|
5
|
+
export default function MaterialButton({
|
6
|
+
size = "medium",
|
7
|
+
sx = {},
|
8
|
+
style = {},
|
9
|
+
className = "",
|
10
|
+
onClick,
|
11
|
+
children,
|
12
|
+
disabled = false,
|
13
|
+
...rest
|
14
|
+
}) {
|
15
|
+
const buttonRef = useRef(null);
|
16
|
+
|
17
|
+
const sxStyle = useTangoStyle(sx);
|
18
|
+
const combinedStyle = { ...sxStyle, ...style };
|
19
|
+
|
20
|
+
function handleRipple(e) {
|
21
|
+
if (disabled) return;
|
22
|
+
|
23
|
+
const button = buttonRef.current;
|
24
|
+
const circle = document.createElement("span");
|
25
|
+
const diameter = Math.max(button.clientWidth, button.clientHeight);
|
26
|
+
const radius = diameter / 2;
|
27
|
+
|
28
|
+
circle.classList.add(styles.ripple); // 模块化样式
|
29
|
+
circle.style.width = circle.style.height = `${diameter}px`;
|
30
|
+
circle.style.left = `${e.clientX - button.getBoundingClientRect().left - radius}px`;
|
31
|
+
circle.style.top = `${e.clientY - button.getBoundingClientRect().top - radius}px`;
|
32
|
+
|
33
|
+
const oldRipple = button.querySelector(`.${styles.ripple}`);
|
34
|
+
if (oldRipple) oldRipple.remove();
|
35
|
+
|
36
|
+
button.appendChild(circle);
|
37
|
+
}
|
38
|
+
|
39
|
+
const sizeClass = styles[`materialBtn${capitalize(size)}`]; // 动态大小样式
|
40
|
+
const combinedClassName = [
|
41
|
+
styles.materialBtn,
|
42
|
+
sizeClass,
|
43
|
+
disabled ? styles.materialBtnDisabled : "",
|
44
|
+
className, // 用户自定义 className(外部样式)
|
45
|
+
]
|
46
|
+
.filter(Boolean)
|
47
|
+
.join(" ");
|
48
|
+
|
49
|
+
return (
|
50
|
+
<button
|
51
|
+
ref={buttonRef}
|
52
|
+
className={combinedClassName}
|
53
|
+
style={combinedStyle}
|
54
|
+
onClick={(e) => {
|
55
|
+
handleRipple(e);
|
56
|
+
onClick?.(e);
|
57
|
+
}}
|
58
|
+
disabled={disabled}
|
59
|
+
{...rest}
|
60
|
+
>
|
61
|
+
{children}
|
62
|
+
</button>
|
63
|
+
);
|
64
|
+
}
|
65
|
+
|
66
|
+
// 辅助函数:首字母大写
|
67
|
+
function capitalize(str) {
|
68
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
69
|
+
}
|