tango-ui-cw 0.2.5 → 0.2.7
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.js +256 -15
- package/dist/index.mjs +26118 -1301
- package/package.json +11 -12
- package/src/component/CSSFab/useTangoStyle.jsx +0 -182
- package/src/component/MaterialButton/MaterialButton.module.css +0 -64
- package/src/component/MaterialButton/index.jsx +0 -69
- package/src/component/MaterialInput/MaterialInput.module.css +0 -37
- package/src/component/MaterialInput/index.jsx +0 -34
- package/src/component/TButton/TButton.module.css +0 -184
- package/src/component/TButton/index.jsx +0 -81
- package/src/component/TColorPicker/TColorPicker.module.css +0 -24
- package/src/component/TColorPicker/index.jsx +0 -107
- package/src/component/TDate/index.jsx +0 -145
- package/src/component/TDatePicker/TDatePicker.module.css +0 -12
- package/src/component/TDatePicker/index.jsx +0 -72
- package/src/component/TDrawer/TDrawer.module.css +0 -203
- package/src/component/TDrawer/index.jsx +0 -80
- package/src/component/TInput/TInput.module.css +0 -67
- package/src/component/TInput/index.jsx +0 -94
- package/src/component/TLayout/TLayout.css +0 -88
- package/src/component/TLayout/index.jsx +0 -76
- package/src/component/TLine/TLine.module.css +0 -52
- package/src/component/TLine/index.jsx +0 -47
- package/src/component/TMark/TMark.module.css +0 -6
- package/src/component/TMark/index.jsx +0 -68
- package/src/component/TModal/TModal.module.css +0 -109
- package/src/component/TModal/index.jsx +0 -75
- package/src/component/TNotice/TNotice.module.css +0 -50
- package/src/component/TNotice/index.jsx +0 -37
- package/src/component/TNotice/useNotice.jsx +0 -53
- package/src/component/TSearch/TSearch.module.css +0 -80
- package/src/component/TSearch/index.jsx +0 -86
- package/src/component/TSpace/TSpace.module.css +0 -43
- package/src/component/TSpace/index.jsx +0 -60
- package/src/component/TTable/TTable.module.css +0 -26
- package/src/component/TTable/index.jsx +0 -72
- package/src/component/TTooltip/TTooltip.module.css +0 -66
- package/src/component/TTooltip/index.jsx +0 -33
@@ -1,94 +0,0 @@
|
|
1
|
-
import PropTypes from "prop-types";
|
2
|
-
import styles from "./TInput.module.css"; // 模块化 CSS
|
3
|
-
import { useTangoStyle } from "../CSSFab/useTangoStyle";
|
4
|
-
|
5
|
-
export default function Input(props) {
|
6
|
-
const {
|
7
|
-
type = "default",
|
8
|
-
size = "medium",
|
9
|
-
sx = {},
|
10
|
-
style: userStyle = {},
|
11
|
-
className: userClassName = "", // 允许用户自定义 className
|
12
|
-
onClick,
|
13
|
-
onChange,
|
14
|
-
value,
|
15
|
-
defaultValue = "",
|
16
|
-
disabled = false,
|
17
|
-
placeholder = "",
|
18
|
-
maxlength
|
19
|
-
} = props;
|
20
|
-
|
21
|
-
|
22
|
-
const isControlled = value !== undefined && onChange !== undefined;
|
23
|
-
|
24
|
-
const baseClass = styles.input;
|
25
|
-
const sizeClass = styles[`input${size.charAt(0).toUpperCase() + size.slice(1)}`] || "";
|
26
|
-
const disabledClass = disabled ? styles.inputDisabled : "";
|
27
|
-
const combinedClassName = `${baseClass} ${sizeClass} ${disabledClass} ${userClassName}`.trim();
|
28
|
-
|
29
|
-
const sxStyle = useTangoStyle(sx);
|
30
|
-
const combinedStyle = { ...sxStyle, ...userStyle };
|
31
|
-
|
32
|
-
const inputType = type === "password" ? "password" : "text";
|
33
|
-
|
34
|
-
return (
|
35
|
-
<div>
|
36
|
-
{type === "textarea" ? (
|
37
|
-
<textarea
|
38
|
-
className={combinedClassName}
|
39
|
-
style={combinedStyle}
|
40
|
-
onClick={onClick}
|
41
|
-
onChange={onChange && ((e) => onChange(e.target.value))}
|
42
|
-
value={isControlled ? value : undefined}
|
43
|
-
defaultValue={!isControlled ? defaultValue : undefined}
|
44
|
-
disabled={disabled}
|
45
|
-
placeholder={placeholder}
|
46
|
-
maxLength={maxlength}
|
47
|
-
/>
|
48
|
-
) : (
|
49
|
-
<input
|
50
|
-
className={combinedClassName}
|
51
|
-
style={combinedStyle}
|
52
|
-
type={inputType}
|
53
|
-
onClick={onClick}
|
54
|
-
onChange={onChange && ((e) => onChange(e.target.value))}
|
55
|
-
value={isControlled ? value : undefined}
|
56
|
-
defaultValue={!isControlled ? defaultValue : undefined}
|
57
|
-
disabled={disabled}
|
58
|
-
placeholder={placeholder}
|
59
|
-
maxLength={maxlength}
|
60
|
-
/>
|
61
|
-
)}
|
62
|
-
</div>
|
63
|
-
);
|
64
|
-
};
|
65
|
-
|
66
|
-
Input.propTypes = {
|
67
|
-
type: PropTypes.oneOf(["default", "textarea", "password"]),
|
68
|
-
size: PropTypes.oneOf(["small", "medium", "large", "huge"]),
|
69
|
-
sx: PropTypes.object,
|
70
|
-
style: PropTypes.object,
|
71
|
-
onClick: PropTypes.func,
|
72
|
-
onChange: PropTypes.func,
|
73
|
-
className: PropTypes.string,
|
74
|
-
value: PropTypes.string,
|
75
|
-
defaultValue: PropTypes.string,
|
76
|
-
disabled: PropTypes.bool,
|
77
|
-
placeholder: PropTypes.string,
|
78
|
-
maxlength: PropTypes.number,
|
79
|
-
};
|
80
|
-
|
81
|
-
Input.defaultProps = {
|
82
|
-
type: "default",
|
83
|
-
size: "medium",
|
84
|
-
sx: {},
|
85
|
-
style: {},
|
86
|
-
onClick: () => {},
|
87
|
-
className: "",
|
88
|
-
onChange: undefined,
|
89
|
-
value: undefined,
|
90
|
-
defaultValue: "",
|
91
|
-
disabled: false,
|
92
|
-
placeholder: "",
|
93
|
-
maxlength: 524288,
|
94
|
-
};
|
@@ -1,88 +0,0 @@
|
|
1
|
-
/* 公共样式 */
|
2
|
-
html,
|
3
|
-
body {
|
4
|
-
height: 100%;
|
5
|
-
margin: 0;
|
6
|
-
padding: 0;
|
7
|
-
box-sizing: border-box;
|
8
|
-
}
|
9
|
-
|
10
|
-
.ultra {
|
11
|
-
display: flex;
|
12
|
-
flex-direction: column;
|
13
|
-
width: 100%;
|
14
|
-
height: 100%;
|
15
|
-
background-color: #f0f2f5;
|
16
|
-
border-radius: 8px;
|
17
|
-
overflow: hidden;
|
18
|
-
}
|
19
|
-
|
20
|
-
.clay-header {
|
21
|
-
background-color: #96d498;
|
22
|
-
color: #fff;
|
23
|
-
text-align: center;
|
24
|
-
height: 64px;
|
25
|
-
line-height: 64px;
|
26
|
-
}
|
27
|
-
|
28
|
-
.clay-main {
|
29
|
-
display: flex;
|
30
|
-
flex: 1; /* 占据剩余高度 */
|
31
|
-
width: 100%; /* 确保子元素水平分布 */
|
32
|
-
min-height: 120px;
|
33
|
-
display: flex;
|
34
|
-
align-items: center;
|
35
|
-
justify-content: center;
|
36
|
-
background-color: #4caf50;
|
37
|
-
color: #fff;
|
38
|
-
|
39
|
-
}
|
40
|
-
|
41
|
-
.clay-aside {
|
42
|
-
background-color: #6ccb6f;
|
43
|
-
color: #fff;
|
44
|
-
text-align: center;
|
45
|
-
padding: 16px;
|
46
|
-
min-width: 120px;
|
47
|
-
min-height: 120px;
|
48
|
-
display: flex;
|
49
|
-
align-items: center;
|
50
|
-
justify-content: center;
|
51
|
-
}
|
52
|
-
|
53
|
-
.clay-right {
|
54
|
-
flex: 3;
|
55
|
-
display: flex;
|
56
|
-
flex-direction: column; /* 确保右侧是上下布局 */
|
57
|
-
}
|
58
|
-
|
59
|
-
.clay-content {
|
60
|
-
background-color: #4caf50;
|
61
|
-
color: #fff;
|
62
|
-
flex: 1;
|
63
|
-
text-align: center;
|
64
|
-
padding: 16px;
|
65
|
-
min-height: 120px;
|
66
|
-
display: flex;
|
67
|
-
align-items: center;
|
68
|
-
justify-content: center;
|
69
|
-
|
70
|
-
}
|
71
|
-
|
72
|
-
.clay-footer {
|
73
|
-
background-color: #96d498;
|
74
|
-
color: #fff;
|
75
|
-
text-align: center;
|
76
|
-
height: 64px;
|
77
|
-
line-height: 64px;
|
78
|
-
}
|
79
|
-
|
80
|
-
/* 支持自适应布局 */
|
81
|
-
@media (max-width: 768px) {
|
82
|
-
.ultra {
|
83
|
-
flex-direction: column;
|
84
|
-
}
|
85
|
-
.clay-main {
|
86
|
-
flex-direction: column; /* 主内容区域改为竖向排列 */
|
87
|
-
}
|
88
|
-
}
|
@@ -1,76 +0,0 @@
|
|
1
|
-
import PropTypes from "prop-types";
|
2
|
-
import "./TLayout.css";
|
3
|
-
|
4
|
-
// 定义基本组件
|
5
|
-
export const Header = ({ children }) => <header>{children}</header>;
|
6
|
-
export const Aside = ({ children }) => <aside>{children}</aside>;
|
7
|
-
export const Content = ({ children }) => <div>{children}</div>;
|
8
|
-
export const Footer = ({ children }) => <footer>{children}</footer>;
|
9
|
-
|
10
|
-
export default function Layout(props) {
|
11
|
-
const { children, type, className: userClassName = "" } = props;
|
12
|
-
const className = `clay-layout clay-layout-${type} ${userClassName}`;
|
13
|
-
|
14
|
-
return (
|
15
|
-
<div className={className}>
|
16
|
-
{/* 第一种:上中下布局 */}
|
17
|
-
{type === "top-middle-bottom" && (
|
18
|
-
<div className="ultra">
|
19
|
-
<header className="clay-header">{children[0]}</header>
|
20
|
-
<main className="clay-main">{children[1]}</main>
|
21
|
-
<footer className="clay-footer">{children[2]}</footer>
|
22
|
-
</div>
|
23
|
-
)}
|
24
|
-
|
25
|
-
{/* 第二种:上下布局,下部分是左右布局 */}
|
26
|
-
{type === "top-bottom-split" && (
|
27
|
-
<div className="ultra">
|
28
|
-
<header className="clay-header">{children[0]}</header>
|
29
|
-
<main className="clay-main">
|
30
|
-
<aside className="clay-aside">{children[1]}</aside>
|
31
|
-
<div className="clay-content">{children[2]}</div>
|
32
|
-
</main>
|
33
|
-
</div>
|
34
|
-
)}
|
35
|
-
|
36
|
-
{/* 第三种:左右布局,右侧分为上下布局 */}
|
37
|
-
{type === "left-right-top-bottom" && (
|
38
|
-
<>
|
39
|
-
<header className="clay-header">{children[0]}</header>
|
40
|
-
<div className="clay-main">
|
41
|
-
<aside className="clay-aside">{children[1]}</aside>
|
42
|
-
<div className="clay-right">
|
43
|
-
<header className="clay-header">{children[2]}</header>
|
44
|
-
<div className="clay-content">{children[3]}</div>
|
45
|
-
</div>
|
46
|
-
</div>
|
47
|
-
</>
|
48
|
-
)}
|
49
|
-
|
50
|
-
{/* 第四种:左右布局,右侧分为上中下布局 */}
|
51
|
-
{type === "left-right-three-parts" && (
|
52
|
-
<div className="ultra">
|
53
|
-
<aside className="clay-aside">{children[0]}</aside>
|
54
|
-
<div className="clay-right">
|
55
|
-
<header className="clay-header">{children[1]}</header>
|
56
|
-
<main className="clay-main">{children[2]}</main>
|
57
|
-
<footer className="clay-footer">{children[3]}</footer>
|
58
|
-
</div>
|
59
|
-
</div>
|
60
|
-
)}
|
61
|
-
</div>
|
62
|
-
);
|
63
|
-
};
|
64
|
-
|
65
|
-
Layout.propTypes = {
|
66
|
-
children: PropTypes.node.isRequired,
|
67
|
-
className: PropTypes.string, // 添加 className PropTypes
|
68
|
-
|
69
|
-
type: PropTypes.oneOf([
|
70
|
-
"top-middle-bottom",
|
71
|
-
"top-bottom-split",
|
72
|
-
"left-right-top-bottom",
|
73
|
-
"left-right-three-parts",
|
74
|
-
]).isRequired,
|
75
|
-
};
|
76
|
-
|
@@ -1,52 +0,0 @@
|
|
1
|
-
.line {
|
2
|
-
display: flex;
|
3
|
-
align-items: center;
|
4
|
-
justify-content: center;
|
5
|
-
position: relative;
|
6
|
-
width: 100%;
|
7
|
-
}
|
8
|
-
|
9
|
-
.lineSmall {
|
10
|
-
margin: 2px 0;
|
11
|
-
}
|
12
|
-
|
13
|
-
.lineMedium {
|
14
|
-
margin: 6px 0;
|
15
|
-
}
|
16
|
-
|
17
|
-
.lineLarge {
|
18
|
-
margin: 10px 0;
|
19
|
-
}
|
20
|
-
|
21
|
-
.lineHuge {
|
22
|
-
margin: 15px 0;
|
23
|
-
}
|
24
|
-
|
25
|
-
.line::before,
|
26
|
-
.line::after {
|
27
|
-
content: "";
|
28
|
-
flex: 1;
|
29
|
-
height: 1px;
|
30
|
-
background-color: #b2b2b2;
|
31
|
-
}
|
32
|
-
|
33
|
-
.line::before {
|
34
|
-
margin-right: 10px;
|
35
|
-
}
|
36
|
-
|
37
|
-
.line::after {
|
38
|
-
margin-left: 10px;
|
39
|
-
}
|
40
|
-
|
41
|
-
.lineNoText::before,
|
42
|
-
.lineNoText::after {
|
43
|
-
margin: 0;
|
44
|
-
}
|
45
|
-
|
46
|
-
.lineText {
|
47
|
-
padding: 0 5px;
|
48
|
-
color: inherit;
|
49
|
-
background-color: transparent;
|
50
|
-
white-space: nowrap;
|
51
|
-
z-index: 1;
|
52
|
-
}
|
@@ -1,47 +0,0 @@
|
|
1
|
-
import PropTypes from "prop-types";
|
2
|
-
import styles from "./TLine.module.css"; // 使用 CSS Modules
|
3
|
-
import { useTangoStyle } from "../CSSFab/useTangoStyle";
|
4
|
-
|
5
|
-
export default function Line(props) {
|
6
|
-
// 接收属性参数,调整Space样式
|
7
|
-
const {
|
8
|
-
sx = {},
|
9
|
-
style: userStyle = {},
|
10
|
-
className: userClassName = "",
|
11
|
-
onClick,
|
12
|
-
children,
|
13
|
-
size = "medium",
|
14
|
-
} = props;
|
15
|
-
|
16
|
-
const hasText = !!children;
|
17
|
-
const sizeClass = styles[`line${size.charAt(0).toUpperCase() + size.slice(1)}`] || "";
|
18
|
-
const textClass = hasText ? styles.lineHasText : styles.lineNoText;
|
19
|
-
const combinedClassName = `${styles.line} ${sizeClass} ${textClass} ${userClassName}`.trim();
|
20
|
-
|
21
|
-
const sxStyle = useTangoStyle(sx);
|
22
|
-
const combinedStyle = { ...sxStyle, ...userStyle };
|
23
|
-
|
24
|
-
return (
|
25
|
-
<div style={combinedStyle} onClick={onClick} className={combinedClassName}>
|
26
|
-
{hasText && <div className={styles.lineText}>{children}</div>}
|
27
|
-
</div>
|
28
|
-
);
|
29
|
-
};
|
30
|
-
|
31
|
-
Line.propTypes = {
|
32
|
-
sx: PropTypes.object,
|
33
|
-
size: PropTypes.oneOf(["small", "medium", "large", "huge"]),
|
34
|
-
style: PropTypes.object,
|
35
|
-
onClick: PropTypes.func,
|
36
|
-
className: PropTypes.string,
|
37
|
-
children: PropTypes.node.isRequired,
|
38
|
-
};
|
39
|
-
|
40
|
-
Line.defaultProps = {
|
41
|
-
sx: {},
|
42
|
-
size: "medium",
|
43
|
-
style: {},
|
44
|
-
onClick: () => {},
|
45
|
-
className: "",
|
46
|
-
};
|
47
|
-
|
@@ -1,68 +0,0 @@
|
|
1
|
-
import PropTypes from "prop-types";
|
2
|
-
import styles from "./TMark.module.css"; // 使用 CSS Modules
|
3
|
-
import { useTangoStyle } from "../CSSFab/useTangoStyle";
|
4
|
-
|
5
|
-
export default function Mark(props) {
|
6
|
-
const {
|
7
|
-
sx = {},
|
8
|
-
style: userStyle = {},
|
9
|
-
className: userClassName = "",
|
10
|
-
onClick,
|
11
|
-
children,
|
12
|
-
color = "default",
|
13
|
-
beauty = false, // 是否使用新样式
|
14
|
-
} = props;
|
15
|
-
const sxStyle = useTangoStyle(sx);
|
16
|
-
|
17
|
-
const backgroundColor = color === "default" ? "#ffe28d" : color;
|
18
|
-
|
19
|
-
const defaultStyle = {
|
20
|
-
width: "auto",
|
21
|
-
height: "auto",
|
22
|
-
display: "inline-block",
|
23
|
-
};
|
24
|
-
|
25
|
-
const newStyle = beauty
|
26
|
-
? {
|
27
|
-
padding: "4px 8px",
|
28
|
-
borderRadius: "4px",
|
29
|
-
}
|
30
|
-
: {};
|
31
|
-
|
32
|
-
const combinedStyle = {
|
33
|
-
backgroundColor,
|
34
|
-
...defaultStyle,
|
35
|
-
...newStyle,
|
36
|
-
...sxStyle,
|
37
|
-
...userStyle,
|
38
|
-
};
|
39
|
-
|
40
|
-
return (
|
41
|
-
<div
|
42
|
-
style={combinedStyle}
|
43
|
-
onClick={onClick}
|
44
|
-
className={`${styles.mark} ${userClassName}`}
|
45
|
-
>
|
46
|
-
{children}
|
47
|
-
</div>
|
48
|
-
);
|
49
|
-
};
|
50
|
-
|
51
|
-
Mark.propTypes = {
|
52
|
-
color: PropTypes.string,
|
53
|
-
sx: PropTypes.object,
|
54
|
-
style: PropTypes.object,
|
55
|
-
onClick: PropTypes.func,
|
56
|
-
className: PropTypes.string,
|
57
|
-
children: PropTypes.node.isRequired,
|
58
|
-
beauty: PropTypes.bool,
|
59
|
-
};
|
60
|
-
|
61
|
-
Mark.defaultProps = {
|
62
|
-
color: "default",
|
63
|
-
sx: {},
|
64
|
-
style: {},
|
65
|
-
onClick: () => {},
|
66
|
-
className: "",
|
67
|
-
beauty: false,
|
68
|
-
};
|
@@ -1,109 +0,0 @@
|
|
1
|
-
.modalOverlay {
|
2
|
-
position: fixed;
|
3
|
-
top: 0;
|
4
|
-
left: 0;
|
5
|
-
width: 100vw;
|
6
|
-
height: 100vh;
|
7
|
-
background-color: rgba(0, 0, 0, 0.5);
|
8
|
-
z-index: 999;
|
9
|
-
display: flex;
|
10
|
-
justify-content: center;
|
11
|
-
align-items: center;
|
12
|
-
}
|
13
|
-
|
14
|
-
.modalContainer {
|
15
|
-
background-color: #fff;
|
16
|
-
padding: 20px;
|
17
|
-
border-radius: 8px;
|
18
|
-
width: 520px;
|
19
|
-
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
20
|
-
position: relative;
|
21
|
-
margin-top: -350px;
|
22
|
-
}
|
23
|
-
|
24
|
-
.modalHeader {
|
25
|
-
font-size: 18px;
|
26
|
-
font-weight: bold;
|
27
|
-
margin-bottom: 16px;
|
28
|
-
display: flex;
|
29
|
-
justify-content: space-between;
|
30
|
-
}
|
31
|
-
|
32
|
-
.modalContent {
|
33
|
-
margin-bottom: 24px;
|
34
|
-
}
|
35
|
-
|
36
|
-
.modalFooter {
|
37
|
-
display: flex;
|
38
|
-
justify-content: flex-end;
|
39
|
-
gap: 10px;
|
40
|
-
}
|
41
|
-
|
42
|
-
.modalCloseBtn {
|
43
|
-
background-image: url('../../assets/关闭.png');
|
44
|
-
width: 15px;
|
45
|
-
height: 15px;
|
46
|
-
background-size: 100% 100%;
|
47
|
-
cursor: pointer;
|
48
|
-
}
|
49
|
-
|
50
|
-
/* 过渡动画 */
|
51
|
-
@keyframes fade-in {
|
52
|
-
from {
|
53
|
-
opacity: 0;
|
54
|
-
}
|
55
|
-
to {
|
56
|
-
opacity: 1;
|
57
|
-
}
|
58
|
-
}
|
59
|
-
|
60
|
-
@keyframes fade-out {
|
61
|
-
from {
|
62
|
-
opacity: 1;
|
63
|
-
}
|
64
|
-
to {
|
65
|
-
opacity: 0;
|
66
|
-
}
|
67
|
-
}
|
68
|
-
|
69
|
-
@keyframes scale-in {
|
70
|
-
from {
|
71
|
-
transform: scale(0.8);
|
72
|
-
opacity: 0;
|
73
|
-
}
|
74
|
-
to {
|
75
|
-
transform: scale(1);
|
76
|
-
opacity: 1;
|
77
|
-
}
|
78
|
-
}
|
79
|
-
|
80
|
-
@keyframes scale-out {
|
81
|
-
from {
|
82
|
-
transform: scale(1);
|
83
|
-
opacity: 1;
|
84
|
-
}
|
85
|
-
to {
|
86
|
-
transform: scale(0.8);
|
87
|
-
opacity: 0;
|
88
|
-
}
|
89
|
-
}
|
90
|
-
|
91
|
-
.fadeIn {
|
92
|
-
animation: fade-in 0.3s ease-in-out;
|
93
|
-
-webkit-animation: fade-in 0.3s ease-in-out;
|
94
|
-
}
|
95
|
-
|
96
|
-
.fadeOut {
|
97
|
-
animation: fade-out 0.3s ease-in-out;
|
98
|
-
-webkit-animation: fade-out 0.3s ease-in-out;
|
99
|
-
}
|
100
|
-
|
101
|
-
.scaleIn {
|
102
|
-
animation: scale-in 0.3s ease-in-out;
|
103
|
-
-webkit-animation: scale-in 0.3s ease-in-out;
|
104
|
-
}
|
105
|
-
|
106
|
-
.scaleOut {
|
107
|
-
animation: scale-out 0.3s ease-in-out;
|
108
|
-
-webkit-animation: scale-out 0.3s ease-in-out;
|
109
|
-
}
|
@@ -1,75 +0,0 @@
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
2
|
-
import PropTypes from "prop-types";
|
3
|
-
import styles from "./TModal.module.css"; // CSS Modules 导入
|
4
|
-
import TButton from "../TButton/index";
|
5
|
-
|
6
|
-
export default function Modal(props) {
|
7
|
-
const { children, title, onText, cancelText, open, onClose } = props;
|
8
|
-
const [showAnimation, setShowAnimation] = useState(false); // 控制是否展示 Modal
|
9
|
-
const [closing, setClosing] = useState(false); // 标志是否在关闭动画中
|
10
|
-
|
11
|
-
useEffect(() => {
|
12
|
-
if (open) {
|
13
|
-
setShowAnimation(true);
|
14
|
-
setClosing(false);
|
15
|
-
} else if (showAnimation) {
|
16
|
-
setClosing(true);
|
17
|
-
setTimeout(() => {
|
18
|
-
setShowAnimation(false);
|
19
|
-
setClosing(false);
|
20
|
-
}, 300);
|
21
|
-
}
|
22
|
-
}, [open]);
|
23
|
-
|
24
|
-
function ok() {
|
25
|
-
console.log("确定按钮");
|
26
|
-
if (onClose) onClose();
|
27
|
-
}
|
28
|
-
|
29
|
-
return (
|
30
|
-
<>
|
31
|
-
{showAnimation && (
|
32
|
-
<div
|
33
|
-
className={`${styles.modalOverlay} ${
|
34
|
-
closing ? styles.fadeOut : styles.fadeIn
|
35
|
-
}`}
|
36
|
-
>
|
37
|
-
<div
|
38
|
-
className={`${styles.modalContainer} ${
|
39
|
-
closing ? styles.scaleOut : styles.scaleIn
|
40
|
-
}`}
|
41
|
-
>
|
42
|
-
<div className={styles.modalHeader}>
|
43
|
-
<h3>{title}</h3>
|
44
|
-
<div className={styles.modalCloseBtn} onClick={onClose}></div>
|
45
|
-
</div>
|
46
|
-
<div className={styles.modalContent}>{children}</div>
|
47
|
-
<div className={styles.modalFooter}>
|
48
|
-
<TButton type="success" onClick={ok}>
|
49
|
-
{onText}
|
50
|
-
</TButton>
|
51
|
-
<TButton onClick={onClose}>{cancelText}</TButton>
|
52
|
-
</div>
|
53
|
-
</div>
|
54
|
-
</div>
|
55
|
-
)}
|
56
|
-
</>
|
57
|
-
);
|
58
|
-
};
|
59
|
-
|
60
|
-
Modal.propTypes = {
|
61
|
-
children: PropTypes.node.isRequired,
|
62
|
-
title: PropTypes.string,
|
63
|
-
onText: PropTypes.string,
|
64
|
-
cancelText: PropTypes.string,
|
65
|
-
open: PropTypes.bool,
|
66
|
-
onClose: PropTypes.func,
|
67
|
-
};
|
68
|
-
|
69
|
-
Modal.defaultProps = {
|
70
|
-
title: "基础标题",
|
71
|
-
onText: "确定",
|
72
|
-
cancelText: "取消",
|
73
|
-
open: false,
|
74
|
-
onClose: () => {},
|
75
|
-
};
|
@@ -1,50 +0,0 @@
|
|
1
|
-
.notice {
|
2
|
-
display: inline-flex;
|
3
|
-
align-items: center;
|
4
|
-
justify-content: start;
|
5
|
-
padding: 8px 10px 8px 11px;
|
6
|
-
text-align: left;
|
7
|
-
border-radius: 8px;
|
8
|
-
box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08),
|
9
|
-
0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
|
10
|
-
background-color: white;
|
11
|
-
color: black;
|
12
|
-
position: absolute;
|
13
|
-
top: 20px;
|
14
|
-
left: 50%;
|
15
|
-
transform: translateX(-50%);
|
16
|
-
animation: slideDown 0.1s ease-out;
|
17
|
-
transition: opacity 0.3s ease-out, transform 0.5s ease-out;
|
18
|
-
}
|
19
|
-
|
20
|
-
.notice img {
|
21
|
-
width: 20px;
|
22
|
-
height: 20px;
|
23
|
-
margin-right: 8px;
|
24
|
-
flex-shrink: 0;
|
25
|
-
}
|
26
|
-
|
27
|
-
.notice span {
|
28
|
-
display: inline-block;
|
29
|
-
vertical-align: middle;
|
30
|
-
}
|
31
|
-
|
32
|
-
.fadeOut {
|
33
|
-
opacity: 0;
|
34
|
-
transform: translateX(-50%) translateY(-20px);
|
35
|
-
}
|
36
|
-
|
37
|
-
@keyframes slideDown {
|
38
|
-
0% {
|
39
|
-
transform: translateX(-50%) translateY(-50px);
|
40
|
-
opacity: 0;
|
41
|
-
}
|
42
|
-
90% {
|
43
|
-
transform: translateX(-50%) translateY(8px);
|
44
|
-
opacity: 1;
|
45
|
-
}
|
46
|
-
100% {
|
47
|
-
transform: translateX(-50%) translateY(0);
|
48
|
-
opacity: 1;
|
49
|
-
}
|
50
|
-
}
|
@@ -1,37 +0,0 @@
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
2
|
-
import PropTypes from "prop-types";
|
3
|
-
import styles from "./TNotice.module.css";
|
4
|
-
|
5
|
-
export default function Notice({ type = "success", icon, message }) { // 使用默认参数
|
6
|
-
const [visible, setVisible] = useState(true);
|
7
|
-
const [isFading, setIsFading] = useState(false);
|
8
|
-
|
9
|
-
useEffect(() => {
|
10
|
-
const timer = setTimeout(() => {
|
11
|
-
setIsFading(true);
|
12
|
-
const timer2 = setTimeout(() => {
|
13
|
-
setVisible(false);
|
14
|
-
}, 300);
|
15
|
-
return () => clearTimeout(timer2);
|
16
|
-
}, 3000);
|
17
|
-
|
18
|
-
return () => clearTimeout(timer);
|
19
|
-
}, []);
|
20
|
-
|
21
|
-
if (!visible) return null;
|
22
|
-
|
23
|
-
return (
|
24
|
-
<div className={`${styles.notice} ${isFading ? styles.fadeOut : ""}`}>
|
25
|
-
<img src={icon} alt={type} />
|
26
|
-
<span>{message}</span>
|
27
|
-
</div>
|
28
|
-
);
|
29
|
-
};
|
30
|
-
|
31
|
-
Notice.propTypes = {
|
32
|
-
type: PropTypes.oneOf(["success", "fail", "caution"]),
|
33
|
-
icon: PropTypes.string.isRequired,
|
34
|
-
message: PropTypes.string.isRequired,
|
35
|
-
};
|
36
|
-
|
37
|
-
|