@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,250 @@
1
+ import {
2
+ BarChartOutlined,
3
+ LeftOutlined,
4
+ RightOutlined,
5
+ SwapOutlined,
6
+ TeamOutlined,
7
+ } from "@ant-design/icons";
8
+ import { Button, Flex, Layout, Menu, type MenuProps } from "antd";
9
+ import { type CSSProperties, type Key, type ReactNode, useState } from "react";
10
+ import { createStyles } from "antd-style";
11
+
12
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
13
+ import { AuthCheck, AuthProvider } from "./Auth";
14
+ import UserButton from "./UserButton";
15
+
16
+ export type MenuItem = Required<MenuProps>["items"][number];
17
+
18
+ const menuItem = (
19
+ label: ReactNode,
20
+ key: Key,
21
+ icon?: ReactNode,
22
+ children?: MenuItem[],
23
+ ): MenuItem => ({ key, icon, children, label });
24
+
25
+ /** 默认菜单项配置,可以作为参考或默认值 */
26
+ const DEFAULT_MENU_ITEMS: MenuItem[] = [
27
+ menuItem("数据看板", "data-board", <BarChartOutlined />, [
28
+ menuItem("宏观数据", "macro-data"),
29
+ menuItem("合约看板", "contract-overview"),
30
+ menuItem("数据复盘", "data-review"),
31
+ ]),
32
+ menuItem("交易管理", "trade-management", <SwapOutlined />, [
33
+ menuItem("日前交易", "day-ahead-trade"),
34
+ menuItem("现货交易", "spot-trade"),
35
+ menuItem("中长期交易", "long-term-trade"),
36
+ ]),
37
+ menuItem("合约管理", "customer-management", <TeamOutlined />, [
38
+ menuItem("客户总览", "customer-overview"),
39
+ menuItem("售电合约管理", "sales-contract"),
40
+ menuItem("供应商管理", "supplier-management"),
41
+ menuItem("购电合约管理", "purchase-contract"),
42
+ ]),
43
+ ];
44
+
45
+ export interface SidebarProps extends MenuProps {
46
+ /**
47
+ * 侧边栏的宽度。
48
+ * @default 260
49
+ */
50
+ width?: number | string;
51
+ /**
52
+ * 是否启用伸缩功能。
53
+ * @default false
54
+ */
55
+ collapsible?: boolean;
56
+ /**
57
+ * 网站 logo 的 URL。
58
+ *
59
+ * 建议导入图片,然后填入导入得到的地址,而不要硬编码地址。
60
+ */
61
+ logo?: string;
62
+ /** 侧边栏的标题。*/
63
+ title?: string;
64
+ /**
65
+ * 侧边栏头部(logo 和标题部分)的高度。
66
+ * @default 116
67
+ */
68
+ headerHeight?: number | string;
69
+ /**
70
+ * 侧边栏的头部(logo 和标题部分)。设置了该属性时,
71
+ * {@linkcode SidebarProps.logo | logo}、
72
+ * {@linkcode SidebarProps.title | title} 和
73
+ * {@linkcode SidebarProps.headerHeight | headerHeight} 将失去作用。
74
+ * 参数 `collapsed` 表示侧边栏是否收起。
75
+ * 填 `null` 可以隐藏掉默认值(与 `undefined` 不同!)。
76
+ */
77
+ header?: ((collapsed: boolean) => ReactNode) | null;
78
+ /**
79
+ * 菜单项配置,默认与 TMS 系统的菜单相同。
80
+ *
81
+ * 该属性以及其余属性的用法可参考 [`Menu` 组件的文档][1]。
82
+ *
83
+ * [1]: https://ant-design.antgroup.com/components/menu-cn
84
+ */
85
+ items?: MenuItem[];
86
+ /** 当前选中的菜单项 key 数组。 */
87
+ selectedKeys?: string[];
88
+ /** 当前展开的子菜单 key 数组。 */
89
+ openKeys?: string[];
90
+ /** 菜单项被选中时的回调函数。 */
91
+ onSelect?: MenuProps["onSelect"];
92
+ /** 子菜单展开/收起时的回调函数。 */
93
+ onOpenChange?: MenuProps["onOpenChange"];
94
+ /**
95
+ * 侧边栏底部的额外内容。参数 `collapsed` 表示侧边栏是否收起。
96
+ * 默认情况下使用 {@linkcode UserButton} 组件。
97
+ * 填 `null` 可以隐藏掉默认值(与 `undefined` 不同!)。
98
+ * @default (collapsed) => <UserButton compact={collapsed} />
99
+ */
100
+ footer?: ((collapsed: boolean) => ReactNode) | null;
101
+ /** 额外的 `className`。*/
102
+ className?: string;
103
+ /** 额外的 CSS 样式。*/
104
+ style?: CSSProperties;
105
+ }
106
+
107
+ const useStyles = createStyles(
108
+ ({ token, css, cx, prefixCls }, collapsed: boolean) => {
109
+ const sidebarHeader = css`
110
+ margin-top: ${token.marginXXS}px;
111
+
112
+ > img {
113
+ width: 40%;
114
+ }
115
+
116
+ > h1 {
117
+ margin: ${collapsed ? 0 : token.marginXXS}px 0 0 0;
118
+ font-size: ${collapsed ? 0 : token.fontSize}px;
119
+ font-weight: normal;
120
+ line-height: 1;
121
+ transition:
122
+ margin-top ${token.motionDurationMid},
123
+ font-size ${token.motionDurationMid};
124
+ }
125
+ `;
126
+ const sidebarMenu = css`
127
+ flex-basis: 100%;
128
+ overflow-y: auto;
129
+ `;
130
+ const sidebarBtn = css`
131
+ position: absolute;
132
+ top: 75%;
133
+ right: 0;
134
+ transform: translate(50%, -50%);
135
+
136
+ font-size: ${token.sizeSM}px;
137
+
138
+ transition: opacity ${token.motionDurationMid};
139
+ opacity: 0%;
140
+ `;
141
+ const sidebar = css`
142
+ position: relative;
143
+ box-shadow: rgba(0, 0, 0, 0.15) 0 0 8px;
144
+
145
+ > .${prefixCls}-layout-sider-children {
146
+ display: flex;
147
+ flex-direction: column;
148
+ }
149
+
150
+ /* 为了提高权重 */
151
+ & .${cx(sidebarBtn)} {
152
+ width: ${token.controlHeightXS}px;
153
+ }
154
+ & .${cx(sidebarMenu)}.${cx(sidebarMenu)} {
155
+ border-inline-end: none;
156
+ }
157
+
158
+ &:hover .${cx(sidebarBtn)} {
159
+ opacity: 100%;
160
+ }
161
+ `;
162
+ return {
163
+ sidebar,
164
+ sidebarHeader,
165
+ sidebarMenu,
166
+ sidebarBtn,
167
+ };
168
+ },
169
+ );
170
+
171
+ /**
172
+ * 出自 TMS 系统的侧边栏组件。该组件需要放置在 [Ant Design 的 `Layout` 组件][1]内部才能正常工作。
173
+ * 如果没有指定 {@linkcode SidebarProps.footer | footer} 属性,
174
+ * 那么还需要包裹在 {@linkcode AuthProvider} 内,并且经过 {@linkcode AuthCheck} 验证后
175
+ * 才能正常显示边栏底部的用户信息按钮。
176
+ *
177
+ * 一般来说,使用该组件时至少需要提供 `logo`、`items` 和 `onSelect` 三个属性,具体用法请参照范例。
178
+ *
179
+ * 除了文档中列出的属性之外,该组件会把额外的属性全部传递给内部的菜单 [`Menu` 组件][2]。
180
+ *
181
+ * [1]: https://ant-design.antgroup.com/components/layout-cn
182
+ * [2]: https://ant-design.antgroup.com/components/menu-cn
183
+ */
184
+ function Sidebar(props: SidebarProps) {
185
+ const {
186
+ width = 260,
187
+ collapsible = false,
188
+ logo,
189
+ title,
190
+ headerHeight = 116,
191
+ header,
192
+ items = DEFAULT_MENU_ITEMS,
193
+ footer = (collapsed) => (
194
+ <UserButton
195
+ compact={collapsed}
196
+ style={{ marginBottom: token.paddingSM }}
197
+ />
198
+ ),
199
+ className,
200
+ style,
201
+ ...rest
202
+ } = props;
203
+
204
+ const [collapsed, setCollapsed] = useState(false);
205
+ const { cx, styles, theme: token } = useStyles(collapsed);
206
+
207
+ return (
208
+ <Layout.Sider
209
+ theme="light"
210
+ width={width}
211
+ collapsed={collapsible ? collapsed : false}
212
+ collapsible={collapsible}
213
+ trigger={null}
214
+ className={cx(styles.sidebar, className)}
215
+ style={style}
216
+ >
217
+ {header === null ? null : header ? (
218
+ header(collapsed)
219
+ ) : (
220
+ <Flex
221
+ vertical
222
+ align="center"
223
+ justify="center"
224
+ className={cx(styles.sidebarHeader)}
225
+ style={{ height: headerHeight }}
226
+ >
227
+ <img alt="logo" src={logo} />
228
+ <h1 style={{ color: token.colorText }}>{title}</h1>
229
+ </Flex>
230
+ )}
231
+ <Menu
232
+ mode="inline"
233
+ items={items}
234
+ inlineCollapsed={collapsible ? collapsed : false}
235
+ className={cx(styles.sidebarMenu)}
236
+ {...rest}
237
+ />
238
+ {footer === null ? null : footer?.(collapsed)}
239
+ {collapsible && (
240
+ <Button
241
+ className={cx(styles.sidebarBtn)}
242
+ icon={collapsed ? <RightOutlined /> : <LeftOutlined />}
243
+ onClick={() => setCollapsed(!collapsed)}
244
+ />
245
+ )}
246
+ </Layout.Sider>
247
+ );
248
+ }
249
+
250
+ export default Sidebar;
@@ -0,0 +1,103 @@
1
+ import {
2
+ type DatePickerProps as AntdDatePickerProps,
3
+ Button,
4
+ type ButtonProps,
5
+ DatePicker,
6
+ Space,
7
+ } from "antd";
8
+ import { LeftOutlined, RightOutlined } from "@ant-design/icons";
9
+ import type { Dayjs } from "dayjs";
10
+ import type { SpaceCompactProps } from "antd/es/space/Compact";
11
+ import { useState } from "react";
12
+
13
+ export interface DatePickerProps extends Omit<SpaceCompactProps, "onChange"> {
14
+ value?: Dayjs;
15
+ onChange?: (value: Dayjs) => void;
16
+ /**
17
+ * 日期的单位。
18
+ * @default "month"
19
+ */
20
+ dataType?: "day" | "week" | "month" | "year";
21
+ /**
22
+ * 是否禁用。
23
+ * @default false
24
+ */
25
+ disabled?: boolean;
26
+ /**
27
+ * 左右按钮的 `props`,见 [Ant Design 的 `Button` API][1]。
28
+ *
29
+ * [1]: https://ant-design.antgroup.com/components/button-cn#api
30
+ */
31
+ buttonProps?: ButtonProps;
32
+ /**
33
+ * 日期选择器的 `props`,见 [Ant Design 的 `DatePicker` API][1]。
34
+ *
35
+ * [1]: https://ant-design.antgroup.com/components/date-picker-cn#api
36
+ */
37
+ pickerProps?: AntdDatePickerProps;
38
+ }
39
+
40
+ /**
41
+ * 支持快速跳转的日/周/月/年选择器。
42
+ *
43
+ * 除了文档中列出的属性外,该组件会将其它属性传递给 [Ant Design 的 `Space.Compact` 组件][1]。
44
+ *
45
+ * [1]: https://ant-design.antgroup.com/components/space-cn#spacecompact
46
+ */
47
+ function TsingrocDatePicker(props: DatePickerProps) {
48
+ const {
49
+ value,
50
+ onChange: propsOnChange,
51
+ dataType = "month",
52
+ disabled,
53
+ buttonProps,
54
+ pickerProps,
55
+ ...rest
56
+ } = props;
57
+ const [dateValue, setDateValue] =
58
+ value === undefined
59
+ ? // eslint-disable-next-line react-hooks/rules-of-hooks
60
+ useState<Dayjs | undefined>(undefined)
61
+ : [value, () => {}];
62
+ /**
63
+ * 快速增减一定时间,如果当前未选择日期则无效。
64
+ * @param delta 增减的时间量,按传入的时间单位 `dataType` 计算
65
+ */
66
+ const quickSwitch = (delta: number) => {
67
+ if (!dateValue) return;
68
+ const temp = dateValue.add(delta, dataType);
69
+ setDateValue(temp);
70
+ propsOnChange?.(temp);
71
+ };
72
+ const onChange = (value: Dayjs) => {
73
+ setDateValue(value);
74
+ propsOnChange?.(value);
75
+ };
76
+ return (
77
+ <Space.Compact {...rest}>
78
+ <Button
79
+ onClick={() => quickSwitch(-1)}
80
+ icon={<LeftOutlined />}
81
+ disabled={disabled}
82
+ className={props.className}
83
+ {...buttonProps}
84
+ />
85
+ <DatePicker
86
+ picker={dataType == "day" ? "date" : dataType}
87
+ value={dateValue}
88
+ onChange={onChange}
89
+ disabled={disabled}
90
+ className={props.className}
91
+ {...pickerProps}
92
+ />
93
+ <Button
94
+ onClick={() => quickSwitch(+1)}
95
+ icon={<RightOutlined />}
96
+ disabled={disabled}
97
+ {...buttonProps}
98
+ />
99
+ </Space.Compact>
100
+ );
101
+ }
102
+
103
+ export default TsingrocDatePicker;
@@ -0,0 +1,47 @@
1
+ import { ConfigProvider, theme } from "antd";
2
+ import dayjs from "dayjs";
3
+ import type { ReactNode } from "react";
4
+ import zhCN from "antd/es/locale/zh_CN";
5
+ import "dayjs/locale/zh-cn";
6
+
7
+ export interface TsingrocThemeProps {
8
+ /** 是否开启黑暗模式。*/
9
+ dark?: boolean;
10
+ /** 主题覆盖的页面内容。*/
11
+ children: ReactNode;
12
+ }
13
+
14
+ /**
15
+ * 清鹏智能的公共 Ant Design 主题,会影响内部的所有 Ant Design 组件的样式。
16
+ * 请将该组件放置在整个 React 项目的顶层。
17
+ */
18
+ function TsingrocTheme(props: TsingrocThemeProps) {
19
+ // Ant Design 主题编辑器链接:
20
+ // https://ant-design.antgroup.com/theme-editor-cn
21
+ // 色板设计工具链接:
22
+ // https://huetone.ardov.me/?palette=N4IgdghgtgpiBcICiAPaAHANjABABQmwBcjcBjAe3QE8QAaEACwFcYBnBAbVElgRDwBLMAGt6ISpgoAnDvE4gAxADMADDAAmygCzjFmjTGUBOPRuMAjAIww4DRWTIAOMjF32yAJgBs3jU70Lb20AVjJvPWMYTwsIdyUnAGZVVScIQNCYCwD7CDJki0S9J21ExKdTe29EmN89bW1PVW0I%2B0SQq2NE1qVPbStGkJAAXQBfOh5oOEQAQTAiABFxSRk5BX1vHWVlQIgYVW3IqzIIQ6rLKzOlbVVjTZ37K28AdmerxVuQp3M9J9f3xLOKI5JR-N4PUEhELaCAaX7QqzPOyQmohCy-KyeaFDR5WKwQTxkEajYYMIgUMDsLggAAyqnENKsDM8DKKDBp8RpONpPUA3HKADIzAE5B4gWPQW3IW8QWbJACxZDAWTIV9LGQA
23
+ dayjs.locale("zh-cn");
24
+ return (
25
+ <ConfigProvider
26
+ locale={zhCN}
27
+ theme={{
28
+ algorithm: props.dark ? theme.darkAlgorithm : theme.defaultAlgorithm,
29
+ token: props.dark
30
+ ? {
31
+ colorPrimary: "#9b5efd",
32
+ colorInfo: "#9b5efd",
33
+ colorSuccess: "#1ac489",
34
+ }
35
+ : {
36
+ colorPrimary: "#5200d7",
37
+ colorInfo: "#5200d7",
38
+ colorSuccess: "#1ac489",
39
+ },
40
+ }}
41
+ >
42
+ {props.children}
43
+ </ConfigProvider>
44
+ );
45
+ }
46
+
47
+ export default TsingrocTheme;
@@ -0,0 +1,152 @@
1
+ import {
2
+ Avatar,
3
+ Button,
4
+ type ButtonProps,
5
+ Dropdown,
6
+ type DropdownProps,
7
+ theme,
8
+ } from "antd";
9
+ import {
10
+ DownOutlined,
11
+ LogoutOutlined,
12
+ UpOutlined,
13
+ UserOutlined,
14
+ } from "@ant-design/icons";
15
+ import type { Account } from "casdoor-js-sdk/lib/esm/sdk";
16
+
17
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
18
+ import { AuthCheck, AuthProvider, useAuth } from "./Auth";
19
+
20
+ export interface UserButtonProps extends ButtonProps {
21
+ /**
22
+ * 是否显示为缩小形态(只显示头像)。
23
+ * @default false
24
+ */
25
+ compact?: boolean;
26
+ /**
27
+ * 使用边栏布局还是顶栏布局。
28
+ * @default "sidebar"
29
+ */
30
+ layout?: "sidebar" | "header";
31
+ /** 点击“账户”时的操作。若省略,默认通过 Casdoor SDK 获取用户主页链接并跳转。*/
32
+ onOpenProfile?: () => void;
33
+ /**
34
+ * 点击“登出”时的操作。默认先登出,然后跳转到主页。
35
+ *
36
+ * @default
37
+ * () => {
38
+ * auth.logout(); // auth = useAuth()
39
+ * location.href = "/";
40
+ * }
41
+ */
42
+ onLogout?: () => void;
43
+ /**
44
+ * 下拉菜单的属性,见 [Ant Design 文档][1]。你可以在这里覆盖弹出菜单的内容和样式。
45
+ *
46
+ * [1]: https://ant-design.antgroup.com/components/dropdown-cn
47
+ */
48
+ dropdownProps?: DropdownProps;
49
+ }
50
+
51
+ /**
52
+ * 显示用户信息的按钮,点击弹出登出或跳转到账户页的菜单。
53
+ * 该组件必须包裹在 {@linkcode AuthProvider} 内,并且经过 {@linkcode AuthCheck} 验证后,
54
+ * 才能正常显示用户信息,否则只会显示占位数据。
55
+ *
56
+ * 除了文档中列出的属性以外,该组件会把额外的属性传递给内部的 [`Button`][1] 组件。
57
+ *
58
+ * [1]: https://ant-design.antgroup.com/components/button-cn
59
+ */
60
+ function UserButton(props: UserButtonProps) {
61
+ const { token } = theme.useToken();
62
+ const auth = useAuth("UserButton");
63
+ const userInfo = auth.userInfo;
64
+ const {
65
+ compact,
66
+ layout = "sidebar",
67
+ onOpenProfile = () => {
68
+ const account =
69
+ auth.accessToken === undefined
70
+ ? undefined
71
+ : { accessToken: auth.accessToken };
72
+ location.href = auth.sdk.getMyProfileUrl(
73
+ account as Account,
74
+ location.href,
75
+ );
76
+ },
77
+ onLogout = () => {
78
+ auth.logout();
79
+ location.href = "/";
80
+ },
81
+ dropdownProps,
82
+ ...rest
83
+ } = props;
84
+ return (
85
+ <Dropdown
86
+ trigger={["click"]}
87
+ placement={layout === "sidebar" ? "topLeft" : "bottomRight"}
88
+ {...dropdownProps}
89
+ menu={{
90
+ items: [
91
+ {
92
+ key: "profile",
93
+ label: <>账户</>, // 如果使用字符串,在缩小时会被裁剪,即使宽度足够
94
+ icon: <UserOutlined />,
95
+ title: "", // 若不设置,在缩小时总是会显示工具提示,即使宽度足够
96
+ onClick: onOpenProfile,
97
+ },
98
+ {
99
+ key: "logout",
100
+ icon: <LogoutOutlined />,
101
+ label: <>登出</>,
102
+ title: "",
103
+ onClick: onLogout,
104
+ },
105
+ ],
106
+ ...dropdownProps?.menu,
107
+ style: {
108
+ minWidth: "100%",
109
+ ...dropdownProps?.menu?.style,
110
+ },
111
+ }}
112
+ >
113
+ <Button
114
+ type="text"
115
+ icon={
116
+ <Avatar alt="头像" src={userInfo?.picture} icon={<UserOutlined />} />
117
+ }
118
+ {...rest}
119
+ styles={{
120
+ icon: {
121
+ display: "inline-flex",
122
+ alignItems: "center",
123
+ ...rest.styles?.icon,
124
+ },
125
+ }}
126
+ style={{
127
+ margin: token.marginXXS,
128
+ ...(layout === "sidebar"
129
+ ? {
130
+ width: "auto",
131
+ padding: token.paddingXXS,
132
+ }
133
+ : {
134
+ paddingBlock: token.padding + token.paddingXS,
135
+ }),
136
+ ...rest.style,
137
+ }}
138
+ >
139
+ {!compact && (
140
+ <>
141
+ <span style={{ marginRight: token.marginXXS }}>
142
+ {userInfo?.name ?? userInfo?.prefered_username ?? "平台用户"}
143
+ </span>
144
+ {layout === "sidebar" ? <UpOutlined /> : <DownOutlined />}
145
+ </>
146
+ )}
147
+ </Button>
148
+ </Dropdown>
149
+ );
150
+ }
151
+
152
+ export default UserButton;
@@ -0,0 +1,73 @@
1
+ import type { HTMLAttributes } from "react";
2
+ import { theme } from "antd";
3
+
4
+ export interface VerticalColorLegendProps
5
+ extends HTMLAttributes<HTMLDivElement> {
6
+ title?: string;
7
+ palette: [number, [number, number, number]][];
8
+ }
9
+
10
+ function VerticalColorLegend(props: VerticalColorLegendProps) {
11
+ const { title, palette, ...rest } = props;
12
+ const { token } = theme.useToken();
13
+ const max = palette.at(-1)![0];
14
+ const min = palette[0][0];
15
+ const range = max - min;
16
+ return (
17
+ <div
18
+ {...rest}
19
+ style={{
20
+ display: "flex",
21
+ flexDirection: "column",
22
+ userSelect: "none",
23
+ fontSize: token.fontSizeSM,
24
+ color: token.colorText,
25
+ textShadow:
26
+ "-1px -1px white, 0px -1px white, 1px -1px white, 1px 0px white, " +
27
+ "1px 1px white, 0px 1px white, -1px 1px white, -1px 0px white",
28
+ ...rest.style,
29
+ }}
30
+ >
31
+ <div style={{ fontWeight: "bold" }}>{title}</div>
32
+ <div
33
+ style={{
34
+ display: "flex",
35
+ flexBasis: "100%",
36
+ alignItems: "stretch",
37
+ gap: token.paddingXXS,
38
+ paddingBlock: "0.5em",
39
+ }}
40
+ >
41
+ <div
42
+ style={{
43
+ width: 24,
44
+ background: `linear-gradient(
45
+ to top,
46
+ ${palette
47
+ .map(
48
+ ([value, color]) =>
49
+ `rgb(${color.join(", ")}) ${((value - min) / range) * 100}%`,
50
+ )
51
+ .join(", ")}
52
+ )`,
53
+ }}
54
+ />
55
+ <div style={{ lineHeight: 0, verticalAlign: "middle" }}>
56
+ {palette.map(([value], i) => (
57
+ <div
58
+ key={i}
59
+ style={{
60
+ position: "relative",
61
+ top: ((max - value) / range) * 100 + "%",
62
+ }}
63
+ >
64
+ {value.toFixed(1)}
65
+ </div>
66
+ ))}
67
+ </div>
68
+ </div>
69
+ </div>
70
+ );
71
+ }
72
+
73
+ export default VerticalColorLegend;