@tsingroc/tsingroc-components 3.13.4 → 3.14.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.
Files changed (39) hide show
  1. package/dist/components/TsingrocTheme.js +1 -1
  2. package/dist/components/TsingrocTheme.js.map +1 -1
  3. package/dist/deckgl/TiandituLayer.js +6 -17
  4. package/dist/deckgl/TiandituLayer.js.map +1 -1
  5. package/dist/deckgl/WeatherData.d.ts +3 -3
  6. package/dist/echarts/index.js +1 -1
  7. package/dist/echarts/index.js.map +1 -1
  8. package/dist/echarts/series.d.ts +44 -0
  9. package/dist/echarts/series.js +54 -1
  10. package/dist/echarts/series.js.map +1 -1
  11. package/package.json +3 -3
  12. package/src/components/Auth.tsx +389 -0
  13. package/src/components/Calendar.tsx +182 -0
  14. package/src/components/CircularProgress.tsx +38 -0
  15. package/src/components/Header.tsx +136 -0
  16. package/src/components/ImageBackground.tsx +58 -0
  17. package/src/components/IndicatorLight.tsx +106 -0
  18. package/src/components/LineChartEditor.tsx +558 -0
  19. package/src/components/LineChartTable.tsx +285 -0
  20. package/src/components/LinkedLineChart.tsx +223 -0
  21. package/src/components/QuickDateRangePicker.tsx +84 -0
  22. package/src/components/SegmentedButtons.tsx +46 -0
  23. package/src/components/Sidebar.tsx +250 -0
  24. package/src/components/TsingrocDatePicker.tsx +103 -0
  25. package/src/components/TsingrocTheme.tsx +47 -0
  26. package/src/components/UserButton.tsx +152 -0
  27. package/src/components/VerticalColorLegend.tsx +73 -0
  28. package/src/components/WeatherMap.tsx +521 -0
  29. package/src/deckgl/TiandituLayer.ts +56 -0
  30. package/src/deckgl/WeatherData.ts +157 -0
  31. package/src/deckgl/index.ts +4 -0
  32. package/src/echarts/coordinateSystem.ts +132 -0
  33. package/src/echarts/gl.ts +158 -0
  34. package/src/echarts/index.ts +120 -0
  35. package/src/echarts/legend.ts +36 -0
  36. package/src/echarts/radar.ts +46 -0
  37. package/src/echarts/series.ts +441 -0
  38. package/src/echarts/tooltip.ts +17 -0
  39. package/src/index.ts +79 -0
@@ -0,0 +1,182 @@
1
+ import dayjs, { type Dayjs } from "dayjs";
2
+ import { createStyles } from "antd-style";
3
+ import localeData from "dayjs/plugin/localeData";
4
+ import { useState } from "react";
5
+
6
+ export interface CalendarProps
7
+ extends Omit<React.HTMLAttributes<HTMLTableElement>, "onChange"> {
8
+ /**
9
+ * 当前显示的月份。
10
+ *
11
+ * 注意:传入的月份的时区会决定整个日历所用的时区。
12
+ */
13
+ month: Dayjs;
14
+ /** 当前选中的日期。*/
15
+ selected?: Dayjs;
16
+ /** 选中日期更改时的回调函数。*/
17
+ onChange?: (selected: Dayjs) => void;
18
+ /**
19
+ * 无论一个月需要占用多少周,都总是显示 6 周。
20
+ * @default false
21
+ */
22
+ alwaysSixWeeks?: boolean;
23
+ /**
24
+ * 淡化第一周和最后几周不属于本月的日期。
25
+ * @default true
26
+ */
27
+ fadeAdjacentDays?: boolean;
28
+ /**
29
+ * 表头单元格的属性,详见 [MDN][1]。可以通过设置这里的 `children` 来自定义表头内容。
30
+ *
31
+ * [1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/th
32
+ */
33
+ thProps?: (
34
+ /**
35
+ * 范围 0-6,表示一周的第几天
36
+ *
37
+ * 注意:这个数字的含义会受到地区设置的影响!请使用 `dayjs.weekdays()` 获取每一天的名称。
38
+ */
39
+ weekday: number,
40
+ ) => React.HTMLAttributes<HTMLTableCellElement>;
41
+ /**
42
+ * 日期单元格的属性,详见 [MDN][1]。可以通过设置这里的 `children` 来自定义单元格内容。
43
+ *
44
+ * [1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td
45
+ */
46
+ tdProps?: (
47
+ date: Dayjs,
48
+ selected: boolean,
49
+ ) => React.HTMLAttributes<HTMLTableCellElement>;
50
+ }
51
+
52
+ dayjs.extend(localeData);
53
+
54
+ const useStyles = createStyles(({ token, css, cx }) => {
55
+ const calendarFade = css`
56
+ color: ${token.colorTextDisabled};
57
+ `;
58
+ const calendarSelected = css`
59
+ background: ${token.colorPrimaryBg};
60
+ color: ${token.colorPrimary};
61
+ `;
62
+ const calendar = css`
63
+ box-sizing: border-box;
64
+ width: 100%;
65
+ height: 100%;
66
+ border-collapse: collapse;
67
+ font-family: ${token.fontFamily};
68
+ font-size: ${token.fontSize}px;
69
+ line-height: ${token.lineHeight};
70
+ user-select: none;
71
+
72
+ > thead > tr > th {
73
+ box-sizing: border-box;
74
+ height: ${token.fontSize * token.lineHeight + token.paddingXXS * 2}px;
75
+ padding: ${token.paddingXXS}px;
76
+ font-weight: normal;
77
+ }
78
+
79
+ > tbody > tr > td {
80
+ box-sizing: border-box;
81
+ width: calc(100% / 7);
82
+ border: 1px solid ${token.colorBorder};
83
+ padding: ${token.paddingXXS}px;
84
+ vertical-align: bottom;
85
+ transition:
86
+ background ease ${token.motionDurationFast},
87
+ color ease ${token.motionDurationFast};
88
+
89
+ &:hover:not(.${cx(calendarSelected)}) {
90
+ background: ${token.colorBgTextHover};
91
+ }
92
+ }
93
+ `;
94
+ return {
95
+ calendar,
96
+ calendarFade,
97
+ calendarSelected,
98
+ };
99
+ });
100
+
101
+ /**
102
+ * 一个日历组件。
103
+ *
104
+ * 除了文档列出的属性之外,也接受所有 [HTML Table 元素][1] 接受的属性。
105
+ *
106
+ * [1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table
107
+ */
108
+ function Calendar(props: CalendarProps) {
109
+ const {
110
+ month,
111
+ selected: propsSelected,
112
+ onChange,
113
+ alwaysSixWeeks,
114
+ fadeAdjacentDays = true,
115
+ thProps,
116
+ tdProps,
117
+ className,
118
+ ...rest
119
+ } = props;
120
+ const { cx, styles } = useStyles();
121
+
122
+ const [selected, setSelected] =
123
+ propsSelected === undefined
124
+ ? // eslint-disable-next-line react-hooks/rules-of-hooks
125
+ useState<Dayjs | undefined>()
126
+ : [propsSelected, () => {}];
127
+
128
+ const monthStart = month.startOf("month");
129
+ const calendarStart = monthStart.startOf("week");
130
+ const monthEnd = month.endOf("month");
131
+ const minWeeks = Math.ceil(monthEnd.diff(calendarStart, "week", true));
132
+ const weekdays = [...dayjs.weekdaysShort()];
133
+ // 按地区设置调整一周的第一天
134
+ weekdays.splice(0, 0, ...weekdays.splice(calendarStart.day()));
135
+ return (
136
+ <table {...rest} className={cx(styles.calendar, className)}>
137
+ <thead>
138
+ <tr>
139
+ {weekdays.map((name, weekday) => (
140
+ <th key={weekday} children={name} {...thProps?.(weekday)} />
141
+ ))}
142
+ </tr>
143
+ </thead>
144
+ <tbody>
145
+ {Array.from({ length: alwaysSixWeeks ? 6 : minWeeks }, (_, week) => (
146
+ <tr key={week}>
147
+ {Array(7)
148
+ .fill(null)
149
+ .map((_, weekday) => {
150
+ const date = calendarStart.add(week * 7 + weekday, "day");
151
+ const fade =
152
+ fadeAdjacentDays && date.month() != monthStart.month();
153
+ const isSelected =
154
+ Math.floor(selected?.diff(date, "day", true) ?? NaN) === 0;
155
+ const { className, ...props } = tdProps?.(date, false) ?? {};
156
+ return (
157
+ <td
158
+ key={weekday}
159
+ children={date.date()}
160
+ onClick={() => {
161
+ setSelected(date);
162
+ onChange?.(date);
163
+ }}
164
+ {...props}
165
+ className={cx(
166
+ {
167
+ [styles.calendarFade]: fade,
168
+ [styles.calendarSelected]: isSelected,
169
+ },
170
+ className,
171
+ )}
172
+ />
173
+ );
174
+ })}
175
+ </tr>
176
+ ))}
177
+ </tbody>
178
+ </table>
179
+ );
180
+ }
181
+
182
+ export default Calendar;
@@ -0,0 +1,38 @@
1
+ import { Progress, type ProgressProps } from "antd";
2
+ import type { ProgressGradient } from "antd/es/progress/progress";
3
+
4
+ export interface CircularProgressProps
5
+ extends ProgressProps,
6
+ React.RefAttributes<HTMLDivElement> {
7
+ /** 进度百分比,范围是 0-100。*/
8
+ progress?: number;
9
+ /**
10
+ * 进度条已完成部分的颜色。
11
+ * @default "#34A9D4"
12
+ */
13
+ color?: string | string[] | ProgressGradient;
14
+ }
15
+
16
+ /**
17
+ * 环形进度条。
18
+ *
19
+ * 本组件基于 [Ant Design 的 `Progress`][1] 自定义而来。
20
+ * 因此,除了文档中列出的属性以外,也兼容 `Progress` 的所有属性。
21
+ *
22
+ * [1]: https://ant-design.antgroup.com/components/progress-cn
23
+ */
24
+ function CircularProgress(props: CircularProgressProps) {
25
+ return (
26
+ <Progress
27
+ type="circle"
28
+ percent={props.progress}
29
+ strokeLinecap="butt"
30
+ strokeWidth={9}
31
+ strokeColor={props.color ?? "#34A9D4"}
32
+ trailColor="#22405A"
33
+ {...props}
34
+ />
35
+ );
36
+ }
37
+
38
+ export default CircularProgress;
@@ -0,0 +1,136 @@
1
+ import type { CSSProperties, ReactNode } from "react";
2
+ import { Flex, Layout, Menu, type MenuProps, theme } from "antd";
3
+
4
+ import UserButton from "./UserButton";
5
+
6
+ export type MenuItem = Required<MenuProps>["items"][number];
7
+
8
+ export interface HeaderProps extends MenuProps {
9
+ /**
10
+ * 网站 logo 的 URL。
11
+ *
12
+ * 建议导入图片,然后填入导入得到的地址,而不要硬编码地址。
13
+ */
14
+ logo?: string;
15
+ /** 顶栏的标题。*/
16
+ title?: string;
17
+ /**
18
+ * 顶栏左端部分(logo 和标题)的宽度。在与边栏搭配时,推荐设置成与边栏同宽。
19
+ * @default 260
20
+ */
21
+ leftEndWidth?: number | string;
22
+ /**
23
+ * 顶栏左端的内容(logo 和标题)。设置了该属性时,
24
+ * {@linkcode HeaderProps.logo | logo}、
25
+ * {@linkcode HeaderProps.title | title} 和
26
+ * {@linkcode HeaderProps.leftEndWidth | leftEndWidth} 将失去作用。
27
+ * 填 `null` 可以隐藏掉默认值(与 `undefined` 不同!)。
28
+ */
29
+ leftEnd?: ReactNode;
30
+ /**
31
+ * 菜单项配置,默认为空。
32
+ *
33
+ * 该属性以及其余属性的用法可参考 [`Menu` 组件的文档][1]。
34
+ *
35
+ * [1]: https://ant-design.antgroup.com/components/menu-cn
36
+ */
37
+ items?: MenuItem[];
38
+ /** 当前选中的菜单项 key 数组。 */
39
+ selectedKeys?: string[];
40
+ /** 当前展开的子菜单 key 数组。 */
41
+ openKeys?: string[];
42
+ /** 菜单项被选中时的回调函数。 */
43
+ onSelect?: MenuProps["onSelect"];
44
+ /** 子菜单展开/收起时的回调函数。 */
45
+ onOpenChange?: MenuProps["onOpenChange"];
46
+ /**
47
+ * 顶栏右端的额外内容。默认使用 {@linkcode UserButton} 组件。
48
+ * 填 `null` 可以隐藏掉默认值(与 `undefined` 不同!)。
49
+ * @default <UserButton layout="header" />
50
+ */
51
+ rightEnd?: ReactNode;
52
+ /** 额外的 `className`。*/
53
+ className?: string;
54
+ /** 额外的 CSS 样式。*/
55
+ style?: CSSProperties;
56
+ }
57
+
58
+ /**
59
+ * 顶栏组件。该组件需要放置在 [Ant Design 的 `Layout` 组件][1]内部才能正常工作。
60
+ * 如果没有指定 {@linkcode HeaderProps.rightEnd | rightEnd} 属性,
61
+ * 那么还需要包裹在 {@linkcode AuthProvider} 内,并且经过 {@linkcode AuthCheck} 验证后
62
+ * 才能正常显示顶栏右端的用户信息按钮。
63
+ *
64
+ * 一般来说,使用该组件时至少需要提供 `logo`、`items` 和 `onSelect` 三个属性,具体用法请参照范例。
65
+ *
66
+ * 除了文档中列出的属性之外,该组件会把额外的属性全部传递给内部的菜单 [`Menu` 组件][2]。
67
+ *
68
+ * [1]: https://ant-design.antgroup.com/components/layout-cn
69
+ * [2]: https://ant-design.antgroup.com/components/menu-cn
70
+ */
71
+ function Header(props: HeaderProps) {
72
+ const { token } = theme.useToken();
73
+ const {
74
+ logo,
75
+ title,
76
+ leftEndWidth = 260,
77
+ leftEnd,
78
+ rightEnd,
79
+ className,
80
+ style,
81
+ ...rest
82
+ } = props;
83
+ return (
84
+ <Layout.Header
85
+ className={className}
86
+ style={{
87
+ display: "flex",
88
+ alignItems: "center",
89
+ boxShadow: "rgba(0, 0, 0, 0.15) 0 0 8px",
90
+ zIndex: 1,
91
+ background: token.colorBgContainer,
92
+ padding: 0,
93
+ color: token.colorText,
94
+ ...style,
95
+ }}
96
+ >
97
+ {leftEnd !== undefined ? (
98
+ leftEnd
99
+ ) : (
100
+ <Flex
101
+ align="center"
102
+ gap={token.marginSM}
103
+ style={{
104
+ minWidth: leftEndWidth,
105
+ height: "100%",
106
+ paddingInlineStart: token.paddingLG + token.paddingXXS,
107
+ paddingInlineEnd: token.paddingSM,
108
+ }}
109
+ >
110
+ <img alt="logo" src={logo} style={{ height: "50%" }} />
111
+ <h1
112
+ style={{
113
+ flexBasis: "100%",
114
+ textAlign: "center",
115
+ color: token.colorText,
116
+ }}
117
+ >
118
+ {title}
119
+ </h1>
120
+ </Flex>
121
+ )}
122
+ <Menu
123
+ mode="horizontal"
124
+ {...rest}
125
+ style={{
126
+ flexBasis: "100%",
127
+ height: "100%",
128
+ borderBlockEnd: "none",
129
+ }}
130
+ />
131
+ {rightEnd !== undefined ? rightEnd : <UserButton layout="header" />}
132
+ </Layout.Header>
133
+ );
134
+ }
135
+
136
+ export default Header;
@@ -0,0 +1,58 @@
1
+ export interface ImageBackgroundProps
2
+ extends React.HTMLAttributes<HTMLDivElement> {
3
+ /**
4
+ * 图片的 URL。
5
+ *
6
+ * 建议导入图片,然后填入导入得到的地址,而不要硬编码地址。
7
+ *
8
+ * ```jsx
9
+ * import img from "../public/image.png";
10
+ * <ImageBackground url={img}>...</ImageBackground>
11
+ * ```
12
+ */
13
+ url: string;
14
+ children: React.ReactNode;
15
+ /**
16
+ * 容器的宽度。
17
+ * @default "100%"
18
+ */
19
+ width?: React.CSSProperties["width"];
20
+ /**
21
+ * 容器的高度。
22
+ * @default "100%"
23
+ */
24
+ height?: React.CSSProperties["height"];
25
+ style?: React.CSSProperties;
26
+ }
27
+
28
+ /**
29
+ * 以图片作为背景的块级容器。除了文档列出的属性以外,也兼容所有 [HTML Div 元素][1] 的属性。
30
+ *
31
+ * [1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div
32
+ */
33
+ function ImageBackground(props: ImageBackgroundProps) {
34
+ const {
35
+ url,
36
+ children,
37
+ width = "100%",
38
+ height = "100%",
39
+ style,
40
+ ...rest
41
+ } = props;
42
+ return (
43
+ <div
44
+ {...rest}
45
+ style={{
46
+ backgroundSize: "100% 100%",
47
+ width: width,
48
+ height: height,
49
+ backgroundImage: `url('${url}')`,
50
+ ...style,
51
+ }}
52
+ >
53
+ {children}
54
+ </div>
55
+ );
56
+ }
57
+
58
+ export default ImageBackground;
@@ -0,0 +1,106 @@
1
+ import { createStyles, keyframes } from "antd-style";
2
+ import type { HTMLAttributes } from "react";
3
+
4
+ export interface IndicatorLightProps extends HTMLAttributes<HTMLDivElement> {
5
+ /**
6
+ * 指示灯的直径。
7
+ * @default token.sizeXL
8
+ */
9
+ size?: number | string;
10
+ /**
11
+ * 指示的状态。设置了这一项时,{@linkcode onColor}、{@linkcode mode} 和 {@linkcode period} 会被忽略。
12
+ *
13
+ * `"healthy"` 表示常绿,`"attention"` 表示绿色闪烁,
14
+ * `"danger"` 表示常红,`"emergency"` 表示红色闪烁,
15
+ * `"off"` 表示关闭。
16
+ * 具体色值取自 design token。
17
+ */
18
+ status?: "healthy" | "attention" | "danger" | "emergency" | "off";
19
+ /**
20
+ * 灯亮时的颜色。
21
+ * @default token.colorError
22
+ */
23
+ onColor?: string;
24
+ /**
25
+ * 灯灭时的颜色。
26
+ * @default token.colorFill
27
+ */
28
+ offColor?: string;
29
+ /**
30
+ * 灯的状态。`"on"` 表示常亮,`"flash"` 表示闪烁,`"off"` 表示常暗。
31
+ * @default "on"
32
+ */
33
+ mode?: "on" | "flash" | "off";
34
+ /**
35
+ * 闪烁周期(一亮一暗)的时长,以秒为单位。不可为 `0`、`NaN` 或 `Infinity`。
36
+ * @default 1
37
+ */
38
+ period?: number;
39
+ }
40
+
41
+ const ANIMATION_MAP: Record<IndicatorLightProps["mode"] & {}, string> = {
42
+ on: "linear(0, 0) paused",
43
+ flash: "cubic-bezier(0.9, 0, 0.1, 1) infinite alternate",
44
+ off: "linear(1, 1) paused",
45
+ };
46
+
47
+ const useStyles = createStyles(({ token, css }, props: IndicatorLightProps) => {
48
+ const size = props.size ?? token.sizeXL;
49
+ const sizeCss = typeof size === "number" ? size + "px" : size;
50
+ const colorMap: Record<
51
+ IndicatorLightProps["status"] & {},
52
+ { onColor: string; mode: "on" | "flash" | "off" }
53
+ > = {
54
+ healthy: { onColor: token.colorSuccess, mode: "on" },
55
+ attention: { onColor: token.colorSuccess, mode: "flash" },
56
+ danger: { onColor: token.colorError, mode: "on" },
57
+ emergency: { onColor: token.colorError, mode: "flash" },
58
+ off: { onColor: token.colorError, mode: "off" },
59
+ };
60
+ const { onColor = token.colorError, mode = "on" } = props.status
61
+ ? colorMap[props.status]
62
+ : props;
63
+ const offColor = props.offColor ?? token.colorFillSecondary;
64
+ const halfPeriod = (props.period ?? 1) / 2;
65
+ const flash = keyframes`
66
+ from {
67
+ background-color: ${onColor};
68
+ box-shadow: 0 0 6px 2px ${onColor};
69
+ }
70
+ to {
71
+ background-color: ${offColor};
72
+ }
73
+ `;
74
+ return {
75
+ light: css`
76
+ width: 100%;
77
+ height: 100%;
78
+ border-radius: 50%;
79
+ animation: ${flash} ${halfPeriod}s ${ANIMATION_MAP[mode]};
80
+ `,
81
+ lightBorder: css`
82
+ height: ${sizeCss};
83
+ aspect-ratio: 1;
84
+ border: ${token.colorBorder} 2px solid;
85
+ border-radius: 50%;
86
+ `,
87
+ };
88
+ });
89
+
90
+ /**
91
+ * 一个指示灯。
92
+ *
93
+ * 文档内未列出的属性会被传递给组件顶层的 `div` 元素。
94
+ */
95
+ function IndicatorLight(props: IndicatorLightProps) {
96
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
97
+ const { size, status, onColor, offColor, mode, period, ...rest } = props;
98
+ const { cx, styles } = useStyles(props);
99
+ return (
100
+ <div {...rest} className={cx(styles.lightBorder, rest.className)}>
101
+ <div className={cx(styles.light)}></div>
102
+ </div>
103
+ );
104
+ }
105
+
106
+ export default IndicatorLight;