@hsu-react/ui 2.3.0 → 2.4.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 (34) hide show
  1. package/es/build/webpack.d.ts +40 -0
  2. package/es/build/webpack.js +43 -0
  3. package/es/components/Chart/Bar/index.js +12 -5
  4. package/es/components/Chart/Heatmap/index.js +12 -4
  5. package/es/components/Chart/Line/index.js +12 -4
  6. package/es/components/Chart/_utils/cartesian.d.ts +3 -2
  7. package/es/components/Chart/_utils/cartesian.js +9 -10
  8. package/es/components/Chart/_utils/chartTheme.d.ts +22 -0
  9. package/es/components/Chart/_utils/chartTheme.js +23 -0
  10. package/es/components/Chart/_utils/heatmap.d.ts +3 -2
  11. package/es/components/Chart/_utils/heatmap.js +7 -10
  12. package/es/components/Panel/ListPanel/ListModalPanel/index.module.scss +10 -0
  13. package/lib/build/webpack.d.ts +40 -0
  14. package/lib/build/webpack.js +48 -0
  15. package/lib/components/Chart/Bar/index.js +10 -5
  16. package/lib/components/Chart/Heatmap/index.js +10 -4
  17. package/lib/components/Chart/Line/index.js +10 -4
  18. package/lib/components/Chart/_utils/cartesian.d.ts +3 -2
  19. package/lib/components/Chart/_utils/cartesian.js +9 -11
  20. package/lib/components/Chart/_utils/chartTheme.d.ts +22 -0
  21. package/lib/components/Chart/_utils/chartTheme.js +29 -0
  22. package/lib/components/Chart/_utils/heatmap.d.ts +3 -2
  23. package/lib/components/Chart/_utils/heatmap.js +7 -10
  24. package/lib/components/Panel/ListPanel/ListModalPanel/index.module.scss +10 -0
  25. package/lib/package.json +3 -0
  26. package/package.json +3 -3
  27. package/src/build/webpack.ts +44 -0
  28. package/src/components/Chart/Bar/index.tsx +10 -4
  29. package/src/components/Chart/Heatmap/index.tsx +10 -3
  30. package/src/components/Chart/Line/index.tsx +10 -3
  31. package/src/components/Chart/_utils/cartesian.ts +11 -10
  32. package/src/components/Chart/_utils/chartTheme.ts +34 -0
  33. package/src/components/Chart/_utils/heatmap.ts +10 -10
  34. package/src/components/Panel/ListPanel/ListModalPanel/index.module.scss +10 -0
@@ -0,0 +1,40 @@
1
+ /**
2
+ * 给消费方 webpack 配置用的工具。**构建期模块,不要从应用代码里引**
3
+ * —— 它不依赖 React,也不该进运行时产物。
4
+ *
5
+ * ```js
6
+ * // webpack.config.js(CJS)
7
+ * const { excludeNodeModulesExceptHsuUi } = require("@hsu-react/ui/lib/build/webpack");
8
+ *
9
+ * { test: /\.scss$/, exclude: excludeNodeModulesExceptHsuUi, use: [...] }
10
+ * ```
11
+ */
12
+ /**
13
+ * 判断一个模块路径「是否该被 loader 排除」:node_modules 一律排除,但放行本库。
14
+ *
15
+ * ## 为什么需要它
16
+ *
17
+ * 本库的 es / lib 产物里带着**未编译的 `.module.scss`** 和图片资源,要由消费方自己的
18
+ * loader 处理(这样 CSS Module 的类名哈希、`getLocalIdent` 等策略才由消费方说了算)。
19
+ * 于是每个 webpack 项目都得在 scss / 图片规则上开一个「排除 node_modules,但放行
20
+ * @hsu-react/ui」的例外。
21
+ *
22
+ * ## 为什么不能用正则
23
+ *
24
+ * 手写的版本几乎都是 `/node_modules\/(?!@hsu-react\/ui\/)/`。它只看**第一个**
25
+ * node_modules 后面跟着什么——扁平安装(yarn / npm)下确实是 `@hsu-react/ui/`,
26
+ * 但 pnpm 的真实路径是
27
+ *
28
+ * ```
29
+ * node_modules/.pnpm/@hsu-react+ui@<版本>/node_modules/@hsu-react/ui/es/...
30
+ * ```
31
+ *
32
+ * 跟着的是 `.pnpm/`,否定前瞻立刻失败,本库的 scss 与图片会被**全部排除**,
33
+ * 报「no loaders are configured to process this file」。这个坑在四个下游项目里
34
+ * 各踩过一次,所以把判定收进库里导出,消费方引用而不是各抄一份。
35
+ *
36
+ * 改按「整条路径里有没有 @hsu-react/ui」判断,扁平与嵌套两种布局都成立;
37
+ * 路径分隔符同时接受 `/` 与 `\`,Windows 下同样有效。
38
+ */
39
+ export declare const excludeNodeModulesExceptHsuUi: (modulePath: string) => boolean;
40
+ export default excludeNodeModulesExceptHsuUi;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * 给消费方 webpack 配置用的工具。**构建期模块,不要从应用代码里引**
3
+ * —— 它不依赖 React,也不该进运行时产物。
4
+ *
5
+ * ```js
6
+ * // webpack.config.js(CJS)
7
+ * const { excludeNodeModulesExceptHsuUi } = require("@hsu-react/ui/lib/build/webpack");
8
+ *
9
+ * { test: /\.scss$/, exclude: excludeNodeModulesExceptHsuUi, use: [...] }
10
+ * ```
11
+ */
12
+
13
+ /**
14
+ * 判断一个模块路径「是否该被 loader 排除」:node_modules 一律排除,但放行本库。
15
+ *
16
+ * ## 为什么需要它
17
+ *
18
+ * 本库的 es / lib 产物里带着**未编译的 `.module.scss`** 和图片资源,要由消费方自己的
19
+ * loader 处理(这样 CSS Module 的类名哈希、`getLocalIdent` 等策略才由消费方说了算)。
20
+ * 于是每个 webpack 项目都得在 scss / 图片规则上开一个「排除 node_modules,但放行
21
+ * @hsu-react/ui」的例外。
22
+ *
23
+ * ## 为什么不能用正则
24
+ *
25
+ * 手写的版本几乎都是 `/node_modules\/(?!@hsu-react\/ui\/)/`。它只看**第一个**
26
+ * node_modules 后面跟着什么——扁平安装(yarn / npm)下确实是 `@hsu-react/ui/`,
27
+ * 但 pnpm 的真实路径是
28
+ *
29
+ * ```
30
+ * node_modules/.pnpm/@hsu-react+ui@<版本>/node_modules/@hsu-react/ui/es/...
31
+ * ```
32
+ *
33
+ * 跟着的是 `.pnpm/`,否定前瞻立刻失败,本库的 scss 与图片会被**全部排除**,
34
+ * 报「no loaders are configured to process this file」。这个坑在四个下游项目里
35
+ * 各踩过一次,所以把判定收进库里导出,消费方引用而不是各抄一份。
36
+ *
37
+ * 改按「整条路径里有没有 @hsu-react/ui」判断,扁平与嵌套两种布局都成立;
38
+ * 路径分隔符同时接受 `/` 与 `\`,Windows 下同样有效。
39
+ */
40
+ export var excludeNodeModulesExceptHsuUi = function excludeNodeModulesExceptHsuUi(modulePath) {
41
+ return /node_modules/.test(modulePath) && !/@hsu-react[\\/]ui[\\/]/.test(modulePath);
42
+ };
43
+ export default excludeNodeModulesExceptHsuUi;
@@ -13,6 +13,8 @@ import styles from "../index.module.scss";
13
13
  import { autoScrollLegend } from "../_utils/autoScrollLegend";
14
14
  import { autoScrollByItem } from "../_utils/autoSmooth";
15
15
  import { buildCartesianSeriesOptions, createDefaultCategoryXAxis, createDefaultValueYAxis, getSliderShow, percentWindowToIndexWindow, resolveScrollConfig } from "../_utils/cartesian";
16
+ import { resolveChartChrome } from "../_utils/chartTheme";
17
+ import useIsDark from "../../../hooks/useIsDark";
16
18
  import { jsx as _jsx } from "react/jsx-runtime";
17
19
  var ChartBar = function ChartBar(props) {
18
20
  var className = props.className,
@@ -50,12 +52,18 @@ var ChartBar = function ChartBar(props) {
50
52
  var normalizedScroll = useMemo(function () {
51
53
  return resolveScrollConfig(scrollConfig);
52
54
  }, [scrollConfig]);
55
+ // echarts options are plain JS and cannot read the `--vita-*` variables, so the axis and
56
+ // legend colours have to be resolved against the active appearance here
57
+ var isDark = useIsDark();
58
+ var chrome = useMemo(function () {
59
+ return resolveChartChrome(isDark);
60
+ }, [isDark]);
53
61
 
54
62
  // Cache the chart option with useMemo
55
63
  var chartOption = useMemo(function () {
56
64
  var _xAxisData$length, _ref, _ref2;
57
- var def_xAxis = createDefaultCategoryXAxis(xAxisData);
58
- var def_yAxis = createDefaultValueYAxis("bar");
65
+ var def_xAxis = createDefaultCategoryXAxis(xAxisData, chrome);
66
+ var def_yAxis = createDefaultValueYAxis("bar", chrome);
59
67
 
60
68
  // Process xAxis config
61
69
  var processedXAxis = Array.isArray(xAxis) ? xAxis === null || xAxis === void 0 ? void 0 : xAxis.map(function (item) {
@@ -150,8 +158,7 @@ var ChartBar = function ChartBar(props) {
150
158
  data: legendData,
151
159
  icon: "circle",
152
160
  textStyle: {
153
- color: "#373D48",
154
- fontSize: 16
161
+ color: chrome.text
155
162
  },
156
163
  itemWidth: 8,
157
164
  itemHeight: 8
@@ -175,7 +182,7 @@ var ChartBar = function ChartBar(props) {
175
182
  series: buildCartesianSeriesOptions("bar", seriesData, series)
176
183
  }, coreOption);
177
184
  return option;
178
- }, [xAxisData, xAxis, yAxis, grid, chartTitle, dataZoom, normalizedScroll, insideDataZoom, sliderDataZoom, title, tooltip, legendData, legend, seriesData, series, enableLegendAutoScroll, coreOption]);
185
+ }, [xAxisData, xAxis, yAxis, grid, chartTitle, dataZoom, normalizedScroll, insideDataZoom, sliderDataZoom, title, tooltip, legendData, legend, seriesData, series, enableLegendAutoScroll, coreOption, chrome]);
179
186
 
180
187
  // Callback for handling chart resize
181
188
  var handleResize = useCallback(function () {
@@ -17,6 +17,8 @@ import React, { useCallback, useEffect, useMemo, useRef } from "react";
17
17
  import styles from "../index.module.scss";
18
18
  import * as echarts from "echarts";
19
19
  import { createDefaultHeatmapXAxis, createDefaultHeatmapYAxis } from "../_utils/heatmap";
20
+ import { resolveChartChrome } from "../_utils/chartTheme";
21
+ import useIsDark from "../../../hooks/useIsDark";
20
22
  import { jsx as _jsx } from "react/jsx-runtime";
21
23
  var Heatmap = function Heatmap(props) {
22
24
  var className = props.className,
@@ -41,6 +43,12 @@ var Heatmap = function Heatmap(props) {
41
43
  var chartRef = useRef(null);
42
44
  var chartInstanceRef = useRef(null);
43
45
  var resizeObserverRef = useRef(null);
46
+ // echarts options are plain JS and cannot read the `--vita-*` variables, so the axis and legend
47
+ // colours have to be resolved against the active appearance here
48
+ var isDark = useIsDark();
49
+ var chrome = useMemo(function () {
50
+ return resolveChartChrome(isDark);
51
+ }, [isDark]);
44
52
 
45
53
  // Process the data and generate the chart option
46
54
  var chartOption = useMemo(function () {
@@ -85,7 +93,7 @@ var Heatmap = function Heatmap(props) {
85
93
  left: "right",
86
94
  top: "center",
87
95
  textStyle: {
88
- color: "#373D48"
96
+ color: chrome.text
89
97
  },
90
98
  inRange: {
91
99
  color: inRangeColor
@@ -93,7 +101,7 @@ var Heatmap = function Heatmap(props) {
93
101
  };
94
102
 
95
103
  // Process xAxis config
96
- var def_xAxis = createDefaultHeatmapXAxis(xAxisData);
104
+ var def_xAxis = createDefaultHeatmapXAxis(xAxisData, chrome);
97
105
  var processedXAxis = Array.isArray(xAxis) ? xAxis === null || xAxis === void 0 ? void 0 : xAxis.map(function (item) {
98
106
  return _objectSpread(_objectSpread({}, def_xAxis), {}, {
99
107
  data: (item === null || item === void 0 ? void 0 : item.type) === "value" ? undefined : xAxisData
@@ -103,7 +111,7 @@ var Heatmap = function Heatmap(props) {
103
111
  }, xAxis);
104
112
 
105
113
  // Process yAxis config
106
- var def_yAxis = createDefaultHeatmapYAxis(yAxisData);
114
+ var def_yAxis = createDefaultHeatmapYAxis(yAxisData, chrome);
107
115
  var processedYAxis = Array.isArray(yAxis) ? yAxis === null || yAxis === void 0 ? void 0 : yAxis.map(function (item) {
108
116
  return _objectSpread(_objectSpread({}, def_yAxis), {}, {
109
117
  data: (item === null || item === void 0 ? void 0 : item.type) === "value" ? undefined : yAxisData
@@ -170,7 +178,7 @@ var Heatmap = function Heatmap(props) {
170
178
  }, series)]
171
179
  }, coreOption);
172
180
  return option;
173
- }, [data, inRangeColor, xAxisData, xAxis, yAxisData, yAxis, propVisualMap, grid, chartTitle, title, tooltip, series, coreOption, zeroColor]);
181
+ }, [data, inRangeColor, xAxisData, xAxis, yAxisData, yAxis, propVisualMap, grid, chartTitle, title, tooltip, series, coreOption, zeroColor, chrome]);
174
182
 
175
183
  // Callback for handling chart resize
176
184
  var handleResize = useCallback(function () {
@@ -13,6 +13,8 @@ import styles from "../index.module.scss";
13
13
  import { autoScrollLegend } from "../_utils/autoScrollLegend";
14
14
  import { autoScrollByItem } from "../_utils/autoSmooth";
15
15
  import { buildCartesianSeriesOptions, createDefaultCategoryXAxis, createDefaultValueYAxis, getSliderShow, percentWindowToIndexWindow, resolveScrollConfig } from "../_utils/cartesian";
16
+ import { resolveChartChrome } from "../_utils/chartTheme";
17
+ import useIsDark from "../../../hooks/useIsDark";
16
18
  import { jsx as _jsx } from "react/jsx-runtime";
17
19
  var ChartLine = function ChartLine(props) {
18
20
  var className = props.className,
@@ -50,12 +52,18 @@ var ChartLine = function ChartLine(props) {
50
52
  var normalizedScroll = useMemo(function () {
51
53
  return resolveScrollConfig(scrollConfig);
52
54
  }, [scrollConfig]);
55
+ // echarts options are plain JS and cannot read the `--vita-*` variables, so the axis and
56
+ // legend colours have to be resolved against the active appearance here
57
+ var isDark = useIsDark();
58
+ var chrome = useMemo(function () {
59
+ return resolveChartChrome(isDark);
60
+ }, [isDark]);
53
61
 
54
62
  // Cache the chart option with useMemo
55
63
  var chartOption = useMemo(function () {
56
64
  var _xAxisData$length, _ref, _ref2;
57
- var def_xAxis = createDefaultCategoryXAxis(xAxisData);
58
- var def_yAxis = createDefaultValueYAxis("line");
65
+ var def_xAxis = createDefaultCategoryXAxis(xAxisData, chrome);
66
+ var def_yAxis = createDefaultValueYAxis("line", chrome);
59
67
 
60
68
  // Process xAxis config
61
69
  var processedXAxis = Array.isArray(xAxis) ? xAxis === null || xAxis === void 0 ? void 0 : xAxis.map(function (item) {
@@ -144,7 +152,7 @@ var ChartLine = function ChartLine(props) {
144
152
  top: "5%",
145
153
  icon: "circle",
146
154
  textStyle: {
147
- color: "#373D48"
155
+ color: chrome.text
148
156
  },
149
157
  itemWidth: 8,
150
158
  itemHeight: 8
@@ -171,7 +179,7 @@ var ChartLine = function ChartLine(props) {
171
179
  series: buildCartesianSeriesOptions("line", seriesData, series)
172
180
  }, coreOption);
173
181
  return option;
174
- }, [xAxisData, xAxis, yAxis, grid, chartTitle, dataZoom, normalizedScroll, insideDataZoom, sliderDataZoom, title, legendData, legend, tooltip, seriesData, series, enableLegendAutoScroll, coreOption]);
182
+ }, [xAxisData, xAxis, yAxis, grid, chartTitle, dataZoom, normalizedScroll, insideDataZoom, sliderDataZoom, title, legendData, legend, tooltip, seriesData, series, enableLegendAutoScroll, coreOption, chrome]);
175
183
 
176
184
  // Callback for handling chart resize
177
185
  var handleResize = useCallback(function () {
@@ -1,5 +1,6 @@
1
1
  import * as echarts from "echarts";
2
2
  import { ChartOptionType, SeriesDataType } from "..";
3
+ import { ChartChrome } from "./chartTheme";
3
4
  export interface ChartScrollConfig {
4
5
  enabled?: boolean;
5
6
  autoScroll?: boolean;
@@ -29,8 +30,8 @@ export interface DataZoomIndexWindow {
29
30
  * percentages produced by native echarts interactions are rounded outward, so each boundary may include at most one extra item, without affecting the axis magnitude.
30
31
  */
31
32
  export declare const percentWindowToIndexWindow: (startPercent: number, endPercent: number, total: number) => DataZoomIndexWindow;
32
- export declare const createDefaultCategoryXAxis: (xAxisData?: Array<string>) => ChartOptionType;
33
- export declare const createDefaultValueYAxis: (mode?: "bar" | "line") => ChartOptionType;
33
+ export declare const createDefaultCategoryXAxis: (xAxisData: Array<string> | undefined, chrome: ChartChrome) => ChartOptionType;
34
+ export declare const createDefaultValueYAxis: (mode: "bar" | "line" | undefined, chrome: ChartChrome) => ChartOptionType;
34
35
  export declare const buildCartesianSeriesOptions: (mode: "bar" | "line", seriesData?: SeriesDataType, series?: echarts.SeriesOption | echarts.SeriesOption[]) => echarts.SeriesOption[];
35
36
  export declare const getSliderShow: (zoom?: echarts.DataZoomComponentOption | Record<string, unknown>) => boolean | undefined;
36
37
  export declare const resolveScrollConfig: (scrollConfig?: ChartScrollConfig) => NormalizedScrollConfig;
@@ -23,7 +23,7 @@ export var percentWindowToIndexWindow = function percentWindowToIndexWindow(star
23
23
  endIndex: endIndex
24
24
  };
25
25
  };
26
- export var createDefaultCategoryXAxis = function createDefaultCategoryXAxis(xAxisData) {
26
+ export var createDefaultCategoryXAxis = function createDefaultCategoryXAxis(xAxisData, chrome) {
27
27
  return {
28
28
  type: "category",
29
29
  boundaryGap: true,
@@ -31,10 +31,10 @@ export var createDefaultCategoryXAxis = function createDefaultCategoryXAxis(xAxi
31
31
  axisLabel: {
32
32
  interval: 0,
33
33
  hideOverlap: true,
34
- textStyle: {
35
- fontSize: 14,
36
- color: "#373D48"
37
- }
34
+ // echarts removed the `textStyle` nesting under `axisLabel` in v4: keeping it means both
35
+ // properties are silently dropped *and* a deprecation warning is logged on every render.
36
+ fontSize: chrome.fontSize,
37
+ color: chrome.axis
38
38
  },
39
39
  axisTick: {
40
40
  show: false
@@ -43,17 +43,16 @@ export var createDefaultCategoryXAxis = function createDefaultCategoryXAxis(xAxi
43
43
  };
44
44
  export var createDefaultValueYAxis = function createDefaultValueYAxis() {
45
45
  var mode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "bar";
46
+ var chrome = arguments.length > 1 ? arguments[1] : undefined;
46
47
  return {
47
48
  type: "value",
48
49
  axisLabel: {
49
- textStyle: {
50
- fontSize: 14,
51
- color: "#373D48"
52
- }
50
+ fontSize: chrome.fontSize,
51
+ color: chrome.axis
53
52
  },
54
53
  splitLine: mode === "line" ? {
55
54
  lineStyle: {
56
- color: "#C9CED6",
55
+ color: chrome.splitLine,
57
56
  type: "dashed"
58
57
  }
59
58
  } : {
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Colours for the chart *chrome* — axis ticks, split lines, legend labels.
3
+ *
4
+ * echarts options are plain JS, so they cannot read the `--vita-*` CSS variables the rest of the
5
+ * library styles itself with; the literal values have to be resolved here instead. These used to
6
+ * be hard-coded to a light-mode slate (`#373D48` / `#C9CED6`), which left every axis and legend
7
+ * nearly invisible once the page switched to the dark palette.
8
+ *
9
+ * The plotted data is deliberately *not* covered here: series colours come from echarts' own
10
+ * palette or from whatever the caller passes as `color`, and both read fine on either background.
11
+ */
12
+ export interface ChartChrome {
13
+ /** Legend labels — a real label, so it sits on the foreground ramp */
14
+ text: string;
15
+ /** Axis tick labels — secondary information, one step down */
16
+ axis: string;
17
+ /** Split lines behind the plot area */
18
+ splitLine: string;
19
+ /** Base font size, same scale the rest of the library uses */
20
+ fontSize: number;
21
+ }
22
+ export declare const resolveChartChrome: (dark: boolean) => ChartChrome;
@@ -0,0 +1,23 @@
1
+ import { darkTokens, fontTokens, lightTokens } from "../../../styles/tokens";
2
+
3
+ /**
4
+ * Colours for the chart *chrome* — axis ticks, split lines, legend labels.
5
+ *
6
+ * echarts options are plain JS, so they cannot read the `--vita-*` CSS variables the rest of the
7
+ * library styles itself with; the literal values have to be resolved here instead. These used to
8
+ * be hard-coded to a light-mode slate (`#373D48` / `#C9CED6`), which left every axis and legend
9
+ * nearly invisible once the page switched to the dark palette.
10
+ *
11
+ * The plotted data is deliberately *not* covered here: series colours come from echarts' own
12
+ * palette or from whatever the caller passes as `color`, and both read fine on either background.
13
+ */
14
+
15
+ export var resolveChartChrome = function resolveChartChrome(dark) {
16
+ var t = dark ? darkTokens : lightTokens;
17
+ return {
18
+ text: t.foreground,
19
+ axis: t.mutedForeground,
20
+ splitLine: t.border,
21
+ fontSize: fontTokens.size
22
+ };
23
+ };
@@ -1,3 +1,4 @@
1
1
  import { ChartOptionType } from "..";
2
- export declare const createDefaultHeatmapXAxis: (xAxisData?: string[]) => ChartOptionType;
3
- export declare const createDefaultHeatmapYAxis: (yAxisData?: string[]) => ChartOptionType;
2
+ import { ChartChrome } from "./chartTheme";
3
+ export declare const createDefaultHeatmapXAxis: (xAxisData: string[] | undefined, chrome: ChartChrome) => ChartOptionType;
4
+ export declare const createDefaultHeatmapYAxis: (yAxisData: string[] | undefined, chrome: ChartChrome) => ChartOptionType;
@@ -1,4 +1,4 @@
1
- export var createDefaultHeatmapXAxis = function createDefaultHeatmapXAxis(xAxisData) {
1
+ export var createDefaultHeatmapXAxis = function createDefaultHeatmapXAxis(xAxisData, chrome) {
2
2
  return {
3
3
  type: "category",
4
4
  data: xAxisData,
@@ -8,17 +8,16 @@ export var createDefaultHeatmapXAxis = function createDefaultHeatmapXAxis(xAxisD
8
8
  axisLabel: {
9
9
  interval: 0,
10
10
  hideOverlap: true,
11
- textStyle: {
12
- fontSize: 14,
13
- color: "#373D48"
14
- }
11
+ // See the note in `cartesian.ts`: `axisLabel.textStyle` has been deprecated since echarts 4
12
+ fontSize: chrome.fontSize,
13
+ color: chrome.axis
15
14
  },
16
15
  axisTick: {
17
16
  show: false
18
17
  }
19
18
  };
20
19
  };
21
- export var createDefaultHeatmapYAxis = function createDefaultHeatmapYAxis(yAxisData) {
20
+ export var createDefaultHeatmapYAxis = function createDefaultHeatmapYAxis(yAxisData, chrome) {
22
21
  return {
23
22
  type: "category",
24
23
  data: yAxisData,
@@ -26,10 +25,8 @@ export var createDefaultHeatmapYAxis = function createDefaultHeatmapYAxis(yAxisD
26
25
  show: true
27
26
  },
28
27
  axisLabel: {
29
- textStyle: {
30
- fontSize: 14,
31
- color: "#373D48"
32
- }
28
+ fontSize: chrome.fontSize,
29
+ color: chrome.axis
33
30
  },
34
31
  axisTick: {
35
32
  show: false
@@ -21,8 +21,18 @@
21
21
 
22
22
  height: 100%;
23
23
 
24
+ // Inside a modal the Search must not keep its card chrome. On a page it is an outlined white
25
+ // card standing on the grey page background; in a modal the body is already `--vita-surface`,
26
+ // so the same treatment paints a white card on white and only the border survives — a stray
27
+ // outline around the search row. The padding was already being cleared here; the background and
28
+ // border are the other half of the same intent, and `.tableContainer` below is flush for
29
+ // exactly this reason.
24
30
  .search {
25
31
  padding: 0px;
32
+
33
+ background: transparent;
34
+
35
+ border: none;
26
36
  }
27
37
 
28
38
  .tableContainer {
@@ -0,0 +1,40 @@
1
+ /**
2
+ * 给消费方 webpack 配置用的工具。**构建期模块,不要从应用代码里引**
3
+ * —— 它不依赖 React,也不该进运行时产物。
4
+ *
5
+ * ```js
6
+ * // webpack.config.js(CJS)
7
+ * const { excludeNodeModulesExceptHsuUi } = require("@hsu-react/ui/lib/build/webpack");
8
+ *
9
+ * { test: /\.scss$/, exclude: excludeNodeModulesExceptHsuUi, use: [...] }
10
+ * ```
11
+ */
12
+ /**
13
+ * 判断一个模块路径「是否该被 loader 排除」:node_modules 一律排除,但放行本库。
14
+ *
15
+ * ## 为什么需要它
16
+ *
17
+ * 本库的 es / lib 产物里带着**未编译的 `.module.scss`** 和图片资源,要由消费方自己的
18
+ * loader 处理(这样 CSS Module 的类名哈希、`getLocalIdent` 等策略才由消费方说了算)。
19
+ * 于是每个 webpack 项目都得在 scss / 图片规则上开一个「排除 node_modules,但放行
20
+ * @hsu-react/ui」的例外。
21
+ *
22
+ * ## 为什么不能用正则
23
+ *
24
+ * 手写的版本几乎都是 `/node_modules\/(?!@hsu-react\/ui\/)/`。它只看**第一个**
25
+ * node_modules 后面跟着什么——扁平安装(yarn / npm)下确实是 `@hsu-react/ui/`,
26
+ * 但 pnpm 的真实路径是
27
+ *
28
+ * ```
29
+ * node_modules/.pnpm/@hsu-react+ui@<版本>/node_modules/@hsu-react/ui/es/...
30
+ * ```
31
+ *
32
+ * 跟着的是 `.pnpm/`,否定前瞻立刻失败,本库的 scss 与图片会被**全部排除**,
33
+ * 报「no loaders are configured to process this file」。这个坑在四个下游项目里
34
+ * 各踩过一次,所以把判定收进库里导出,消费方引用而不是各抄一份。
35
+ *
36
+ * 改按「整条路径里有没有 @hsu-react/ui」判断,扁平与嵌套两种布局都成立;
37
+ * 路径分隔符同时接受 `/` 与 `\`,Windows 下同样有效。
38
+ */
39
+ export declare const excludeNodeModulesExceptHsuUi: (modulePath: string) => boolean;
40
+ export default excludeNodeModulesExceptHsuUi;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.excludeNodeModulesExceptHsuUi = exports.default = void 0;
7
+ /**
8
+ * 给消费方 webpack 配置用的工具。**构建期模块,不要从应用代码里引**
9
+ * —— 它不依赖 React,也不该进运行时产物。
10
+ *
11
+ * ```js
12
+ * // webpack.config.js(CJS)
13
+ * const { excludeNodeModulesExceptHsuUi } = require("@hsu-react/ui/lib/build/webpack");
14
+ *
15
+ * { test: /\.scss$/, exclude: excludeNodeModulesExceptHsuUi, use: [...] }
16
+ * ```
17
+ */
18
+
19
+ /**
20
+ * 判断一个模块路径「是否该被 loader 排除」:node_modules 一律排除,但放行本库。
21
+ *
22
+ * ## 为什么需要它
23
+ *
24
+ * 本库的 es / lib 产物里带着**未编译的 `.module.scss`** 和图片资源,要由消费方自己的
25
+ * loader 处理(这样 CSS Module 的类名哈希、`getLocalIdent` 等策略才由消费方说了算)。
26
+ * 于是每个 webpack 项目都得在 scss / 图片规则上开一个「排除 node_modules,但放行
27
+ * @hsu-react/ui」的例外。
28
+ *
29
+ * ## 为什么不能用正则
30
+ *
31
+ * 手写的版本几乎都是 `/node_modules\/(?!@hsu-react\/ui\/)/`。它只看**第一个**
32
+ * node_modules 后面跟着什么——扁平安装(yarn / npm)下确实是 `@hsu-react/ui/`,
33
+ * 但 pnpm 的真实路径是
34
+ *
35
+ * ```
36
+ * node_modules/.pnpm/@hsu-react+ui@<版本>/node_modules/@hsu-react/ui/es/...
37
+ * ```
38
+ *
39
+ * 跟着的是 `.pnpm/`,否定前瞻立刻失败,本库的 scss 与图片会被**全部排除**,
40
+ * 报「no loaders are configured to process this file」。这个坑在四个下游项目里
41
+ * 各踩过一次,所以把判定收进库里导出,消费方引用而不是各抄一份。
42
+ *
43
+ * 改按「整条路径里有没有 @hsu-react/ui」判断,扁平与嵌套两种布局都成立;
44
+ * 路径分隔符同时接受 `/` 与 `\`,Windows 下同样有效。
45
+ */
46
+ const excludeNodeModulesExceptHsuUi = modulePath => /node_modules/.test(modulePath) && !/@hsu-react[\\/]ui[\\/]/.test(modulePath);
47
+ exports.excludeNodeModulesExceptHsuUi = excludeNodeModulesExceptHsuUi;
48
+ var _default = exports.default = excludeNodeModulesExceptHsuUi;
@@ -10,6 +10,8 @@ var _indexModule = _interopRequireDefault(require("../index.module.scss"));
10
10
  var _autoScrollLegend = require("../_utils/autoScrollLegend");
11
11
  var _autoSmooth = require("../_utils/autoSmooth");
12
12
  var _cartesian = require("../_utils/cartesian");
13
+ var _chartTheme = require("../_utils/chartTheme");
14
+ var _useIsDark = _interopRequireDefault(require("../../../hooks/useIsDark"));
13
15
  var _jsxRuntime = require("react/jsx-runtime");
14
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
17
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
@@ -47,11 +49,15 @@ const ChartBar = props => {
47
49
  const prevXAxisKeyRef = (0, _react.useRef)(null);
48
50
  const legendScrollRef = (0, _react.useRef)(null);
49
51
  const normalizedScroll = (0, _react.useMemo)(() => (0, _cartesian.resolveScrollConfig)(scrollConfig), [scrollConfig]);
52
+ // echarts options are plain JS and cannot read the `--vita-*` variables, so the axis and
53
+ // legend colours have to be resolved against the active appearance here
54
+ const isDark = (0, _useIsDark.default)();
55
+ const chrome = (0, _react.useMemo)(() => (0, _chartTheme.resolveChartChrome)(isDark), [isDark]);
50
56
 
51
57
  // Cache the chart option with useMemo
52
58
  const chartOption = (0, _react.useMemo)(() => {
53
- const def_xAxis = (0, _cartesian.createDefaultCategoryXAxis)(xAxisData);
54
- const def_yAxis = (0, _cartesian.createDefaultValueYAxis)("bar");
59
+ const def_xAxis = (0, _cartesian.createDefaultCategoryXAxis)(xAxisData, chrome);
60
+ const def_yAxis = (0, _cartesian.createDefaultValueYAxis)("bar", chrome);
55
61
 
56
62
  // Process xAxis config
57
63
  const processedXAxis = Array.isArray(xAxis) ? xAxis?.map(item => ({
@@ -155,8 +161,7 @@ const ChartBar = props => {
155
161
  data: legendData,
156
162
  icon: "circle",
157
163
  textStyle: {
158
- color: "#373D48",
159
- fontSize: 16
164
+ color: chrome.text
160
165
  },
161
166
  itemWidth: 8,
162
167
  itemHeight: 8,
@@ -183,7 +188,7 @@ const ChartBar = props => {
183
188
  ...coreOption
184
189
  };
185
190
  return option;
186
- }, [xAxisData, xAxis, yAxis, grid, chartTitle, dataZoom, normalizedScroll, insideDataZoom, sliderDataZoom, title, tooltip, legendData, legend, seriesData, series, enableLegendAutoScroll, coreOption]);
191
+ }, [xAxisData, xAxis, yAxis, grid, chartTitle, dataZoom, normalizedScroll, insideDataZoom, sliderDataZoom, title, tooltip, legendData, legend, seriesData, series, enableLegendAutoScroll, coreOption, chrome]);
187
192
 
188
193
  // Callback for handling chart resize
189
194
  const handleResize = (0, _react.useCallback)(() => {
@@ -8,6 +8,8 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _indexModule = _interopRequireDefault(require("../index.module.scss"));
9
9
  var echarts = _interopRequireWildcard(require("echarts"));
10
10
  var _heatmap = require("../_utils/heatmap");
11
+ var _chartTheme = require("../_utils/chartTheme");
12
+ var _useIsDark = _interopRequireDefault(require("../../../hooks/useIsDark"));
11
13
  var _jsxRuntime = require("react/jsx-runtime");
12
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
15
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
@@ -36,6 +38,10 @@ const Heatmap = props => {
36
38
  const chartRef = (0, _react.useRef)(null);
37
39
  const chartInstanceRef = (0, _react.useRef)(null);
38
40
  const resizeObserverRef = (0, _react.useRef)(null);
41
+ // echarts options are plain JS and cannot read the `--vita-*` variables, so the axis and legend
42
+ // colours have to be resolved against the active appearance here
43
+ const isDark = (0, _useIsDark.default)();
44
+ const chrome = (0, _react.useMemo)(() => (0, _chartTheme.resolveChartChrome)(isDark), [isDark]);
39
45
 
40
46
  // Process the data and generate the chart option
41
47
  const chartOption = (0, _react.useMemo)(() => {
@@ -76,7 +82,7 @@ const Heatmap = props => {
76
82
  left: "right",
77
83
  top: "center",
78
84
  textStyle: {
79
- color: "#373D48"
85
+ color: chrome.text
80
86
  },
81
87
  inRange: {
82
88
  color: inRangeColor
@@ -84,7 +90,7 @@ const Heatmap = props => {
84
90
  };
85
91
 
86
92
  // Process xAxis config
87
- const def_xAxis = (0, _heatmap.createDefaultHeatmapXAxis)(xAxisData);
93
+ const def_xAxis = (0, _heatmap.createDefaultHeatmapXAxis)(xAxisData, chrome);
88
94
  const processedXAxis = Array.isArray(xAxis) ? xAxis?.map(item => ({
89
95
  ...def_xAxis,
90
96
  data: item?.type === "value" ? undefined : xAxisData,
@@ -96,7 +102,7 @@ const Heatmap = props => {
96
102
  };
97
103
 
98
104
  // Process yAxis config
99
- const def_yAxis = (0, _heatmap.createDefaultHeatmapYAxis)(yAxisData);
105
+ const def_yAxis = (0, _heatmap.createDefaultHeatmapYAxis)(yAxisData, chrome);
100
106
  const processedYAxis = Array.isArray(yAxis) ? yAxis?.map(item => ({
101
107
  ...def_yAxis,
102
108
  data: item?.type === "value" ? undefined : yAxisData,
@@ -172,7 +178,7 @@ const Heatmap = props => {
172
178
  ...coreOption
173
179
  };
174
180
  return option;
175
- }, [data, inRangeColor, xAxisData, xAxis, yAxisData, yAxis, propVisualMap, grid, chartTitle, title, tooltip, series, coreOption, zeroColor]);
181
+ }, [data, inRangeColor, xAxisData, xAxis, yAxisData, yAxis, propVisualMap, grid, chartTitle, title, tooltip, series, coreOption, zeroColor, chrome]);
176
182
 
177
183
  // Callback for handling chart resize
178
184
  const handleResize = (0, _react.useCallback)(() => {
@@ -10,6 +10,8 @@ var _indexModule = _interopRequireDefault(require("../index.module.scss"));
10
10
  var _autoScrollLegend = require("../_utils/autoScrollLegend");
11
11
  var _autoSmooth = require("../_utils/autoSmooth");
12
12
  var _cartesian = require("../_utils/cartesian");
13
+ var _chartTheme = require("../_utils/chartTheme");
14
+ var _useIsDark = _interopRequireDefault(require("../../../hooks/useIsDark"));
13
15
  var _jsxRuntime = require("react/jsx-runtime");
14
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
17
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
@@ -47,11 +49,15 @@ const ChartLine = props => {
47
49
  const prevXAxisKeyRef = (0, _react.useRef)(null);
48
50
  const legendScrollRef = (0, _react.useRef)(null);
49
51
  const normalizedScroll = (0, _react.useMemo)(() => (0, _cartesian.resolveScrollConfig)(scrollConfig), [scrollConfig]);
52
+ // echarts options are plain JS and cannot read the `--vita-*` variables, so the axis and
53
+ // legend colours have to be resolved against the active appearance here
54
+ const isDark = (0, _useIsDark.default)();
55
+ const chrome = (0, _react.useMemo)(() => (0, _chartTheme.resolveChartChrome)(isDark), [isDark]);
50
56
 
51
57
  // Cache the chart option with useMemo
52
58
  const chartOption = (0, _react.useMemo)(() => {
53
- const def_xAxis = (0, _cartesian.createDefaultCategoryXAxis)(xAxisData);
54
- const def_yAxis = (0, _cartesian.createDefaultValueYAxis)("line");
59
+ const def_xAxis = (0, _cartesian.createDefaultCategoryXAxis)(xAxisData, chrome);
60
+ const def_yAxis = (0, _cartesian.createDefaultValueYAxis)("line", chrome);
55
61
 
56
62
  // Process xAxis config
57
63
  const processedXAxis = Array.isArray(xAxis) ? xAxis?.map(item => ({
@@ -148,7 +154,7 @@ const ChartLine = props => {
148
154
  top: "5%",
149
155
  icon: "circle",
150
156
  textStyle: {
151
- color: "#373D48"
157
+ color: chrome.text
152
158
  },
153
159
  itemWidth: 8,
154
160
  itemHeight: 8,
@@ -179,7 +185,7 @@ const ChartLine = props => {
179
185
  ...coreOption
180
186
  };
181
187
  return option;
182
- }, [xAxisData, xAxis, yAxis, grid, chartTitle, dataZoom, normalizedScroll, insideDataZoom, sliderDataZoom, title, legendData, legend, tooltip, seriesData, series, enableLegendAutoScroll, coreOption]);
188
+ }, [xAxisData, xAxis, yAxis, grid, chartTitle, dataZoom, normalizedScroll, insideDataZoom, sliderDataZoom, title, legendData, legend, tooltip, seriesData, series, enableLegendAutoScroll, coreOption, chrome]);
183
189
 
184
190
  // Callback for handling chart resize
185
191
  const handleResize = (0, _react.useCallback)(() => {
@@ -1,5 +1,6 @@
1
1
  import * as echarts from "echarts";
2
2
  import { ChartOptionType, SeriesDataType } from "..";
3
+ import { ChartChrome } from "./chartTheme";
3
4
  export interface ChartScrollConfig {
4
5
  enabled?: boolean;
5
6
  autoScroll?: boolean;
@@ -29,8 +30,8 @@ export interface DataZoomIndexWindow {
29
30
  * percentages produced by native echarts interactions are rounded outward, so each boundary may include at most one extra item, without affecting the axis magnitude.
30
31
  */
31
32
  export declare const percentWindowToIndexWindow: (startPercent: number, endPercent: number, total: number) => DataZoomIndexWindow;
32
- export declare const createDefaultCategoryXAxis: (xAxisData?: Array<string>) => ChartOptionType;
33
- export declare const createDefaultValueYAxis: (mode?: "bar" | "line") => ChartOptionType;
33
+ export declare const createDefaultCategoryXAxis: (xAxisData: Array<string> | undefined, chrome: ChartChrome) => ChartOptionType;
34
+ export declare const createDefaultValueYAxis: (mode: "bar" | "line" | undefined, chrome: ChartChrome) => ChartOptionType;
34
35
  export declare const buildCartesianSeriesOptions: (mode: "bar" | "line", seriesData?: SeriesDataType, series?: echarts.SeriesOption | echarts.SeriesOption[]) => echarts.SeriesOption[];
35
36
  export declare const getSliderShow: (zoom?: echarts.DataZoomComponentOption | Record<string, unknown>) => boolean | undefined;
36
37
  export declare const resolveScrollConfig: (scrollConfig?: ChartScrollConfig) => NormalizedScrollConfig;
@@ -24,34 +24,32 @@ const percentWindowToIndexWindow = (startPercent, endPercent, total) => {
24
24
  };
25
25
  };
26
26
  exports.percentWindowToIndexWindow = percentWindowToIndexWindow;
27
- const createDefaultCategoryXAxis = xAxisData => ({
27
+ const createDefaultCategoryXAxis = (xAxisData, chrome) => ({
28
28
  type: "category",
29
29
  boundaryGap: true,
30
30
  data: xAxisData,
31
31
  axisLabel: {
32
32
  interval: 0,
33
33
  hideOverlap: true,
34
- textStyle: {
35
- fontSize: 14,
36
- color: "#373D48"
37
- }
34
+ // echarts removed the `textStyle` nesting under `axisLabel` in v4: keeping it means both
35
+ // properties are silently dropped *and* a deprecation warning is logged on every render.
36
+ fontSize: chrome.fontSize,
37
+ color: chrome.axis
38
38
  },
39
39
  axisTick: {
40
40
  show: false
41
41
  }
42
42
  });
43
43
  exports.createDefaultCategoryXAxis = createDefaultCategoryXAxis;
44
- const createDefaultValueYAxis = (mode = "bar") => ({
44
+ const createDefaultValueYAxis = (mode = "bar", chrome) => ({
45
45
  type: "value",
46
46
  axisLabel: {
47
- textStyle: {
48
- fontSize: 14,
49
- color: "#373D48"
50
- }
47
+ fontSize: chrome.fontSize,
48
+ color: chrome.axis
51
49
  },
52
50
  splitLine: mode === "line" ? {
53
51
  lineStyle: {
54
- color: "#C9CED6",
52
+ color: chrome.splitLine,
55
53
  type: "dashed"
56
54
  }
57
55
  } : {
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Colours for the chart *chrome* — axis ticks, split lines, legend labels.
3
+ *
4
+ * echarts options are plain JS, so they cannot read the `--vita-*` CSS variables the rest of the
5
+ * library styles itself with; the literal values have to be resolved here instead. These used to
6
+ * be hard-coded to a light-mode slate (`#373D48` / `#C9CED6`), which left every axis and legend
7
+ * nearly invisible once the page switched to the dark palette.
8
+ *
9
+ * The plotted data is deliberately *not* covered here: series colours come from echarts' own
10
+ * palette or from whatever the caller passes as `color`, and both read fine on either background.
11
+ */
12
+ export interface ChartChrome {
13
+ /** Legend labels — a real label, so it sits on the foreground ramp */
14
+ text: string;
15
+ /** Axis tick labels — secondary information, one step down */
16
+ axis: string;
17
+ /** Split lines behind the plot area */
18
+ splitLine: string;
19
+ /** Base font size, same scale the rest of the library uses */
20
+ fontSize: number;
21
+ }
22
+ export declare const resolveChartChrome: (dark: boolean) => ChartChrome;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.resolveChartChrome = void 0;
7
+ var _tokens = require("../../../styles/tokens");
8
+ /**
9
+ * Colours for the chart *chrome* — axis ticks, split lines, legend labels.
10
+ *
11
+ * echarts options are plain JS, so they cannot read the `--vita-*` CSS variables the rest of the
12
+ * library styles itself with; the literal values have to be resolved here instead. These used to
13
+ * be hard-coded to a light-mode slate (`#373D48` / `#C9CED6`), which left every axis and legend
14
+ * nearly invisible once the page switched to the dark palette.
15
+ *
16
+ * The plotted data is deliberately *not* covered here: series colours come from echarts' own
17
+ * palette or from whatever the caller passes as `color`, and both read fine on either background.
18
+ */
19
+
20
+ const resolveChartChrome = dark => {
21
+ const t = dark ? _tokens.darkTokens : _tokens.lightTokens;
22
+ return {
23
+ text: t.foreground,
24
+ axis: t.mutedForeground,
25
+ splitLine: t.border,
26
+ fontSize: _tokens.fontTokens.size
27
+ };
28
+ };
29
+ exports.resolveChartChrome = resolveChartChrome;
@@ -1,3 +1,4 @@
1
1
  import { ChartOptionType } from "..";
2
- export declare const createDefaultHeatmapXAxis: (xAxisData?: string[]) => ChartOptionType;
3
- export declare const createDefaultHeatmapYAxis: (yAxisData?: string[]) => ChartOptionType;
2
+ import { ChartChrome } from "./chartTheme";
3
+ export declare const createDefaultHeatmapXAxis: (xAxisData: string[] | undefined, chrome: ChartChrome) => ChartOptionType;
4
+ export declare const createDefaultHeatmapYAxis: (yAxisData: string[] | undefined, chrome: ChartChrome) => ChartOptionType;
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.createDefaultHeatmapYAxis = exports.createDefaultHeatmapXAxis = void 0;
7
- const createDefaultHeatmapXAxis = xAxisData => ({
7
+ const createDefaultHeatmapXAxis = (xAxisData, chrome) => ({
8
8
  type: "category",
9
9
  data: xAxisData,
10
10
  splitArea: {
@@ -13,27 +13,24 @@ const createDefaultHeatmapXAxis = xAxisData => ({
13
13
  axisLabel: {
14
14
  interval: 0,
15
15
  hideOverlap: true,
16
- textStyle: {
17
- fontSize: 14,
18
- color: "#373D48"
19
- }
16
+ // See the note in `cartesian.ts`: `axisLabel.textStyle` has been deprecated since echarts 4
17
+ fontSize: chrome.fontSize,
18
+ color: chrome.axis
20
19
  },
21
20
  axisTick: {
22
21
  show: false
23
22
  }
24
23
  });
25
24
  exports.createDefaultHeatmapXAxis = createDefaultHeatmapXAxis;
26
- const createDefaultHeatmapYAxis = yAxisData => ({
25
+ const createDefaultHeatmapYAxis = (yAxisData, chrome) => ({
27
26
  type: "category",
28
27
  data: yAxisData,
29
28
  splitArea: {
30
29
  show: true
31
30
  },
32
31
  axisLabel: {
33
- textStyle: {
34
- fontSize: 14,
35
- color: "#373D48"
36
- }
32
+ fontSize: chrome.fontSize,
33
+ color: chrome.axis
37
34
  },
38
35
  axisTick: {
39
36
  show: false
@@ -21,8 +21,18 @@
21
21
 
22
22
  height: 100%;
23
23
 
24
+ // Inside a modal the Search must not keep its card chrome. On a page it is an outlined white
25
+ // card standing on the grey page background; in a modal the body is already `--vita-surface`,
26
+ // so the same treatment paints a white card on white and only the border survives — a stray
27
+ // outline around the search row. The padding was already being cleared here; the background and
28
+ // border are the other half of the same intent, and `.tableContainer` below is flush for
29
+ // exactly this reason.
24
30
  .search {
25
31
  padding: 0px;
32
+
33
+ background: transparent;
34
+
35
+ border: none;
26
36
  }
27
37
 
28
38
  .tableContainer {
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hsu-react/ui",
3
- "version": "2.3.0",
3
+ "version": "2.4.1",
4
4
  "description": "一套基于 React + Ant Design 的中后台业务组件库",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -41,8 +41,8 @@
41
41
  "dev": "dumi dev",
42
42
  "docs:build": "dumi build",
43
43
  "docs:preview": "dumi preview",
44
- "build": "node scripts/clean-dist.cjs && node scripts/gen-tokens-scss.cjs && father build && node scripts/check-heavy-deps.cjs",
45
- "prepublishOnly": "node scripts/clean-dist.cjs && node scripts/gen-tokens-scss.cjs --check && father build && node scripts/check-heavy-deps.cjs",
44
+ "build": "node scripts/clean-dist.cjs && node scripts/gen-tokens-scss.cjs && father build && node scripts/mark-cjs.cjs && node scripts/check-heavy-deps.cjs",
45
+ "prepublishOnly": "node scripts/clean-dist.cjs && node scripts/gen-tokens-scss.cjs --check && father build && node scripts/mark-cjs.cjs && node scripts/check-heavy-deps.cjs",
46
46
  "check:deps": "node scripts/check-heavy-deps.cjs",
47
47
  "tokens": "node scripts/gen-tokens-scss.cjs",
48
48
  "check:tokens": "node scripts/gen-tokens-scss.cjs --check"
@@ -0,0 +1,44 @@
1
+ /**
2
+ * 给消费方 webpack 配置用的工具。**构建期模块,不要从应用代码里引**
3
+ * —— 它不依赖 React,也不该进运行时产物。
4
+ *
5
+ * ```js
6
+ * // webpack.config.js(CJS)
7
+ * const { excludeNodeModulesExceptHsuUi } = require("@hsu-react/ui/lib/build/webpack");
8
+ *
9
+ * { test: /\.scss$/, exclude: excludeNodeModulesExceptHsuUi, use: [...] }
10
+ * ```
11
+ */
12
+
13
+ /**
14
+ * 判断一个模块路径「是否该被 loader 排除」:node_modules 一律排除,但放行本库。
15
+ *
16
+ * ## 为什么需要它
17
+ *
18
+ * 本库的 es / lib 产物里带着**未编译的 `.module.scss`** 和图片资源,要由消费方自己的
19
+ * loader 处理(这样 CSS Module 的类名哈希、`getLocalIdent` 等策略才由消费方说了算)。
20
+ * 于是每个 webpack 项目都得在 scss / 图片规则上开一个「排除 node_modules,但放行
21
+ * @hsu-react/ui」的例外。
22
+ *
23
+ * ## 为什么不能用正则
24
+ *
25
+ * 手写的版本几乎都是 `/node_modules\/(?!@hsu-react\/ui\/)/`。它只看**第一个**
26
+ * node_modules 后面跟着什么——扁平安装(yarn / npm)下确实是 `@hsu-react/ui/`,
27
+ * 但 pnpm 的真实路径是
28
+ *
29
+ * ```
30
+ * node_modules/.pnpm/@hsu-react+ui@<版本>/node_modules/@hsu-react/ui/es/...
31
+ * ```
32
+ *
33
+ * 跟着的是 `.pnpm/`,否定前瞻立刻失败,本库的 scss 与图片会被**全部排除**,
34
+ * 报「no loaders are configured to process this file」。这个坑在四个下游项目里
35
+ * 各踩过一次,所以把判定收进库里导出,消费方引用而不是各抄一份。
36
+ *
37
+ * 改按「整条路径里有没有 @hsu-react/ui」判断,扁平与嵌套两种布局都成立;
38
+ * 路径分隔符同时接受 `/` 与 `\`,Windows 下同样有效。
39
+ */
40
+ export const excludeNodeModulesExceptHsuUi = (modulePath: string): boolean =>
41
+ /node_modules/.test(modulePath) &&
42
+ !/@hsu-react[\\/]ui[\\/]/.test(modulePath);
43
+
44
+ export default excludeNodeModulesExceptHsuUi;
@@ -21,6 +21,8 @@ import {
21
21
  percentWindowToIndexWindow,
22
22
  resolveScrollConfig,
23
23
  } from "../_utils/cartesian";
24
+ import { resolveChartChrome } from "../_utils/chartTheme";
25
+ import useIsDark from "../../../hooks/useIsDark";
24
26
 
25
27
  export interface ChartBarProps extends ChartCommonProps {
26
28
  chartTitle?: string;
@@ -79,11 +81,15 @@ const ChartBar: React.FC<ChartBarProps> = (props) => {
79
81
  () => resolveScrollConfig(scrollConfig),
80
82
  [scrollConfig],
81
83
  );
84
+ // echarts options are plain JS and cannot read the `--vita-*` variables, so the axis and
85
+ // legend colours have to be resolved against the active appearance here
86
+ const isDark = useIsDark();
87
+ const chrome = useMemo(() => resolveChartChrome(isDark), [isDark]);
82
88
 
83
89
  // Cache the chart option with useMemo
84
90
  const chartOption = useMemo(() => {
85
- const def_xAxis = createDefaultCategoryXAxis(xAxisData);
86
- const def_yAxis = createDefaultValueYAxis("bar");
91
+ const def_xAxis = createDefaultCategoryXAxis(xAxisData, chrome);
92
+ const def_yAxis = createDefaultValueYAxis("bar", chrome);
87
93
 
88
94
  // Process xAxis config
89
95
  const processedXAxis = Array.isArray(xAxis)
@@ -212,8 +218,7 @@ const ChartBar: React.FC<ChartBarProps> = (props) => {
212
218
  data: legendData,
213
219
  icon: "circle",
214
220
  textStyle: {
215
- color: "#373D48",
216
- fontSize: 16,
221
+ color: chrome.text,
217
222
  },
218
223
  itemWidth: 8,
219
224
  itemHeight: 8,
@@ -259,6 +264,7 @@ const ChartBar: React.FC<ChartBarProps> = (props) => {
259
264
  series,
260
265
  enableLegendAutoScroll,
261
266
  coreOption,
267
+ chrome,
262
268
  ]);
263
269
 
264
270
  // Callback for handling chart resize
@@ -6,6 +6,8 @@ import {
6
6
  createDefaultHeatmapXAxis,
7
7
  createDefaultHeatmapYAxis,
8
8
  } from "../_utils/heatmap";
9
+ import { resolveChartChrome } from "../_utils/chartTheme";
10
+ import useIsDark from "../../../hooks/useIsDark";
9
11
 
10
12
  export interface HeatmapDataItem {
11
13
  /** X-axis index or name */
@@ -73,6 +75,10 @@ const Heatmap: React.FC<ChartHeatmapProps> = (props) => {
73
75
  const chartRef = useRef<HTMLDivElement>(null);
74
76
  const chartInstanceRef = useRef<echarts.ECharts | null>(null);
75
77
  const resizeObserverRef = useRef<ResizeObserver | null>(null);
78
+ // echarts options are plain JS and cannot read the `--vita-*` variables, so the axis and legend
79
+ // colours have to be resolved against the active appearance here
80
+ const isDark = useIsDark();
81
+ const chrome = useMemo(() => resolveChartChrome(isDark), [isDark]);
76
82
 
77
83
  // Process the data and generate the chart option
78
84
  const chartOption = useMemo(() => {
@@ -120,7 +126,7 @@ const Heatmap: React.FC<ChartHeatmapProps> = (props) => {
120
126
  left: "right",
121
127
  top: "center",
122
128
  textStyle: {
123
- color: "#373D48",
129
+ color: chrome.text,
124
130
  },
125
131
  inRange: {
126
132
  color: inRangeColor,
@@ -128,7 +134,7 @@ const Heatmap: React.FC<ChartHeatmapProps> = (props) => {
128
134
  };
129
135
 
130
136
  // Process xAxis config
131
- const def_xAxis = createDefaultHeatmapXAxis(xAxisData);
137
+ const def_xAxis = createDefaultHeatmapXAxis(xAxisData, chrome);
132
138
  const processedXAxis = Array.isArray(xAxis)
133
139
  ? xAxis?.map((item) => ({
134
140
  ...def_xAxis,
@@ -142,7 +148,7 @@ const Heatmap: React.FC<ChartHeatmapProps> = (props) => {
142
148
  };
143
149
 
144
150
  // Process yAxis config
145
- const def_yAxis = createDefaultHeatmapYAxis(yAxisData);
151
+ const def_yAxis = createDefaultHeatmapYAxis(yAxisData, chrome);
146
152
  const processedYAxis = Array.isArray(yAxis)
147
153
  ? yAxis?.map((item) => ({
148
154
  ...def_yAxis,
@@ -244,6 +250,7 @@ const Heatmap: React.FC<ChartHeatmapProps> = (props) => {
244
250
  series,
245
251
  coreOption,
246
252
  zeroColor,
253
+ chrome,
247
254
  ]);
248
255
 
249
256
  // Callback for handling chart resize
@@ -21,6 +21,8 @@ import {
21
21
  percentWindowToIndexWindow,
22
22
  resolveScrollConfig,
23
23
  } from "../_utils/cartesian";
24
+ import { resolveChartChrome } from "../_utils/chartTheme";
25
+ import useIsDark from "../../../hooks/useIsDark";
24
26
 
25
27
  export interface ChartLineProps extends ChartCommonProps {
26
28
  chartTitle?: string;
@@ -80,11 +82,15 @@ const ChartLine: React.FC<ChartLineProps> = (props) => {
80
82
  () => resolveScrollConfig(scrollConfig),
81
83
  [scrollConfig],
82
84
  );
85
+ // echarts options are plain JS and cannot read the `--vita-*` variables, so the axis and
86
+ // legend colours have to be resolved against the active appearance here
87
+ const isDark = useIsDark();
88
+ const chrome = useMemo(() => resolveChartChrome(isDark), [isDark]);
83
89
 
84
90
  // Cache the chart option with useMemo
85
91
  const chartOption = useMemo(() => {
86
- const def_xAxis = createDefaultCategoryXAxis(xAxisData);
87
- const def_yAxis = createDefaultValueYAxis("line");
92
+ const def_xAxis = createDefaultCategoryXAxis(xAxisData, chrome);
93
+ const def_yAxis = createDefaultValueYAxis("line", chrome);
88
94
 
89
95
  // Process xAxis config
90
96
  const processedXAxis = Array.isArray(xAxis)
@@ -206,7 +212,7 @@ const ChartLine: React.FC<ChartLineProps> = (props) => {
206
212
  top: "5%",
207
213
  icon: "circle",
208
214
  textStyle: {
209
- color: "#373D48",
215
+ color: chrome.text,
210
216
  },
211
217
  itemWidth: 8,
212
218
  itemHeight: 8,
@@ -256,6 +262,7 @@ const ChartLine: React.FC<ChartLineProps> = (props) => {
256
262
  series,
257
263
  enableLegendAutoScroll,
258
264
  coreOption,
265
+ chrome,
259
266
  ]);
260
267
 
261
268
  // Callback for handling chart resize
@@ -1,5 +1,6 @@
1
1
  import * as echarts from "echarts";
2
2
  import { ChartOptionType, SeriesData, SeriesDataType } from "..";
3
+ import { ChartChrome } from "./chartTheme";
3
4
 
4
5
  export interface ChartScrollConfig {
5
6
  enabled?: boolean;
@@ -50,7 +51,8 @@ export const percentWindowToIndexWindow = (
50
51
  };
51
52
 
52
53
  export const createDefaultCategoryXAxis = (
53
- xAxisData?: Array<string>,
54
+ xAxisData: Array<string> | undefined,
55
+ chrome: ChartChrome,
54
56
  ): ChartOptionType => ({
55
57
  type: "category",
56
58
  boundaryGap: true,
@@ -58,10 +60,10 @@ export const createDefaultCategoryXAxis = (
58
60
  axisLabel: {
59
61
  interval: 0,
60
62
  hideOverlap: true,
61
- textStyle: {
62
- fontSize: 14,
63
- color: "#373D48",
64
- },
63
+ // echarts removed the `textStyle` nesting under `axisLabel` in v4: keeping it means both
64
+ // properties are silently dropped *and* a deprecation warning is logged on every render.
65
+ fontSize: chrome.fontSize,
66
+ color: chrome.axis,
65
67
  },
66
68
  axisTick: {
67
69
  show: false,
@@ -70,19 +72,18 @@ export const createDefaultCategoryXAxis = (
70
72
 
71
73
  export const createDefaultValueYAxis = (
72
74
  mode: "bar" | "line" = "bar",
75
+ chrome: ChartChrome,
73
76
  ): ChartOptionType => ({
74
77
  type: "value",
75
78
  axisLabel: {
76
- textStyle: {
77
- fontSize: 14,
78
- color: "#373D48",
79
- },
79
+ fontSize: chrome.fontSize,
80
+ color: chrome.axis,
80
81
  },
81
82
  splitLine:
82
83
  mode === "line"
83
84
  ? {
84
85
  lineStyle: {
85
- color: "#C9CED6",
86
+ color: chrome.splitLine,
86
87
  type: "dashed",
87
88
  },
88
89
  }
@@ -0,0 +1,34 @@
1
+ import { darkTokens, fontTokens, lightTokens } from "../../../styles/tokens";
2
+
3
+ /**
4
+ * Colours for the chart *chrome* — axis ticks, split lines, legend labels.
5
+ *
6
+ * echarts options are plain JS, so they cannot read the `--vita-*` CSS variables the rest of the
7
+ * library styles itself with; the literal values have to be resolved here instead. These used to
8
+ * be hard-coded to a light-mode slate (`#373D48` / `#C9CED6`), which left every axis and legend
9
+ * nearly invisible once the page switched to the dark palette.
10
+ *
11
+ * The plotted data is deliberately *not* covered here: series colours come from echarts' own
12
+ * palette or from whatever the caller passes as `color`, and both read fine on either background.
13
+ */
14
+ export interface ChartChrome {
15
+ /** Legend labels — a real label, so it sits on the foreground ramp */
16
+ text: string;
17
+ /** Axis tick labels — secondary information, one step down */
18
+ axis: string;
19
+ /** Split lines behind the plot area */
20
+ splitLine: string;
21
+ /** Base font size, same scale the rest of the library uses */
22
+ fontSize: number;
23
+ }
24
+
25
+ export const resolveChartChrome = (dark: boolean): ChartChrome => {
26
+ const t = dark ? darkTokens : lightTokens;
27
+
28
+ return {
29
+ text: t.foreground,
30
+ axis: t.mutedForeground,
31
+ splitLine: t.border,
32
+ fontSize: fontTokens.size,
33
+ };
34
+ };
@@ -1,7 +1,9 @@
1
1
  import { ChartOptionType } from "..";
2
+ import { ChartChrome } from "./chartTheme";
2
3
 
3
4
  export const createDefaultHeatmapXAxis = (
4
- xAxisData?: string[],
5
+ xAxisData: string[] | undefined,
6
+ chrome: ChartChrome,
5
7
  ): ChartOptionType => ({
6
8
  type: "category",
7
9
  data: xAxisData,
@@ -11,10 +13,9 @@ export const createDefaultHeatmapXAxis = (
11
13
  axisLabel: {
12
14
  interval: 0,
13
15
  hideOverlap: true,
14
- textStyle: {
15
- fontSize: 14,
16
- color: "#373D48",
17
- },
16
+ // See the note in `cartesian.ts`: `axisLabel.textStyle` has been deprecated since echarts 4
17
+ fontSize: chrome.fontSize,
18
+ color: chrome.axis,
18
19
  },
19
20
  axisTick: {
20
21
  show: false,
@@ -22,7 +23,8 @@ export const createDefaultHeatmapXAxis = (
22
23
  });
23
24
 
24
25
  export const createDefaultHeatmapYAxis = (
25
- yAxisData?: string[],
26
+ yAxisData: string[] | undefined,
27
+ chrome: ChartChrome,
26
28
  ): ChartOptionType => ({
27
29
  type: "category",
28
30
  data: yAxisData,
@@ -30,10 +32,8 @@ export const createDefaultHeatmapYAxis = (
30
32
  show: true,
31
33
  },
32
34
  axisLabel: {
33
- textStyle: {
34
- fontSize: 14,
35
- color: "#373D48",
36
- },
35
+ fontSize: chrome.fontSize,
36
+ color: chrome.axis,
37
37
  },
38
38
  axisTick: {
39
39
  show: false,
@@ -21,8 +21,18 @@
21
21
 
22
22
  height: 100%;
23
23
 
24
+ // Inside a modal the Search must not keep its card chrome. On a page it is an outlined white
25
+ // card standing on the grey page background; in a modal the body is already `--vita-surface`,
26
+ // so the same treatment paints a white card on white and only the border survives — a stray
27
+ // outline around the search row. The padding was already being cleared here; the background and
28
+ // border are the other half of the same intent, and `.tableContainer` below is flush for
29
+ // exactly this reason.
24
30
  .search {
25
31
  padding: 0px;
32
+
33
+ background: transparent;
34
+
35
+ border: none;
26
36
  }
27
37
 
28
38
  .tableContainer {