tango-ui-cw 0.1.0 → 0.2.1
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 +889 -757
- 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 -72
- 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
@@ -1,108 +1,109 @@
|
|
1
|
-
.
|
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
|
-
.
|
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
|
-
.
|
25
|
-
font-size: 18px;
|
26
|
-
font-weight: bold;
|
27
|
-
margin-bottom: 16px;
|
28
|
-
display: flex;
|
29
|
-
justify-content: space-between;
|
30
|
-
}
|
31
|
-
|
32
|
-
.
|
33
|
-
margin-bottom: 24px;
|
34
|
-
}
|
35
|
-
|
36
|
-
.
|
37
|
-
display: flex;
|
38
|
-
justify-content: flex-end;
|
39
|
-
gap: 10px;
|
40
|
-
}
|
41
|
-
|
42
|
-
.
|
43
|
-
background-image: url('../../assets/关闭.png');
|
44
|
-
width: 15px;
|
45
|
-
height: 15px;
|
46
|
-
background-size: 100% 100%;
|
47
|
-
cursor: pointer;
|
48
|
-
}
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
}
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
}
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
}
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
}
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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,69 +1,75 @@
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
2
|
-
import PropTypes from "prop-types";
|
3
|
-
import "./TModal.css";
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
+
TModal.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
|
+
TModal.defaultProps = {
|
70
|
+
title: "基础标题",
|
71
|
+
onText: "确定",
|
72
|
+
cancelText: "取消",
|
73
|
+
open: false,
|
74
|
+
onClose: () => {},
|
75
|
+
};
|
@@ -1,52 +1,50 @@
|
|
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:
|
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
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
}
|
52
|
-
}
|
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,38 +1,37 @@
|
|
1
|
-
|
2
|
-
import
|
3
|
-
import
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
const [
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
}, 3000);
|
17
|
-
|
18
|
-
return () => clearTimeout(timer);
|
19
|
-
}, []);
|
20
|
-
|
21
|
-
if (!visible) return null;
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
+
TNotice.propTypes = {
|
32
|
+
type: PropTypes.oneOf(["success", "fail", "caution"]),
|
33
|
+
icon: PropTypes.string.isRequired,
|
34
|
+
message: PropTypes.string.isRequired,
|
35
|
+
};
|
36
|
+
|
37
|
+
|
@@ -1,54 +1,54 @@
|
|
1
|
-
import React from "react";
|
2
|
-
import { createRoot } from "react-dom/client"; // 使用 React 18 的 createRoot
|
3
|
-
import ClayNotice from "./index"; // 引入 ClayNotice 组件
|
4
|
-
import successIcon from "../../assets/Notice/成功.png";
|
5
|
-
import failIcon from "../../assets/Notice/失败.png";
|
6
|
-
import cautionIcon from "../../assets/Notice/警告.png";
|
7
|
-
|
8
|
-
// 创建全局通知容器
|
9
|
-
let root; // 用于缓存 React 根实例
|
10
|
-
|
11
|
-
export function useNotice() {
|
12
|
-
// 初始化通知容器
|
13
|
-
const initializeContainer = () => {
|
14
|
-
let container = document.getElementById("notification-container");
|
15
|
-
if (!container) {
|
16
|
-
container = document.createElement("div");
|
17
|
-
container.id = "notification-container";
|
18
|
-
document.body.appendChild(container);
|
19
|
-
}
|
20
|
-
|
21
|
-
if (!root) {
|
22
|
-
root = createRoot(container); // 仅初始化一次 createRoot
|
23
|
-
}
|
24
|
-
|
25
|
-
return container;
|
26
|
-
};
|
27
|
-
|
28
|
-
// 通知生成函数
|
29
|
-
const addNotice = (type, message) => {
|
30
|
-
initializeContainer(); // 确保容器已初始化
|
31
|
-
|
32
|
-
const iconMap = {
|
33
|
-
success: successIcon,
|
34
|
-
fail: failIcon,
|
35
|
-
caution: cautionIcon,
|
36
|
-
};
|
37
|
-
|
38
|
-
const icon = iconMap[type] || successIcon;
|
39
|
-
|
40
|
-
// 创建通知组件
|
41
|
-
const notice = (
|
42
|
-
<ClayNotice key={Date.now()} type={type} icon={icon} message={message} />
|
43
|
-
);
|
44
|
-
|
45
|
-
// 渲染通知
|
46
|
-
root.render(notice);
|
47
|
-
};
|
48
|
-
|
49
|
-
return {
|
50
|
-
success: (message) => addNotice("success", message),
|
51
|
-
fail: (message) => addNotice("fail", message),
|
52
|
-
caution: (message) => addNotice("caution", message),
|
53
|
-
};
|
54
|
-
}
|
1
|
+
import React from "react";
|
2
|
+
import { createRoot } from "react-dom/client"; // 使用 React 18 的 createRoot
|
3
|
+
import ClayNotice from "./index"; // 引入 ClayNotice 组件
|
4
|
+
import successIcon from "../../assets/Notice/成功.png";
|
5
|
+
import failIcon from "../../assets/Notice/失败.png";
|
6
|
+
import cautionIcon from "../../assets/Notice/警告.png";
|
7
|
+
|
8
|
+
// 创建全局通知容器
|
9
|
+
let root; // 用于缓存 React 根实例
|
10
|
+
|
11
|
+
export function useNotice() {
|
12
|
+
// 初始化通知容器
|
13
|
+
const initializeContainer = () => {
|
14
|
+
let container = document.getElementById("notification-container");
|
15
|
+
if (!container) {
|
16
|
+
container = document.createElement("div");
|
17
|
+
container.id = "notification-container";
|
18
|
+
document.body.appendChild(container);
|
19
|
+
}
|
20
|
+
|
21
|
+
if (!root) {
|
22
|
+
root = createRoot(container); // 仅初始化一次 createRoot
|
23
|
+
}
|
24
|
+
|
25
|
+
return container;
|
26
|
+
};
|
27
|
+
|
28
|
+
// 通知生成函数
|
29
|
+
const addNotice = (type, message) => {
|
30
|
+
initializeContainer(); // 确保容器已初始化
|
31
|
+
|
32
|
+
const iconMap = {
|
33
|
+
success: successIcon,
|
34
|
+
fail: failIcon,
|
35
|
+
caution: cautionIcon,
|
36
|
+
};
|
37
|
+
|
38
|
+
const icon = iconMap[type] || successIcon;
|
39
|
+
|
40
|
+
// 创建通知组件
|
41
|
+
const notice = (
|
42
|
+
<ClayNotice key={Date.now()} type={type} icon={icon} message={message} />
|
43
|
+
);
|
44
|
+
|
45
|
+
// 渲染通知
|
46
|
+
root.render(notice);
|
47
|
+
};
|
48
|
+
|
49
|
+
return {
|
50
|
+
success: (message) => addNotice("success", message),
|
51
|
+
fail: (message) => addNotice("fail", message),
|
52
|
+
caution: (message) => addNotice("caution", message),
|
53
|
+
};
|
54
|
+
}
|