tango-ui-cw 0.2.0 → 0.2.2
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 +10 -10
- package/dist/index.mjs +307 -307
- package/package.json +1 -1
- package/src/component/TButton/index.jsx +2 -2
- package/src/component/TDate/index.jsx +0 -1
- package/src/component/TDrawer/index.jsx +2 -2
- package/src/component/TInput/index.jsx +2 -3
- package/src/component/TLayout/index.jsx +0 -1
- package/src/component/TLine/index.jsx +2 -3
- package/src/component/TMark/index.jsx +2 -3
- package/src/component/TModal/index.jsx +2 -2
- package/src/component/TNotice/index.jsx +1 -1
- package/src/component/TSearch/index.jsx +2 -2
- package/src/component/TTable/index.jsx +2 -3
- package/src/component/TTooltip/index.jsx +2 -2
- package/src/component/Tango/store.js +0 -105
- package/src/component/Tools/WaterMark/WaterMark.jsx +0 -78
package/package.json
CHANGED
@@ -40,7 +40,7 @@ export default function Button(props) {
|
|
40
40
|
const combinedStyle = { ...sxStyle, ...userStyle };
|
41
41
|
|
42
42
|
// 定义属性类型
|
43
|
-
|
43
|
+
Button.propTypes = {
|
44
44
|
type: PropTypes.oneOf(["default", "transparent", "danger", "success"]), // 按钮类型:默认、透明、警告、成功
|
45
45
|
size: PropTypes.oneOf(["small", "medium", "large", "huge"]), // 按钮大小
|
46
46
|
sx: PropTypes.object, // 自定义样式对象
|
@@ -54,7 +54,7 @@ export default function Button(props) {
|
|
54
54
|
};
|
55
55
|
|
56
56
|
// 默认属性
|
57
|
-
|
57
|
+
Button.defaultProps = {
|
58
58
|
type: "default",
|
59
59
|
size: "medium",
|
60
60
|
sx: {},
|
@@ -60,7 +60,7 @@ export default function Drawer(props) {
|
|
60
60
|
);
|
61
61
|
};
|
62
62
|
|
63
|
-
|
63
|
+
Drawer.propTypes = {
|
64
64
|
children: PropTypes.node.isRequired,
|
65
65
|
title: PropTypes.string,
|
66
66
|
onText: PropTypes.string,
|
@@ -70,7 +70,7 @@ TDrawer.propTypes = {
|
|
70
70
|
type: PropTypes.oneOf(["top", "bottom", "left", "right"]),
|
71
71
|
};
|
72
72
|
|
73
|
-
|
73
|
+
Drawer.defaultProps = {
|
74
74
|
title: "基础标题",
|
75
75
|
onText: "确定",
|
76
76
|
cancelText: "取消",
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import React from "react";
|
2
1
|
import PropTypes from "prop-types";
|
3
2
|
import styles from "./TInput.module.css"; // 模块化 CSS
|
4
3
|
import { useTangoStyle } from "../CSSFab/useTangoStyle";
|
@@ -64,7 +63,7 @@ export default function Input(props) {
|
|
64
63
|
);
|
65
64
|
};
|
66
65
|
|
67
|
-
|
66
|
+
Input.propTypes = {
|
68
67
|
type: PropTypes.oneOf(["default", "textarea", "password"]),
|
69
68
|
size: PropTypes.oneOf(["small", "medium", "large", "huge"]),
|
70
69
|
sx: PropTypes.object,
|
@@ -79,7 +78,7 @@ TInput.propTypes = {
|
|
79
78
|
maxlength: PropTypes.number,
|
80
79
|
};
|
81
80
|
|
82
|
-
|
81
|
+
Input.defaultProps = {
|
83
82
|
type: "default",
|
84
83
|
size: "medium",
|
85
84
|
sx: {},
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import React from "react";
|
2
1
|
import PropTypes from "prop-types";
|
3
2
|
import styles from "./TLine.module.css"; // 使用 CSS Modules
|
4
3
|
import { useTangoStyle } from "../CSSFab/useTangoStyle";
|
@@ -29,7 +28,7 @@ export default function Line(props) {
|
|
29
28
|
);
|
30
29
|
};
|
31
30
|
|
32
|
-
|
31
|
+
Line.propTypes = {
|
33
32
|
sx: PropTypes.object,
|
34
33
|
size: PropTypes.oneOf(["small", "medium", "large", "huge"]),
|
35
34
|
style: PropTypes.object,
|
@@ -38,7 +37,7 @@ TLine.propTypes = {
|
|
38
37
|
children: PropTypes.node.isRequired,
|
39
38
|
};
|
40
39
|
|
41
|
-
|
40
|
+
Line.defaultProps = {
|
42
41
|
sx: {},
|
43
42
|
size: "medium",
|
44
43
|
style: {},
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import React from "react";
|
2
1
|
import PropTypes from "prop-types";
|
3
2
|
import styles from "./TMark.module.css"; // 使用 CSS Modules
|
4
3
|
import { useTangoStyle } from "../CSSFab/useTangoStyle";
|
@@ -49,7 +48,7 @@ export default function Mark(props) {
|
|
49
48
|
);
|
50
49
|
};
|
51
50
|
|
52
|
-
|
51
|
+
Mark.propTypes = {
|
53
52
|
color: PropTypes.string,
|
54
53
|
sx: PropTypes.object,
|
55
54
|
style: PropTypes.object,
|
@@ -59,7 +58,7 @@ TMark.propTypes = {
|
|
59
58
|
beauty: PropTypes.bool,
|
60
59
|
};
|
61
60
|
|
62
|
-
|
61
|
+
Mark.defaultProps = {
|
63
62
|
color: "default",
|
64
63
|
sx: {},
|
65
64
|
style: {},
|
@@ -57,7 +57,7 @@ export default function Modal(props) {
|
|
57
57
|
);
|
58
58
|
};
|
59
59
|
|
60
|
-
|
60
|
+
Modal.propTypes = {
|
61
61
|
children: PropTypes.node.isRequired,
|
62
62
|
title: PropTypes.string,
|
63
63
|
onText: PropTypes.string,
|
@@ -66,7 +66,7 @@ TModal.propTypes = {
|
|
66
66
|
onClose: PropTypes.func,
|
67
67
|
};
|
68
68
|
|
69
|
-
|
69
|
+
Modal.defaultProps = {
|
70
70
|
title: "基础标题",
|
71
71
|
onText: "确定",
|
72
72
|
cancelText: "取消",
|
@@ -28,7 +28,7 @@ export default function Notice({ type = "success", icon, message }) { // 使用
|
|
28
28
|
);
|
29
29
|
};
|
30
30
|
|
31
|
-
|
31
|
+
Notice.propTypes = {
|
32
32
|
type: PropTypes.oneOf(["success", "fail", "caution"]),
|
33
33
|
icon: PropTypes.string.isRequired,
|
34
34
|
message: PropTypes.string.isRequired,
|
@@ -58,7 +58,7 @@ export default function Search(props) {
|
|
58
58
|
);
|
59
59
|
};
|
60
60
|
|
61
|
-
|
61
|
+
Search.propTypes = {
|
62
62
|
size: PropTypes.oneOf(["small", "medium", "large", "huge"]),
|
63
63
|
sx: PropTypes.object,
|
64
64
|
style: PropTypes.object,
|
@@ -71,7 +71,7 @@ TSearch.propTypes = {
|
|
71
71
|
path: PropTypes.string,
|
72
72
|
};
|
73
73
|
|
74
|
-
|
74
|
+
Search.defaultProps = {
|
75
75
|
size: "medium",
|
76
76
|
sx: {},
|
77
77
|
style: {},
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import React from "react";
|
2
1
|
import PropTypes from "prop-types";
|
3
2
|
import { useTangoStyle } from "../CSSFab/useTangoStyle";
|
4
3
|
import styles from "./TTable.module.css";
|
@@ -49,7 +48,7 @@ export default function Table({
|
|
49
48
|
);
|
50
49
|
};
|
51
50
|
|
52
|
-
|
51
|
+
Table.propTypes = {
|
53
52
|
dataSource: PropTypes.array.isRequired,
|
54
53
|
columns: PropTypes.arrayOf(
|
55
54
|
PropTypes.shape({
|
@@ -64,7 +63,7 @@ TTable.propTypes = {
|
|
64
63
|
className: PropTypes.string,
|
65
64
|
};
|
66
65
|
|
67
|
-
|
66
|
+
Table.defaultProps = {
|
68
67
|
dataSource: [],
|
69
68
|
sx: {},
|
70
69
|
style: {},
|
@@ -21,13 +21,13 @@ export default function Tooltip({ children, tooltipText, placement = "top" }) {
|
|
21
21
|
);
|
22
22
|
};
|
23
23
|
|
24
|
-
|
24
|
+
Tooltip.propTypes = {
|
25
25
|
children: PropTypes.node.isRequired,
|
26
26
|
tooltipText: PropTypes.string.isRequired,
|
27
27
|
placement: PropTypes.oneOf(["top", "bottom", "right"]),
|
28
28
|
};
|
29
29
|
|
30
|
-
|
30
|
+
Tooltip.defaultProps = {
|
31
31
|
placement: "top",
|
32
32
|
};
|
33
33
|
|
@@ -1,105 +0,0 @@
|
|
1
|
-
import { useState, useEffect } from 'react';
|
2
|
-
|
3
|
-
class TangoStore extends EventTarget {
|
4
|
-
constructor(initialState, options = {}, persistentFields = []) {
|
5
|
-
super();
|
6
|
-
this.state = { ...initialState };
|
7
|
-
this.storageKey = options.storageKey || 'tango-store-state'; // 存储键名
|
8
|
-
this.Eternity = options.Eternity || false; // 是否启用持久化
|
9
|
-
this.storageType = options.Storage || 'local'; // 默认为 'local', 可以选择 'session'
|
10
|
-
this.persistentFields = new Set(persistentFields); // 将数组转换为 Set,便于查找
|
11
|
-
|
12
|
-
// 根据选择的存储类型来决定使用哪种存储
|
13
|
-
this.storage = this.storageType === 'session' ? sessionStorage : localStorage;
|
14
|
-
|
15
|
-
// 加载本地存储的状态
|
16
|
-
if (this.Eternity) {
|
17
|
-
const storedState = this.storage.getItem(this.storageKey);
|
18
|
-
if (storedState) {
|
19
|
-
try {
|
20
|
-
const parsedState = JSON.parse(storedState);
|
21
|
-
this.state = { ...this.state, ...parsedState };
|
22
|
-
} catch (e) {
|
23
|
-
console.error('Failed to load persisted state:', e);
|
24
|
-
}
|
25
|
-
}
|
26
|
-
}
|
27
|
-
}
|
28
|
-
|
29
|
-
setState(newState) {
|
30
|
-
const hasChanged = Object.keys(newState).some(
|
31
|
-
(key) => this.state[key] !== newState[key]
|
32
|
-
);
|
33
|
-
|
34
|
-
if (!hasChanged) {
|
35
|
-
return; // 状态未改变,不派发事件
|
36
|
-
}
|
37
|
-
|
38
|
-
this.state = { ...this.state, ...newState };
|
39
|
-
|
40
|
-
if (this.Eternity) {
|
41
|
-
// 如果启用了持久化
|
42
|
-
if (this.persistentFields.size > 0) {
|
43
|
-
// 仅持久化指定字段
|
44
|
-
const filteredState = Object.keys(this.state).reduce((acc, key) => {
|
45
|
-
if (this.persistentFields.has(key)) {
|
46
|
-
acc[key] = this.state[key];
|
47
|
-
}
|
48
|
-
return acc;
|
49
|
-
}, {});
|
50
|
-
try {
|
51
|
-
this.storage.setItem(this.storageKey, JSON.stringify(filteredState));
|
52
|
-
} catch (e) {
|
53
|
-
console.error('Failed to persist state:', e);
|
54
|
-
}
|
55
|
-
} else {
|
56
|
-
// 默认持久化所有字段
|
57
|
-
try {
|
58
|
-
this.storage.setItem(this.storageKey, JSON.stringify(this.state));
|
59
|
-
} catch (e) {
|
60
|
-
console.error('Failed to persist state:', e);
|
61
|
-
}
|
62
|
-
}
|
63
|
-
}
|
64
|
-
|
65
|
-
// 通知订阅者状态变化
|
66
|
-
this.dispatchEvent(new CustomEvent('change', { detail: this.state }));
|
67
|
-
}
|
68
|
-
|
69
|
-
getState() {
|
70
|
-
return this.state;
|
71
|
-
}
|
72
|
-
|
73
|
-
subscribe(callback) {
|
74
|
-
const listener = (e) => callback(e.detail);
|
75
|
-
this.addEventListener('change', listener);
|
76
|
-
return () => this.removeEventListener('change', listener); // 取消订阅
|
77
|
-
}
|
78
|
-
}
|
79
|
-
|
80
|
-
// 提供创建 store 的方法
|
81
|
-
export const createTangoStore = (initialState = {}, options = {}, persistentFields = []) => {
|
82
|
-
return new TangoStore(initialState, options, persistentFields);
|
83
|
-
};
|
84
|
-
|
85
|
-
// 提供 `useTango` Hook,供用户直接使用
|
86
|
-
export const useTango = (store, key, defaultValue = undefined) => {
|
87
|
-
// 增强安全机制,确保 key 不存在时返回默认值
|
88
|
-
const [state, setState] = useState(() => {
|
89
|
-
const currentState = store.getState();
|
90
|
-
return currentState.hasOwnProperty(key) ? currentState[key] : defaultValue;
|
91
|
-
});
|
92
|
-
|
93
|
-
useEffect(() => {
|
94
|
-
const unsubscribe = store.subscribe((newState) => {
|
95
|
-
if (newState.hasOwnProperty(key)) {
|
96
|
-
setState(newState[key]);
|
97
|
-
} else {
|
98
|
-
setState(defaultValue); // key 不存在时返回默认值
|
99
|
-
}
|
100
|
-
});
|
101
|
-
return () => unsubscribe();
|
102
|
-
}, [store, key, defaultValue]);
|
103
|
-
|
104
|
-
return state;
|
105
|
-
};
|
@@ -1,78 +0,0 @@
|
|
1
|
-
// 加水印组件
|
2
|
-
/**
|
3
|
-
* 为图片添加水印并返回处理后的图片URL
|
4
|
-
* @param {string} imageUrl - 图片的URL
|
5
|
-
* @param {Object} watermarkConfig - 水印配置对象
|
6
|
-
* @param {string} watermarkConfig.text - 水印内容
|
7
|
-
* @param {number} [watermarkConfig.fontSize=30] - 水印文字大小
|
8
|
-
* @param {string} [watermarkConfig.color='rgba(255, 255, 255, 0.5)'] - 水印文字颜色
|
9
|
-
* @param {number} [watermarkConfig.rotate=30] - 水印文字旋转度数
|
10
|
-
* @param {number} [watermarkConfig.spacing=100] - 水印文字间距
|
11
|
-
* @param {number} [watermarkConfig.lineHeight=30] - 水印文字行高
|
12
|
-
* @param {number} [watermarkConfig.opacity=0.5] - 水印文字透明度
|
13
|
-
* @returns {Promise<string>} - 返回处理后的图片URL
|
14
|
-
*/
|
15
|
-
export const addWatermarkToImage = (imageUrl, watermarkConfig) => {
|
16
|
-
return new Promise((resolve, reject) => {
|
17
|
-
const img = new Image();
|
18
|
-
img.crossOrigin = "anonymous"; // 解决跨域问题
|
19
|
-
img.src = imageUrl;
|
20
|
-
|
21
|
-
img.onload = () => {
|
22
|
-
const canvas = document.createElement("canvas");
|
23
|
-
const ctx = canvas.getContext("2d");
|
24
|
-
|
25
|
-
canvas.width = img.width;
|
26
|
-
canvas.height = img.height;
|
27
|
-
|
28
|
-
ctx.drawImage(img, 0, 0);
|
29
|
-
|
30
|
-
// 设置水印样式
|
31
|
-
ctx.font = `${watermarkConfig.fontSize || 30}px Arial`;
|
32
|
-
ctx.fillStyle = watermarkConfig.color || "rgba(255, 255, 255, 0.5)";
|
33
|
-
ctx.globalAlpha = watermarkConfig.opacity || 0.5;
|
34
|
-
|
35
|
-
const textWidth = ctx.measureText(watermarkConfig.text).width;
|
36
|
-
const textHeight = watermarkConfig.lineHeight || 30;
|
37
|
-
const spacing = watermarkConfig.spacing || 100;
|
38
|
-
const angle = ((watermarkConfig.rotate || 30) * Math.PI) / 180; // 将角度转换为弧度
|
39
|
-
|
40
|
-
// 保存初始状态
|
41
|
-
ctx.save();
|
42
|
-
// 将画布中心移到原点
|
43
|
-
ctx.translate(canvas.width / 2, canvas.height / 2);
|
44
|
-
// 旋转画布
|
45
|
-
ctx.rotate(angle);
|
46
|
-
// 将画布移回左上角
|
47
|
-
ctx.translate(-canvas.width / 2, -canvas.height / 2);
|
48
|
-
|
49
|
-
// 计算覆盖整个画布所需的起始点和步长
|
50
|
-
const diagonal = Math.sqrt(
|
51
|
-
canvas.width * canvas.width + canvas.height * canvas.height
|
52
|
-
);
|
53
|
-
const startX = -diagonal;
|
54
|
-
const startY = -diagonal;
|
55
|
-
const stepX = textWidth + spacing;
|
56
|
-
const stepY = textHeight + spacing;
|
57
|
-
|
58
|
-
for (let y = startY; y < canvas.height + diagonal; y += stepY) {
|
59
|
-
for (let x = startX; x < canvas.width + diagonal; x += stepX) {
|
60
|
-
ctx.fillText(watermarkConfig.text, x, y);
|
61
|
-
}
|
62
|
-
}
|
63
|
-
|
64
|
-
// 恢复画布到初始状态
|
65
|
-
ctx.restore();
|
66
|
-
|
67
|
-
// 根据图片URL的扩展名确定输出格式
|
68
|
-
const format = imageUrl.toLowerCase().endsWith(".png")
|
69
|
-
? "image/png"
|
70
|
-
: "image/jpeg";
|
71
|
-
resolve(canvas.toDataURL(format));
|
72
|
-
};
|
73
|
-
|
74
|
-
img.onerror = (error) => {
|
75
|
-
reject(new Error("图片加载失败", error));
|
76
|
-
};
|
77
|
-
});
|
78
|
-
};
|